Posted on

WooCommerce popularity and price sorting

Many WooCommerce users use search sorting that allows users to sort by popularity or price. Unfortunately while Relevanssi works fine with WooCommerce, those sorts do not work. Relevanssi doesn’t know about price or popularity, and the sorting assumes there’s default WP search underneath. Relevanssi doesn’t do meta field sorting as easily as the default WP search does.

No worries, though. All you need to do is to tell Relevanssi how to sort those posts. First, however, you need to disable the meta key parameter, because that messes things up with Relevanssi:

add_filter('relevanssi_modify_wp_query', 'rlv_remove_price');
function rlv_remove_price($query) {
    if (isset($query->query_vars['meta_key']) && $query->query_vars['meta_key'] == "_price") {
        $query->query_vars['meta_key'] = "";
        global $price_sort;
        $price_sort = strtolower($query->query_vars['order']);
    }
    if (isset($query->query_vars['meta_key']) && $query->query_vars['meta_key'] == "total_sales") {
        $query->query_vars['meta_key'] = "";
        global $sales_sort;
        $sales_sort = true;
    }
    return $query;
}

This function checks if the meta_key is set to _price or total_sales (if the meta field names are different in your installation, you need to change them here) and clears out the meta_key field while setting a global variable that can be accessed later on.

add_filter('relevanssi_hits_filter', 'rlv_price_sort');
function rlv_price_sort($hits) {
    global $wp_query, $price_sort, $sales_sort;
 
	if (isset($price_sort)) {
		$prices = array();
	    	foreach ($hits[0] as $hit) {
        		$price = get_post_meta($hit->ID, '_price', true);
	       		if (!isset($prices[$price])) $prices[$price] = array();
			array_push($prices[$price], $hit);
	       	}
 
		if ($price_sort == 'asc') {
			ksort($prices);
		} else {
			krsort($prices);
		}
 
	   	$sorted_hits = array();
		foreach ($prices as $price => $year_hits) {
   	   		$sorted_hits = array_merge($sorted_hits, $year_hits);
	    	}
		$hits[0] = $sorted_hits;
	}
 
	if (isset($sales_sort)) {
		$sales = array();
	    	foreach ($hits[0] as $hit) {
        		$sale_count = get_post_meta($hit->ID, 'total_sales', true);
	       		if (!isset($sales[$sale_count])) $sales[$sale_count] = array();
			array_push($sales[$sale_count], $hit);
	       	}
 
		krsort($sales);
 
	   	$sorted_hits = array();
		foreach ($sales as $sale_count => $year_hits) {
   	   		$sorted_hits = array_merge($sorted_hits, $year_hits);
	    	}
		$hits[0] = $sorted_hits;
	}
 
    return $hits;
}

This second function does the actual sorting. Again, it assumes the price is in _price custom field and that the popularity is based on total_sales.

  • SM

    hi, where does this code get added?

    thanks!

  • Mike Entyce

    Hello, thanks for this. I would like to sort the search results by price ascending. I’ve added both codes from above but it doesn’t look like it’s working… Do I need to change anything in the plugin settings?
    Thanks

    • No, those codes should do it. Then just set the “order” parameter to “asc” and “meta_key” to “_price”.