Sort by custom meta value doesn’t work in WooCommerce products sort by

Tags: , , , ,



I’m trying to add a sorting option for woocommerce products’s list.

The goal is to sort products by a meta value with meta key called _rating. For now I generate this meta value with a function executed at plugin’s activation.

Issue :

Products are not sorted by meta value but by ID instead

My plugin :

<?php
/*
  Plugin Name: Sort by meta value
  Description: Add sort option in product list by meta ratings
  Author: Aurélien
  Version: 1.0.0
  Text Domain: sort-by-meta
  Domain Path: /languages
 */

/**
* Check if WooCommerce is active
**/
if ( in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) {



    class Sort_By_Meta{


        public static function init()
        {
            //Add custom fields for every product
            $all_ids = get_posts( array(
                'post_type' => 'product',
                'numberposts' => -1,
                'post_status' => 'publish',
                'fields' => 'ids',
            ) );
            foreach ( $all_ids as $id ) {
                update_post_meta($id,"_rating", Sort_By_Meta::generateRandomString());
            }
        }

        //Function which generates random string
        public function generateRandomString($length = 10) {
            $characters = 'abcdefghijklmnopqrstuvwxyz';
            $charactersLength = strlen($characters);
            $randomString = '';
            for ($i = 0; $i < $length; $i++) {
                $randomString .= $characters[rand(0, $charactersLength - 1)];
            }
            return $randomString;
        }
    }

    register_activation_hook( __FILE__, array('Sort_By_Meta', 'init' ));


    function 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 ) {
            case 'rating':
                $sort_args['orderby']  = 'meta_value';
                $sort_args['order']    = 'DESC';
                $sort_args['meta_key'] = '_rating';
                break;
        }
        return $sort_args;
    }
    add_filter( 'woocommerce_get_catalog_ordering_args', 'add_postmeta_ordering_args' );


    function add_new_postmeta_orderby( $sortby ) {
        $sortby['rating'] = "rating";
        return $sortby;
    }
    add_filter( 'woocommerce_default_catalog_orderby_options', 'add_new_postmeta_orderby' );
    add_filter( 'woocommerce_catalog_orderby', 'add_new_postmeta_orderby' );
}

Answer

I tested your code and at first sight nothing seemed wrong but the desired result was not forthcoming. When I replaced rating with something like rank this seems to work.

This is because rating is already in use by “Sort by average rating”

function 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 ) {
        case 'rank':
            $sort_args['orderby']  = 'meta_value';
            $sort_args['order']    = 'ASC';
            $sort_args['meta_key'] = '_rating';
            break;
    }

    return $sort_args;
}
add_filter( 'woocommerce_get_catalog_ordering_args', 'add_postmeta_ordering_args', 10, 1 );


function add_new_postmeta_orderby( $sortby ) {
    $sortby['rank'] = 'Rating';
    return $sortby;
}
add_filter( 'woocommerce_default_catalog_orderby_options', 'add_new_postmeta_orderby', 10, 1 );
add_filter( 'woocommerce_catalog_orderby', 'add_new_postmeta_orderby', 10, 1 );


Source: stackoverflow