How to add products per page dropdown to WooCommerce product archive

Want to allow your customers the ability to choose how many WooCommerce products are displayed on your Product archive, by adding this products per page dropdown users will able to set and save how many are visible.

The ground work for this example is possible by the loop_shop_per_page filter which allows us to return the amount of products to be displayed, we will retrieve the amount of products the user wants to display from a drop down attached to the product archive page using woocommerce_before_shop_loop action, save it to session for future use (if they are logged in save it to their user account), and display limit products based on this value.

Retrieve options for the per product dropdown

Lets start by creating a function to retrieve the list of available display options for the dropdown menu. I have wrapped the products per page list in a filter jc_products_per_page to allow the values to be modified without the need to edit this file.

The array returned has to follow a similar structure, for example the array key will be the integer of products to be displayed and the array value will be displayed as the label in the dropdown menu.

    /**
     * Fetch list of avaliable options
     * @return array
     */
    function jc_get_products_per_page_options(){
    	$options = apply_filters( 'jc_products_per_page', array(
    		12 => __('12', 'woocommerce'),
    		24 => __('24', 'woocommerce'),
    		48 => __('48', 'woocommerce'),
    		96 => __('96', 'woocommerce')
        ));
 
    	return $options;
    }

Display products per page dropdown

We can display the per product dropdown on product archive pages by using the woocommerce_before_shop_loop action, or by calling jc_woocommerce_products_per_page (code below) at the location of our choosing within our wordpress template files.

To keep the output tidy instead of adding a submit button to our dropdown form, using javascript it can automatically be submited and update the product display limit.

Using the previously created function jc_get_products_per_page_options to populate our dropdown, using wordpress selected() function we can select the currently active product limit.

The function jc_get_product_per_page when created will fetch from session or user meta their preferred choice.

    /**
     * Display dropdown form to change amount of products displayed
     * @return void
     */
    function jc_woocommerce_products_per_page(){
 
        $options = jc_get_products_per_page_options();
 
        $current_value = jc_get_products_per_page();
        ?>
        <div class="products-per-page">
            <span>Products Per Page:</span>
            <form action="" method="POST" class="woocommerce-products-per-page">
                <select name="jc-woocommerce-products-per-page" onchange="this.form.submit()">
                <?php foreach($options as $value => $name): ?>
                    <option value="<?php echo $value; ?>" <?php selected($value, $current_value); ?>><?php echo $name; ?></option>
                <?php endforeach; ?>
                </select>
            </form>
        </div>
        <?php
    }
 
    // hook into the top of the shop or by calling jc_woocommerce_products_per_page() within your theme files
    add_action('woocommerce_before_shop_loop', 'jc_woocommerce_products_per_page', 25);

Save and load products per page settings

Now we have the product archive dropdown displayed, we need to process the form and store the value in session or user meta, lets scaffold out that function.

To start with we will fetch the list of available options using jc_get_products_per_page_options, this will be used to check if the session value is valid. For this example i have set the default amount of products displayed to be 24.

    /**
     * Get current users preference
     * @return int
     */
    function jc_get_products_per_page(){
 
        global $woocommerce;
 
        $default = 24;
        $count = $default;
        $options = jc_get_products_per_page_options();
 
        // todo: capture form data and store in session
 
        // todo: load product limit from user meta
 
        // todo: load product limit from session
 
        return $count;
    }
    add_filter('loop_shop_per_page','jc_get_products_per_page');

Capture form submission from dropdown

If the drop down has been changed we need to capture the new product limit, we validate the value and store it within WooCommerce session variable and if the current user is logged in then the new value also gets stored in the user meta table so that when they login next time their preference will be loaded.

The value is stored within a session variable so that the value will be stored while the user is on the website.

Once the data has been saved we exit the current function and return the saved variable which will set how many products are displayed.

    // capture form data and store in session
    if(isset($_POST['jc-woocommerce-products-per-page'])){
 
        // set products per page from dropdown
        $products_max = intval($_POST['jc-woocommerce-products-per-page']);
        if($products_max != 0 && $products_max >= -1){
 
        	if(is_user_logged_in()){
 
        		$user_id = get_current_user_id();
    	    	$limit = get_user_meta( $user_id, '_product_per_page', true );
 
    	    	if(!$limit){
    	    		add_user_meta( $user_id, '_product_per_page', $products_max);
    	    	}else{
    	    		update_user_meta( $user_id, '_product_per_page', $products_max, $limit);
    	    	}
        	}
 
            $woocommerce->session->jc_product_per_page = $products_max;
            return $products_max;
        }
    }

