• Resolved mirefoot

    (@mirefoot)


    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.

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

    https://www.ads-software.com/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.

    Thread Starter mirefoot

    (@mirefoot)

    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 https://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.

    Thread Starter mirefoot

    (@mirefoot)

    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 https://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

    https://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?

    Thread Starter mirefoot

    (@mirefoot)

    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?

    Thread Starter mirefoot

    (@mirefoot)

    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 ‘Order Results by SKU first’ is closed to new replies.