We’ve got a plugin that will allow you to add WooCommerce product sorting options (not to mention one that will remove core sorting options as desired), but you may need a more customized solution for sorting your products.

In this case, you may want to sort WooCommerce products by your custom fields or by other post meta values. Let’s go over how we can add sorting options for custom fields that we’ve set for our WooCommerce products. First, we’ll go over what your custom fields should look like.

Add Custom Fields to WooCommerce Products

You can quickly add custom fields to all WooCommerce products by importing them with your custom fields set as post meta. The WooCommerce Product CSV Import suite extension is great for this, and will allow you to both export and import products. This will enable you to set post meta for your products in bulk as needed — export products, add this info, and re-import them to merge your changes.

You can also add custom fields directly from the “Edit Product” screen:

WooCommerce Product Custom Fields

This will allow you to add both text-based and number-based values for your post meta information. Once this information has been added to products, you’ll be able to use it to sort them.

Sort WooCommerce Products by Custom Field

WooCommerce has a bit of helpful information on how to sort WooCommerce products, but it doesn’t address the information we’ll need to sort on: meta values. We can sort by meta values that are both words and numbers, so we’ll do an example of each in this sample snippet.

You can add as many new sorting options as you’d like, but I’m going to add two: Sort by location (word-based) and Sort by points earned (number-based). This could be handy if you, for example, use WooCommerce Points and Rewards for a loyalty program, but some products offer double or triple points and you’d like customers to know.

Now on to the code! If you’re not sure how to add this, check out our tutorial on adding custom code to your site. I’m going to add it via the Code Snippets plugin.

Okay, so what is this doing? The first part creates the sorting arguments. It tells WooCommerce what to use to sort the products when these sorting options are used. You can add extra cases if you’d like to create more than 2 new sorting options.

Notice in the first one that I’ve sorted by meta_value as I want to sort alphabetically, but in the second example I’ve used meta_value_num because I want to sort numerically. I can also determine whether I should sort in ascending (asc) or descending (desc) order. Set these as desired.

For alphabetical sorting, I actually want to sort ascending, as “A” is a regarded as the starting value, and “Z” is regarded as an ending (higher) value. For numerical sorting, I’m going to sort descending because I want the highest points shown first.

As the last note on the first function, I then tell WooCommerce which meta key should be used. This will be the key for your custom field, which will be something like location, points, _wholesale_price, _stock, or others (if you’re curious about the leading underscore, check this out or this).

The second function here will just add my new sorting option to the frontend of my site, as well as add it as a default option in the admin if I’d like to use it for the default. You can edit this text as desired, but I’d keep it short since it will be in your dropdown on the shop pages.

What it looks like

Okay, so ready to see what it will look like when you sort WooCommerce products in your shop? First, these options will be added to the sorting dropdown:

Sort WooCommerce Products

When I select one, the corresponding sorting arguments that we’ve added will be used. I’ve added the post meta to this screenshot so you can see it in action. Here’s my alphabetical sorting by location:

WooCommerce sort by location

And here’s my numerical sorting by points earned for purchasing:

WooCommerce sort by points

Pretty beautiful, huh?

A Potential Hiccup

You may notice that my examples above only include products that have these custom fields set. If these custom fields are not available, they won’t be included in the sorting options.

I like to keep it this way for stuff like “location”, as I may not want to show a bunch of products that don’t have a location assigned at all. However, for my “points” sorting, this won’t do. I want to add the rest of my products after this. You can do so by setting the points custom field for the rest of your products, but leaving it blank.

I just did this with two products, and now they’re shown with this sorting:

Updated meta fields

This is why I recommend using the Product CSV import, as you can set all of these fields blank as desired. If you try to do this within the “Edit Product” screen, just be aware you’ll run into a minor speedbump. The product screen requires a value be set for a custom field:

WooCommerce add custom fields

To work around this, just add your fields with some arbitrary value set:

WooCommerce set custom field values

You can then delete it the value to keep the custom field blank and update your product.

WooCommerce remove post meta values

Not as easy as importing, but it does the job. Now go and sort on all the meta fields you heart desires 🙂 .


Update: On a final note, we’ve occasionally seen people try to do something like this, but the sorting option never appears in the dropdown. This is almost certainly a theme issue, as some (1) override this dropdown and hard-code the core sorting options, or (2) replace the selector via javascript for a fancy dropdown, but hardcode core sorting arguments instead of using WooCommerce methods to get them.

Published by Beka Rice

Beka leads product direction for SkyVerge, focusing on new features for our plugins and Jilt. She spends a lot of time on research and interviews, but likes to write so she has an excuse to spend more time jamming out to anything from The Clash to Lady Gaga.