Check session for existing value

Since the previous function stored data into a WooCommerce session variable, all we need to do know is check that the session variable has been saved and retrieve that value.

    // load product limit from session
    if(isset($woocommerce->session->jc_product_per_page)){
 
        // set products per page from woo session
        $products_max = intval($woocommerce->session->jc_product_per_page);
        if($products_max != 0 && $products_max >= -1){
            return $products_max;
        }
    }

Check user meta for existing value

One final thing we need to do is check that if no session variable has been set but if the user is logged in then we can check to see if they have their preference saved in user meta, if so load it and return the new amount.

    // load product limit from user meta
    if(is_user_logged_in() && !isset($woocommerce->session->jc_product_per_page)){
 
    	$user_id = get_current_user_id();
    	$limit = get_user_meta( $user_id, '_product_per_page', true );
 
    	if(array_key_exists($limit, $options)){
    		$woocommerce->session->jc_product_per_page = $limit;
    		return $limit;
    	}
    }

With some styling added to the dropdown this script will make a useful addition to any WooCommerce shop giving the customer that extra control over what they are looking at.

WooCommerce Products per page dropdown – Complete Source Code

    <?php
    /**
     * Get current users preference
     * @return int
     */
    function jc_get_products_per_page(){
 
        global $woocommerce;
 
        $default = 24;
        $count = $default;
        $options = jc_get_products_per_page_options();
 
        // capture form data and store in session
        if(isset($_POST['jc-woocommerce-products-per-page'])){
 
            // set products per page from dropdown
            $products_max = intval($_POST['jc-woocommerce-products-per-page']);
            if($products_max != 0 && $products_max >= -1){
 
            	if(is_user_logged_in()){
 
            		$user_id = get_current_user_id();
    		    	$limit = get_user_meta( $user_id, '_product_per_page', true );
 
    		    	if(!$limit){
    		    		add_user_meta( $user_id, '_product_per_page', $products_max);
    		    	}else{
    		    		update_user_meta( $user_id, '_product_per_page', $products_max, $limit);
    		    	}
            	}
 
                $woocommerce->session->jc_product_per_page = $products_max;
                return $products_max;
            }
        }
 
        // load product limit from user meta
        if(is_user_logged_in() && !isset($woocommerce->session->jc_product_per_page)){
 
            $user_id = get_current_user_id();
            $limit = get_user_meta( $user_id, '_product_per_page', true );
 
            if(array_key_exists($limit, $options)){
                $woocommerce->session->jc_product_per_page = $limit;
                return $limit;
            }
        }
 
        // load product limit from session
        if(isset($woocommerce->session->jc_product_per_page)){
 
            // set products per page from woo session
            $products_max = intval($woocommerce->session->jc_product_per_page);
            if($products_max != 0 && $products_max >= -1){
                return $products_max;
            }
        }
 
        return $count;
    }
    add_filter('loop_shop_per_page','jc_get_products_per_page');
 
    /**
     * Fetch list of avaliable options
     * @return array
     */
    function jc_get_products_per_page_options(){
    	$options = apply_filters( 'jc_products_per_page', array(
    		12 => __('12', 'woocommerce'),
    		24 => __('24', 'woocommerce'),
    		48 => __('48', 'woocommerce'),
    		96 => __('96', 'woocommerce')
        ));
 
    	return $options;
    }
 
    /**
     * Display dropdown form to change amount of products displayed
     * @return void
     */
    function jc_woocommerce_products_per_page(){
 
        $options = jc_get_products_per_page_options();
 
        $current_value = jc_get_products_per_page();
        ?>
        <div class="products-per-page">
            <span>Products Per Page:</span>
            <form action="" method="POST" class="woocommerce-products-per-page">
                <select name="jc-woocommerce-products-per-page" onchange="this.form.submit()">
                <?php foreach($options as $value => $name): ?>
                    <option value="<?php echo $value; ?>" <?php selected($value, $current_value); ?>><?php echo $name; ?></option>
                <?php endforeach; ?>
                </select>
            </form>
        </div>
        <?php
    }
 
    add_action('woocommerce_before_shop_loop', 'jc_woocommerce_products_per_page', 25);
    ?>


Liked this article? help spread the word.