Custom Order By Attributes

This tutorial will teach you as to how you can add custom sorting or ordering of product by its attribute in shop page.

WooCommerce comes up with a few useful product order, which is quite handy as small website, but if you want to increase your user experience and want to reduce bounce rate then you might have to give user few more option for filtering, ordering, etc., so in this tutorial we ‘ll discussing as how easily you can add such options we few lines of code. So tighten your seatbelt. 😉

Directly we cannot short product with attributes/taxonomy in WooCommerce shop page, so what we have to do is first save the attributes in postmeta from there we can sort product by using meta_value. To do this we have to use save_post hook which is called on every post/product create or update.

/**
 * Save product attributes to post metadata when a product is saved.
 *
 * @param int $post_id The post ID.
 * @param post $post The post object.
 * @param bool $update Whether this is an existing post being updated or not.
 *  
 * Refrence: https://codex.wordpress.org/Plugin_API/Action_Reference/save_post
 */
function wh_save_product_custom_meta($post_id, $post, $update) {
    $post_type = get_post_type($post_id);
    // If this isn't a 'product' post, don't update it.
    if ($post_type != 'product')
        return;

    if (!empty($_POST['attribute_names']) && !empty($_POST['attribute_values'])) {
        $attribute_names = $_POST['attribute_names'];
        $attribute_values = $_POST['attribute_values'];
        foreach ($attribute_names as $key => $attribute_name) {
            switch ($attribute_name) {
                //for color (string)
                case 'pa_color':
                    //it may have multiple color (eg. black, brown, maroon, white) but we'll take only the first color.
                    if (!empty($attribute_values[$key][0])) {
                        update_post_meta($post_id, 'pa_color', $attribute_values[$key][0]);
                    }
                    break;
                //for lenght (int)
                case 'pa_length':
                    if (!empty($attribute_values[$key][0])) {
                        update_post_meta($post_id, 'pa_length', $attribute_values[$key][0]);
                    }
                    break;
                default:
                    break;
            }
        }
    }
}

add_action( 'save_post', 'wh_save_product_custom_meta', 10, 3);

Now that we have added attributes to postmeta now we have to build the logic for ordering them

/** 
 *  Main ordering logic for orderby attribute
 *  Refrence: https://docs.woocommerce.com/document/custom-sorting-options-ascdesc/
 */
add_filter('woocommerce_get_catalog_ordering_args', 'wh_catalog_ordering_args');

function wh_catalog_ordering_args($args) {
    global $wp_query;
    if (isset($_GET['orderby'])) {
        switch ($_GET['orderby']) {
            //for attribute/taxonomy=pa_color
            case 'pa-color-asc' :
                $args['order'] = 'ASC';
                $args['meta_key'] = 'pa_color';
                $args['orderby'] = 'meta_value';
                break;
            case 'pa-color-desc' :
                $args['order'] = 'DESC';
                $args['meta_key'] = 'pa_color';
                $args['orderby'] = 'meta_value';
                break;
            //for attribute/taxonomy=pa_length
            case 'pa-length-asc' :
                $args['order'] = 'ASC';
                $args['meta_key'] = 'pa_length';
                $args['orderby'] = 'meta_value_num';
                break;
            case 'pa-length-desc' :
                $args['order'] = 'DESC';
                $args['meta_key'] = 'pa_length';
                $args['orderby'] = 'meta_value_num';
                break;
        }
    }
    return $args;
}

Now we are all set let’s give Site Admin and User the control to chose shorting option.

/**
 *  Lets add the created sorting order to the dropdown list.
 *  Refrence: http://hookr.io/filters/woocommerce_catalog_orderby/
 */
//To under Default Product Sorting in Dashboard > WooCommerce > Settings > Products > Display.
add_filter( 'woocommerce_default_catalog_orderby_options', 'wh_catalog_orderby' );
add_filter('woocommerce_catalog_orderby', 'wh_catalog_orderby');

function wh_catalog_orderby($sortby) {
    $sortby['pa-color-asc'] = 'Sort by Color: A - Z';
    $sortby['pa-color-desc'] = 'Sort by Color: Z - A';
    $sortby['pa-length-asc'] = 'Sort by Length: Small - Large';
    $sortby['pa-length-desc'] = 'Sort by Length: Large - Small';
    return $sortby;
}

Let me know in the comments if you face any probelm while implementing it or you have a better solution to it, then surely we will love to hear form you.

Default image
Raunak Gupta
I'm an expert Laravel, WooCommerce, WordPress theme and plugin developer, over the time I have developed several sites and applications. I like to help the upcoming developer, So I share my experience through this blog.
Articles: 18

