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.

See more WooCommerce tips.

6 comments WooCommerce popularity and price sorting

  1. 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

  2. Hi,

    The code is not working for me, is it still compatible with the latest version of WooCommerce?
    If it does, what can I be doing wrong?

    Thanks

    1. Yes, I’ve checked and it seems things have changed in WooCommerce.

      I wrote this new code for price sorting and it’s working for me:

      add_filter(‘relevanssi_hits_filter’, ‘rlv_price_sort’);
      function rlv_price_sort($hits)
      {
      if (is_search()) {
      $ordering = WC_Query::get_catalog_ordering_args();
      if (($ordering[‘orderby’] != ‘date ID’) && ($ordering[‘meta_key’] == ”)) {
      $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);
      }
      $priceorder = strtolower($ordering[‘order’]);
      if ($priceorder == ‘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;
      }
      return $hits;
      }
      }

Leave a Reply

Your email address will not be published. Required fields are marked *