23 Comments

  1. Hi Beka,

    How do you show the custom field data below the product images?

  2. Hello everybody!

    You wrote about the little hiccup: “You may notice that my examples above only include products that have these custom fields set.”

    I just solved this problem in my shop with the following code, where the check also includes the posts without the specific custom value set – maybe you can add this to your post:

    add_filter( 'woocommerce_get_catalog_ordering_args', 'points_awarded_ordering_args');
    function points_awarded_ordering_args($args) {
        global $wpdb;
        $orderby_value = isset( $_GET['orderby'] ) ? wc_clean( $_GET['orderby'] ) : apply_filters( 'woocommerce_default_catalog_orderby', get_option( 'woocommerce_default_catalog_orderby' ) );
    
    if ( 'points_awarded' == $orderby_value ) {
        // Sorting handled later through a hook
        add_filter( 'posts_clauses', 'order_by_points_awarded_post_clauses' );
    }
    
    return $args;
    }
    
    function order_by_points_awarded_post_clauses( $args ) {
        global $wpdb;
    
    $args['join'] .= "
              LEFT JOIN wpshop_postmeta AS points ON (wpshop_posts.ID = points.post_id AND favourite.meta_key = 'points_awarded')
        ";
    
    $args['orderby'] = "favourite.meta_value DESC, $wpdb->posts.post_date DESC";
    
    return $args;
    
    }
  3. woocommerce_clean() is depreciated. use wc_clean() instead..

  4. I am pulling in some custom meta data on my product(category) loops, such as SKU and a specific reference letter that matches an exploded parts diagram for that category. The reference letter is unique to the category, and I follow a specific naming convention (metafield name = eref-“categoryslug”) for the custom meta fields, so that I can dynamically pull the right reference letter depending on the category being viewed. To accomplish this on the category page product loops, I use:
    echo $product->get_sku( ', ', '<span class="posted_in">', '</span>' );
    $catslug = get_query_var( 'product_cat' );
    if(get_field('eref-' . $catslug . ''))
    {
    echo '<div><span>REF: ' . get_field('eref-' . $catslug . '') . '</span></div>';
    }

    I’d like to set the default product sorting to:
    First sort by accending reference letter.
    Then sort by accending SKU for all products not containing a matching reference letter in for that category.

    Any WooCommerce pro coders out there who think this is possible? I’m willing to make this a paid job.

  5. See the reference letter in action here:
    https://www.purekarting.com/product-category/otk-parts/exhaust-system-2015/

    and another example where you can see a product (A.B. Nut) which exists in both categories, but has a different reference letter for each category:
    https://www.purekarting.com/product-category/otk-parts/pedals/footrest/

  6. I was able to get it to sort by my custom reference letters using this “orderby” code
    case 'ref':
    $sort_args['orderby'] = 'meta_value';
    // Sort by meta_value because we're using alphabetic sorting
    $sort_args['order'] = 'asc';
    $catslug = get_query_var( 'product_cat' );
    $sort_args['meta_key'] = 'eref-' . $catslug . '';
    // use the meta key you've set for your custom field, i.e., something like "location" or "_wholesale_price"
    break;

    However it places all the items WITHOUT a reference letter before those which DO have a REF set.

    How can I make them appear after those with a REF set? And further can I first sort by REF, and then sort all remaining products without REF by SKU ascending?

  7. I want to sort audio messages by the date they were spoken. This is different from the post date, or date the products were added to my store. I added a custom field: message_date. I want to add two items to the sort-by drop down: Sort messages: newest first, and Sort messages: oldest first. Both use the same custom field. Can this be done with your code?

    • Never mind. I figured it out. At first I thought the “case” had to match the “meta_key”, which it doesn’t. I created a case for ascending and one for descending for the same meta_key.

  8. I tried to use this on a custom date field but it sorts based on the first number only (alphanumerically) – Is it possible to convert the string to a date and sort by date?

    I’m having a play but I’m not having a lot of luck…

  9. Do you put this code in the functions.php of the child theme?

  10. so how do i use same and search for the word new_york instead of asc in location ?

  11. Snippet works great – except I am using a date value as SKU (expiry date).
    Which is a problem, as the code seems to look for the first two digits only, resulting in 25.05.2016 getting ranked before 26.04.2016 for example.
    I already tried with different seperators (blank, /), different date formats – but I cant get this fixed. Any ideas?

    • You’d have to have a date format that would let you sort in number order, like 2016.04.26 instead — the code only sorts by number, it doesn’t recognize dates or timestamps to compare them, so sorting by the first digits is expected.

  12. Hello all

    Can anyone tell me why this does not return any results ?

    function skyverge_add_postmeta_ordering_args( $sort_args ) {
    
    $orderby_value = isset( $_GET['orderby'] ) ? wc_clean( $_GET['orderby'] ) : apply_filters( 'woocommerce_default_catalog_orderby', get_option( 'woocommerce_default_catalog_orderby' ) );
        switch( $orderby_value ) {
    
        // Name your sortby key whatever you'd like; must correspond to the $sortby in the next function
        case 'price_per_mtr_square':
            $sort_args['orderby'] = 'meta_value_num';
            $sort_args['order']    = 'asc';
            //$discount = get_query_var( 'Discount' );
            $discount =  get_post_meta( get_the_ID(), 'Discount', true );
    
        $discount = str_replace("%","",$discount);
        $discount = 100-$discount;
        //$pm2 = get_query_var( 'Price per Mtr Squ' );
        $pm2 =  get_post_meta( get_the_ID(), 'Price per Mtr Squ', true );
    
        $pm2 = $pm2;
        $pm3 = $pm2/100 *$discount;
        $pm3= number_format($pm3, 3);
            $sort_args['meta_key'] = $pm3;
            break;
    
    }
    
    return $sort_args;
    
    }

    I am trying to do some calcs on a product custom field and use the result to sort the products

    Thanks a lot

    joe

  13. Hi again

    Is there a way to transform the value of a meta_key before or at the point it is used for sorting ?

    something like so, using the value of a custom product field

    switch( $orderby_value ) {
    
    case 'price_per_mtr_square':
        $rp  =  get_post_meta('_price', true );
        //add VAT @20%
        $rp = $rp*1.2;
    
        $sort_args['orderby'] = 'meta_value_num';
        $sort_args['order']    = 'ASC';
        $sort_args['meta_key'] = 'Tiles per Mtr Squ' * $rp;
    
        break;
    }

    thanks

    joe

  14. is there anyone looking at this thread ?

    I really need help to resolve the issue above

    thanks

    joe

Hmm, looks like this article is quite old! Its content may be outdated, so comments are now closed.