18 Comments

  1. I’m not fond of adding multiple keys in meta table and ordering the product by that. Isn’t there any better way?

    • Hi Adalie,
      Till now I haven’t found out any better way, but if you got one then do share with us, I would love to know.

  2. Hi Raunak, in my case not execute. Not show the attributes, I don’t know what happens.
    My WordPress version is 4.7.3

    Can you help me?

  3. Hey Raunak, the add_action for wh_save_product_custom_meta is missing in the first code part.

  4. Hi I have searched for a code like this for several days. In my case, the attributes are for beers and I need to filter by attribute value, alcohol level, bitterness and color. try to adapt your code, it does not give errors but I can not make it work. I apologize for my bad English but use a translator since I speak Spanish. Regards

    • Hi Miguel,

      I missed out to add save_post action. Now I have updated my post, so it should be working now.
      And just for you, I have translated the above line in Spanish 😉

      “Me perdí para agregar la acción save_post. Ahora actualicé mi publicación, por lo que debería estar funcionando ahora.”

  5. I like this article, useful stuff on here : D.

  6. tried this code but sorting is not being done, have created an attribute named colour and changed in all the codes given above from color to colour. But sorting of asc to desc or vice-versa not happening, it displays a blank page.

    • Hi Malar,

      Can you please share you code that you have written, and have you added add_action( 'save_post', 'wh_save_product_custom_meta', 10, 3); ?

  7. The code is not working what i tried .
    function wh_save_product_custom_meta($post_id, $post, $update) {
    $post_type = get_post_type($post_id);
    // If this isn’t a ‘product’ post, don’t update it.
    if ($post_type != ‘product’)
    return;

    if (!empty($_POST[‘attribute_names’]) && !empty($_POST[‘attribute_values’])) {
    $attribute_names = $_POST[‘attribute_names’];
    $attribute_values = $_POST[‘attribute_values’];
    foreach ($attribute_names as $key => $attribute_name) {
    switch ($attribute_name) {
    //for lenght (int)
    case ‘pa_stamp-year’:
    if (!empty($attribute_values[$key][0])) {
    update_post_meta($post_id, ‘pa_stamp-year’, $attribute_values[$key][0]);
    }
    break;
    default:
    break;
    }
    }
    }
    }

    add_action( ‘save_post’, ‘wh_save_product_custom_meta’, 10, 3);

    add_filter(‘woocommerce_get_catalog_ordering_args’, ‘wh_catalog_ordering_args’);

    function wh_catalog_ordering_args($args) {
    global $wp_query;
    if (isset($_GET[‘orderby’])) {
    switch ($_GET[‘orderby’]) {

    case ‘pa_stamp-year’ :
    $args[‘order’] = ‘ASC’;
    $args[‘meta_key’] = ‘pa_stamp-year’;
    $args[‘orderby’] = ‘meta_value_num’;

    break;
    default:
    break;
    }
    }
    return $args;
    }

    add_filter( ‘woocommerce_default_catalog_orderby_options’, ‘wh_catalog_orderby’ );
    add_filter(‘woocommerce_catalog_orderby’, ‘wh_catalog_orderby’);

    function wh_catalog_orderby($sortby) {
    $sortby[‘pa_stamp-year’] = ‘Sort by year: Small – Large’;
    return $sortby;
    }

  8. I want to implement this on my website can you please help contact me on my email id

  9. Please update your code to this..

    your code saves the id of the custom attribute to post meta, not the value

    /**
    * Save product attributes to post metadata when a product is saved.
    *
    * @param int $post_id The post ID.
    * @param post $post The post object.
    * @param bool $update Whether this is an existing post being updated or not.
    *
    * Refrence: https://codex.wordpress.org/Plugin_API/Action_Reference/save_post
    */
    function wh_save_product_custom_meta($post_id, $post, $update) {
    $post_type = get_post_type($post_id);
    // If this isn’t a ‘product’ post, don’t update it.
    if ($post_type != ‘product’)
    return;

    $_product = wc_get_product($post_id);
    if(!$_product){
    return;
    }

    $mi_color = $_product->get_attribute( ‘pa_color’ );
    $mi_length = $_product->get_attribute( ‘pa_length’ );
    $mi_size = $_product->get_attribute( ‘pa_size’ );

    update_post_meta($_product->get_id(), ‘pa_size’, $mi_size);
    update_post_meta($_product->get_id(), ‘pa_length’, $mi_length);
    update_post_meta($_product->get_id(), ‘pa_color’, $mi_color);

    }
    add_action( ‘wp_insert_post’, ‘wh_save_product_custom_meta’, 10, 3);

  10. Hi, I tried to follow this procedure, but they are not working. Once asked for sorting, no product results. can you help me understand why?

  11. How do I save all the values ​​in the array and not just a value with the index [0]

    • Hi @Fernando,
      In this post I haven’t mentioned any code regarding saving. can you please elaborate as what you want to achieve. If you simply want to save all the array value you can use maybe_serialize() method.

      • I’m sorry if I misunderstood
        I have an attribute: Price M2
        In this line and by the code comment
        //it may have multiple colour (eg. black, brown, maroon, white) but we’ll take only the first colour.
        if (!empty($attribute_values[$key][0]) {
        update_post_meta($post_id, ‘pa_color’, $attribute_values[$key][0]);
        You are only saving the first key i.e. black, you are not saving all 4 values you mention. I would need to save all values,
        My page is as follows: https://www.vigorita.com.ar/categoria-producto/pisos-flotantes/page/2/
        And as you can see the prices per m2 are not sorted.

Leave a Reply to Rita CésarCancel Reply