WordPress.org

Forums

Relevanssi - A Better Search
[resolved] Order Results by SKU first (8 posts)

  1. mirefoot
    Member
    Posted 1 year ago #

    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/

  2. Mikko Saari
    Member
    Plugin Author

    Posted 1 year ago #

    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.

  3. mirefoot
    Member
    Posted 1 year ago #

    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!

  4. Mikko Saari
    Member
    Plugin Author

    Posted 1 year ago #

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

  5. mirefoot
    Member
    Posted 1 year ago #

    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?

  6. mirefoot
    Member
    Posted 1 year ago #

    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;
    }
  7. Mikko Saari
    Member
    Plugin Author

    Posted 1 year ago #

    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?

  8. mirefoot
    Member
    Posted 1 year ago #

    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.

Topic Closed

This topic has been closed to new replies.

About this Plugin

  • Relevanssi - A Better Search
  • Frequently Asked Questions
  • Support Threads
  • Reviews

About this Topic

Tags