WordPress.org

Support

Support » Plugins and Hacks » [Resolved] Order Results by SKU first

[Resolved] Order Results by SKU first

  • I have a WooCommerce site and have relevanssi working. My customers can search for SKU (Part Number).

    This site sells tool boxes so some products have the SKU of their individual parts in their descriptions.

    I would like to order the results so that the search page shows the products with the exact SKU in the SKU field first then the products with the same SKU in the description.

    I.e the exact match SKU field is always shown first.

    This search shows the problem as the exact match product comes up as no. 10 out of 11 returns.

    http://www.teng.mossdemo.com.au/?s=TTMI16

    http://wordpress.org/plugins/relevanssi/

Viewing 7 replies - 1 through 7 (of 7 total)
  • Plugin Author Mikko Saari

    @msaari

    Use filters. relevanssi_hits_filter lets you modify the search results. You can use it to fix this: if the search term matches a SKU, you can make sure that result is shown on top of the results.

    Hi Mikko

    Thank you for your reply, for anyone else who wants to put the exact match SKU results above the rest here is the code in my child theme functions file.

    It is a little lazy as all I have changed is the search variable to sku for the URL and _sku for the field to check for the result in.

    add_filter('relevanssi_hits_filter', 'order_the_results');
    function order_the_results($hits) {
        global $wp_query;
    
    	switch ($wp_query->query_vars['orderby']) {
    		case 'sku':
    	        $likes = array();
        		foreach ($hits[0] as $hit) {
            		$likecount = get_post_meta($hit->ID, '_sku', true);
    	        	if (!isset($likes[$likecount])) $likes[$likecount] = array();
        	    			array_push($likes[$likecount], $hit);
            		}
    
    			if ($wp_query->query_vars['order'] == 'asc') {
    				ksort($likes);
    			} else {
    				krsort($likes);
    			}
    
    	      		$sorted_hits = array();
    			foreach ($likes as $likecount => $year_hits) {
       	     		$sorted_hits = array_merge($sorted_hits, $year_hits);
    	        }
    		$hits[0] = $sorted_hits;
    		break;
    
    	case 'relevance':
    		//do nothing
    		break;
    
    	 }
        return $hits;
    }

    And this is the Search form on http://www.teng.mossdemo.com.au/

    <form class="search" action="<?php echo home_url(); ?>/" method="get">
    <p>Enter Part Number or any other term</p>
    	<fieldset>
    		<span class="text"><input name="s" id="s" type="text" value="" placeholder="<?php echo __('Search ...', 'Avada'); ?>" /></span>
    	</fieldset>
       <input name="orderby" type="hidden" id="orderby" value="sku" />
    </form>

    I don’t know whether that adding a hidden field in the search form was the best way to append the ‘&orderby=sku’ to the URL but as my theme had the searchform.php like this, it was the laziest way to do it!

    Plugin Author Mikko Saari

    @msaari

    That is a decent way to do it, another would be using relevanssi_modify_wp_query to slip it in invisibly.

    Hi Mikko

    I have had to adjust this so that I add in the order by asc to make sure it works under all circumstances for a SKU search, however I seem to have lost the the relevancy ordering below the top return.

    In this search http://www.teng.mossdemo.com.au/?s=MB442&orderby=sku&order=asc I get the correct product by a Part number search of MB442 but if I then search for what is its Product Title (Post Title) of “side cutting plier” I get this result

    http://www.teng.mossdemo.com.au/?s=side+cutting+plier&orderby=sku&order=asc

    Obviously I have dropped the relevancy part of the search after the SKU search has completed. How do I re-instate this please?

    I have tried this but it doesn’t seem to work…

    Just to clarify, if there is a SKU match then that must come first, if there is no SKU match then the relevancy should kick in. It doesn’t necessarily need to be the title but I suppose it would be useful to know how to target the title next…

    add_filter('relevanssi_hits_filter', 'order_the_results');
    function order_the_results($hits) {
        global $wp_query;
    
    	switch ($wp_query->query_vars['orderby']) {
    		case 'sku':
    	        $likes = array();
        		foreach ($hits[0] as $hit) {
            		$likecount = get_post_meta($hit->ID, '_sku', true);
    	        	if (!isset($likes[$likecount])) $likes[$likecount] = array();
        	    			array_push($likes[$likecount], $hit);
            		}
    
    			if ($wp_query->query_vars['order'] == 'asc') {
    				ksort($likes);
    			} else {
    				krsort($likes);
    			}
    
    	      		$sorted_hits = array();
    			foreach ($likes as $likecount => $year_hits) {
       	     		$sorted_hits = array_merge($sorted_hits, $year_hits);
    	        }
    		$hits[0] = $sorted_hits;
    		break;
    
    case 'title':
    	        $titles = array();
        		foreach ($hits[0] as $hit) {
            		$titlescount = get_post_meta($hit->ID, 'wp_title', true);
    	        	if (!isset($titles[$titlescount])) $titles[$titlescount] = array();
        	    			array_push($titles[$titlescount], $hit);
            		}
    
    			if ($wp_query->query_vars['order'] == 'asc') {
    				ksort($titles);
    			} else {
    				krsort($titles);
    			}
    
    	      		$sorted_hits = array();
    			foreach ($titles as $titlescount => $year_hits) {
       	     		$sorted_hits = array_merge($sorted_hits, $year_hits);
    	        }
    		$hits[0] = $sorted_hits;
    		break;
    
    case 'relevance':
    		//do nothing
    		break;
    
    	 }
        return $hits;
    }
    Plugin Author Mikko Saari

    @msaari

    I think you’re complicating this a bit by recycling code that doesn’t quite do what you’re doing. Here’s a code that will go through the results (and it’s always on, without any extra hidden input fields) and pull the results that have a _sku matching the search query on top of the results, maintaining the relevancy of the results:

    add_filter('relevanssi_hits_filter', 'sku_hits_first');
    function sku_hits_first($hits) {
    	$sku_hits = array();
    	$everything_else = array();
    	global $wp_query;
    	foreach ($hits[0] as $hit) {
    		$sku = get_post_meta($hit->ID, '_sku', true);
    		if ($sku == $wp_query->query_vars['s']) {
    			$sku_hits[] = $hit;
    		}
    		else {
    			$everything_else[] = $hit;
    		}
    	}
    	$hits[0] = array_merge($sku_hits, $everything_else);
    	return $hits;
    }

    Does that work the way you want it to work?

    Ah,

    Thank you Mikko it works exactly as I wanted.

    Thank you very much indeed. I am very much a code re-user rather than a code writer I think it is safe to say.

Viewing 7 replies - 1 through 7 (of 7 total)
  • The topic ‘[Resolved] Order Results by SKU first’ is closed to new replies.