Sort search results with relevanssi_hits_filter

Here’s how you can sort your search results with relevanssi_hits_filter. It’s simple and a good way to give more attention to particular type of content. There are lots of possible ways to do this, I’m going to give some examples and hopefully you’ll be able to figure out how to do what it is you want to do.

Sorting by category

Here’s an actual example from one of my sites. It’s a board game site, with reviews, news, articles and so on. I wanted to make the reviews stand up. One way to do that would be to give extra weight to posts in that particular category, but since I can’t do that on the settings page, I’ll just go ahead and make sure the review posts float on top of the searches no matter what. Here’s what I added to the functions.php of my theme:

add_filter('relevanssi_hits_filter', 'reviews_first');
function reviews_first($hits) {
	$reviews = array();
	$everything_else = array();
	foreach ($hits[0] as $hit) {
		$review = false;
		foreach (get_the_category($hit->ID) as $cat) {
			if ($cat->cat_ID == 3) {
				$review = true;
				break;
			}
		}
		$review ? array_push($reviews, $hit) : array_push($everything_else, $hit);
	}
 
	$hits[0] = array_merge($reviews, $everything_else);
	return $hits;
}

First, create arrays to which the posts are sorted. Then, process the hits. For each post, go through all the categories for the post (I could do a shortcut here, as all my posts are in exactly one category, but it’s better to be thorough) and if the post is in the review category (which is category 3, and I really should use an obvious constant like REVIEW_CATEGORY here), it is marked as a review by setting the $review flag true.

Then, depending on the flag (which I did remember to set to false for each post to start with) the post goes either to $reviews or $everything_else. This kind of sorting automatically retains the original order of the posts, so the relevancy order isn’t badly messed up.

Then we just merge the arrays (in the correct order, mind you) and return the complete array. Done. When doing the array_merge(), make sure all arrays are actually arrays (so initialize them first). If there’s a NULL (for example when doing arrays by post_type, and one post_type is missing), the whole array_merge() will fail.

However, I want to really make the reviews stand out and while my search results template does show the category of the posts right after the post title, I want to add some headings. So, then I’ll take a look at my search results template.

$reviews = false;
if (have_posts()) : while (have_posts()) : the_post();
	foreach (get_the_category($post->ID) as $cat) {
		if (($post->post_type == 'page' || $cat->cat_ID != 3) && $reviews) {
			echo "<h3>Everything else</h3>";
			$reviews = false;
			break;
		}
		if ($cat->cat_ID == 3 && !$reviews) {
			echo "<h3>Reviews</h3>";
			$reviews = true;
			break;
		}
	}

Before the change, this part only had the usual have_posts() loop code. Now, I’ve added some new stuff. I start by setting a review flag to false.

If a post is in the category 3 (again, I should use the REVIEW_CATEGORY constant here, so if the review category somehow changes, I can change it in one place and spare myself lots of trouble) and the review flag is off, the review header is shown and the review flag is set to true.

If the review flag is set and we come across a post that is not in the category or a page (if the first result after the reviews is a page, it’ll still show the review category), then set the review flag to false and show the other header.

Sorting by post type

WP e-Commerce users like to get products first, then posts or pages. Here’s an example that sorts products first, then posts, then pages.

add_filter('relevanssi_hits_filter', 'products_first');
function products_first($hits) {
    $types = array();
 
    $types['page'] = array();
    $types['post'] = array();
    $types['product'] = array();
 
    // Split the post types in array $types
    if (!empty($hits)) {
        foreach ($hits[0] as $hit) {
            array_push($types[$hit->post_type], $hit);
        }
    }
 
    // Merge back to $hits in the desired order
    $hits[0] = array_merge($types['product'], $types['post'], $types['page']);
    return $hits;
}

Sorting by meta field or comment count

This function, provided by Max Hodges, will sort the results by meta field value (hidden meta field _likes) or by WordPress comment count, based on orderby query variable. This is a very good example of a more complicated sorting function.

add_filter('relevanssi_hits_filter', 'order_the_results');
function order_the_results($hits) {
    global $wp_query;
 
	switch ($wp_query->query_vars['orderby']) {
		case 'likes':
	        $likes = array();
    		foreach ($hits[0] as $hit) {
        		$likecount = get_post_meta($hit->ID, '_likes', 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 'comments':
		$comments = array();
		foreach ($hits[0] as $hit) {
			$commentcount = wp_count_comments($hit->ID)->total_comments;
			if (!isset($comments[$commentcount])) $comments[$commentcount] = array();
			array_push($comments[$commentcount], $hit);
		}
 
		if ($wp_query->query_vars['order'] == 'asc') {
			ksort($comments);
		} else {
			krsort($comments);
		}
 
		$sorted_hits = array();
		foreach ($comments as $commentcount => $year_hits) {
			$sorted_hits = array_merge($sorted_hits, $year_hits);
		}
		$hits[0] = $sorted_hits;
 
		break;
 
	case 'relevance':
		//do nothing
		break;
 
	 }
    return $hits;
}

Sorting by post title

Sorting by post title is really simple and doesn’t require using relevanssi_hits_filter:

add_filter('relevanssi_modify_wp_query', 'rlv_sort_by_title');
function rlv_sort_by_title($q) {
	$q->set('orderby', 'post_title');
	$q->set('order', 'asc');
	return $q;
}
  • Hi,

    Does the “Sorting by category” example works with the free version of the plugin?

    Thanks!

  • Yes, this works both in free and Premium.

    • Thanks, Mikko. I guess I did something wrong, since it’s not working. The only value I need to change is the category ID, right? I’ll try to figure it out.

      Cheers!

      • Yes. The code has some problems, if there are pages involved, by the way, but otherwise it should work as posted. Does it do anything?

  • Pingback: Anonymous()

  • Not really. I can’t see anything happening. I tested it with the same keywords, but I got the same results, no matter what category I picked. I’m going to double check, just in case. I’ll let you know.

    Thank you

    • Btw, there’s no pages involved. My settings tells Relevanssi to index posts only ๐Ÿ™‚

  • Rok

    Hello, i have a few more categories, and would like to make categories list in certain order. I tried with tweaking the code, it puts the four categories on top, but it mixes them up. I would like to display all posts from first category first, second category second and so on. Can somebody please help me tweak this code. Thank you.

    add_filter(‘relevanssi_hits_filter’, ‘reviews_first’);

    function reviews_first($hits) {

    $reviews = array();

    $everything_else = array();

    foreach ($hits[0] as $hit) {

    $review = false;

    foreach (get_the_category($hit->ID) as $cat) {

    if ($cat->cat_ID == 1811) {

    $review = true;

    break;

    }

    if ($cat->cat_ID == 1812) {

    $review = true;

    break;

    }

    if ($cat->cat_ID == 1813) {

    $review = true;

    break;

    }

    if ($cat->cat_ID == 1814) {

    $review = true;

    break;

    }

    }

    $review ? array_push($reviews, $hit) : array_push($everything_else, $hit);

    }

    $hits[0] = array_merge($reviews, $everything_else);

    return $hits;

    }

    • You need to put posts from each category to a separate array, then combine them in correct order. So, put the posts from the first category to array $first, second to array $second and so on, then combine them: array_merge($first, $second, $third, $fourth, $everything_else);

      • Rok

        Got it, it’s working now. Thank you 1000x

  • Hi there, i place the Max Hodges code in my function.php page but order don’t works.
    How can i order by custom field (tipologia)?
    Thanks

    • The code by Max Hodges does work, if you just changes “_likes” to “tipologia”, but it only activates with the correct value of orderby parameter. In the sample code, to order the results by the custom field, orderby needs to be set to “likes”.

      If you want the results always ordered by custom field, remove the whole switch {} structure and just keep the case “likes” part.

      • Poe

        Hi Mikko Saari, I replace the “_likes” with my custom field but the result is not change. As per your advise we need to set orderby need to be set to “likes”. Could you please advise where is the setting for this “orderby ” to be “like”. Thanks in advance.

        • Add this to your search form:

          • Poe

            Thanks for your replay. I had add

            to the search form.
            But the result is still the same. Could you please advise if i miss some more thing to add.

          • By the way โ€“ as a paying customer, you can use the customer support form. That provides faster, more reliable answers.

            Do you always want to order by the custom field? In that case you don’t even need to hidden input field: just use the part of the code between “case: ‘likes'” and “break”.

            Does that help?

          • Poe

            Thanks for your great support and plugin. It work. ๐Ÿ™‚

  • Nicole

    Hi Mikko,

    Your plugin is awesome – thank you very much for your help! I’ve been trying to adapt the code you gave above to work with woocommerce, to de-emphasise sold items. (I’d like them to still appear in the search results, but behind items currently for sale.) And I’m struggling – I thought it might be time to admit defeat and see if you had a second to look over my code and see what I’ve done wrong!

    I’ve currently got the below in my functions.php:

    add_filter(‘relevanssi_hits_filter’, ‘sold_last’);
    function sold_last($hits) {
    $solds = array();
    $everything_else = array();
    foreach ($hits[0] as $hit) {
    $sold = false;
    foreach (get_the_terms($hit->ID, ‘product_cat’) as $term) {
    if ($term->product_cat_ID == 807) {
    $sold = true;
    break;
    }
    }
    $sold ? array_push($solds, $hit) : array_push($everything_else, $hit);
    }

    $hits[0] = array_merge($everything_else, $solds);
    return $hits;
    }

    But it’s not affecting the order of the results. I know I’m doing something wrong, but I don’t know enough about this to be able to see what it is…

    Thank you very much for any help you can offer!

    Nicole

    • Nicole, this looks correct, except for this: if ($term->product_cat_ID == 807)

      Are you sure that’s the correct attribute?

      I’d debug this in these steps:

      1. Check the code is running and processing posts.
      2. Check that the code is noticing the sold posts.
      3. Check that the individual arrays contain what they should.

      • Nicole

        Thanks for getting back to me so quickly Mikko!

        No, I’m not at all sure that’s the right attribute – I’ve tried a couple of different variations, but realised eventually that I could quite easily try a million options and later find it was something else that was broken.

        I guessed based on your use of cat_ID in the original, and thought product_cat_ID would be the equivalent. (807 is definitely the category ID.) But if that’s not the right thing, at least I now know where the problem is and can try to find the right answer!

        As for your steps, the search returns results in line with the plugin settings, so I assume step 1 is working. It isn’t filtering out the sold items, so I suspect the problem is at step 2 – which would fit with me having used the wrong attribute to identify them. I shall work on it some more…

        Thanks again for your help!

        • The attribute is actually probably cat_ID, but it’s easy to check: just do a var_dump($term); and you’ll see all the attributes.

          • Nicole

            Fixed! Apparently I needed to use term_taxonomy_id instead of product_cat_id – it now works perfectly! Thank you so much for your help, I was pulling my hair out trying to make this work like I knew it should…

  • Nicole

    Hi Mikko,

    I’m really sorry to bother you again – but is there anything obvious you can think of that would mean that some search terms weren’t being recognised by relevanssi? (Or maybe aren’t being processed by relevanssi?)

    I’ll explain using an example, because I don’t know the right words to explain in abstract! My site sells jewellery – if I search, say “copper” or “chainmaille”, I get all the right results, in the order I wanted (with blog posts behind product listings) thanks to your helpful filter. Including necklace listings. But if I search “necklace” it comes up with no results, even if the listings that should have come up were picked up by another search term. So the product posts are clearly being indexed, just not found via all the tags, only some of them – any idea why/how I could fix it?

    If you need more info from me to make sensible suggestions, just shout. I don’t know if the above is at all enough to go on!

    Thanks again for all your help with this,

    Nicole

    • Is ‘necklace’ a stop word, by any chance? that’s the most common explanation for this kind of behaviour.

      • Nicole

        Sadly not, according to the settings page – and trial and error suggests there’s a few terms that aren’t being registered, even though they’re used as product tags (which are supposed to be indexed – and seem to be picked up on other searches).

        • Hard to say, then. I’d check the database to see if the word appears there. That would tell whether the problem is in indexing or in searching.

          • Nicole

            The words I’m searching for all seem to be in the database – it’s driving me
            mad, because I love everything about this plugin, and if I
            can’t sort this out, I won’t be able to use it. ๐Ÿ™

          • Well, if you had a Premium license, I could take a closer look at this.

          • Nicole

            Fair point, well made – I will buy one when money’s a tiny bit less tight, and then come back to you. I really do appreciate all your help so far, and I wasn’t expecting you to work in depth on something for free! (I was sort of hoping it was something obviously stupid that I’ve done that’s easily fixed; looks like it’s not.)

          • It still might be something simple, but I’d have to investigate before I could say for sure. The missing words are appearing in post content, right, and not just meta data like tags and categories?

          • Nicole

            Yep, in post content and title, as well as tags/categories.

            Sticking with the example of necklace, it’s picked up (and highlighted in the search results) with “chainmaille necklace”, and a search for chainmaille on its own works, but not necklace on its own. (There are other words that should have results that don’t, but that’s the one that’s bugging me most at the moment, since it’s one of my main product categories.)

          • Ok. That sounds very much like a stopword issue, hence my initial question, but if it’s not (and if the words appear in Relevanssi db table, it’s not), it’s hard to say.

          • Nicole

            I shall buy a premium licence as soon as possible! Thanks again for thinking about this!

  • jefffassnacht

    Hi Mikko,

    Thanks for the great plugin! When using the snippet above to sort by post type, I’m getting an error on the search result page. The error refers to the line array_push($types[$hit->post_type], $hit); and I believe is happening when it encounters a result type that hasn’t been explicitly defined in the $types array, such as $types[‘product’] = array(); How would I create a catch-all for any type not defined?

    • You can add this before the array_push():

      if (!is_array($types[$hit->post_type])) $types[$hit->post_type] = array();

      • jefffassnacht

        Thank you!

  • Hi Mikko,

    I’ve wrangled the above code ‘sorting by meta field’ to order my search results by meta value ‘start_date’.

    I modified the code slightly – and it’s working – but I was hoping you could take a quick look for errors. https://gist.github.com/aburi/02101531bf828749fbd0

    Thanks for all your help.
    Alex

  • AlexanderBog

    Hi!
    Please show an example of how to do woocommerce sorting by price (ascending – descending). How to make that as a result of the search is running this plugin https://wordpress.org/plugins/yith-woocommerce-ajax-navigation/ or standard. In the standard search this plugin works.

    • Hi,

      I don’t know how to do that, as I don’t know how WooCommerce stores the price information. That AJAX Navigation plugin will almost certainly not work with Relevanssi.

  • I’m trying to alphabetize search results based on a meta field “alphabetize”. But my attempt to modify Max’s script doesn’t work, and PHP complains about the closing bracket. Can you help me correct? I’ve purchased Premium:

    add_filter(‘relevanssi_hits_filter’, ‘order_the_results’);

    function order_the_results($hits) {

    global $wp_query;

    $alphabetize = array();

    foreach ($hits[0] as $hit) {

    $alphacount = get_post_meta($hit->ID, ‘alphabetize’, true);

    if (!isset($alphabetize[$alphacount])) $alphabetize[$alphacount] = array();

    array_push($alphabetize[$alphacount], $hit);

    }

    if ($wp_query->query_vars[‘order’] == ‘asc’) {

    ksort($alphabetize);

    } else {

    krsort($alphabetize);

    }

    $sorted_hits = array();

    $hits[0] = $sorted_hits;

    }

    return $hits;

    }

    • You actually have too many closing brackets in this code. Remove the one before “return $hits” and it should work better.

      • Thanks, Mikko. But the script itself isn’t returning any results. Without the function, Relevanssi returns results just fine, but chronologically. I need them sorted by the value in an added field called “alphabetize.”

      • Ah. I left out a bit. It’s working now. But what does this mean?

        foreach ($alphabetize as $alphavalue => $year_hits) {
        $sorted_hits = array_merge($sorted_hits, $year_hits);
        }

        I don’t want to limit hits to just the current year or something.

        • It’s just a name of the variable. Name it $alpha_hits if it bothers you =)

          • I’m almost there, Mikko, just one last question, thanks! I’m trying to integrate your post_type sorting script, but it throws a PHP error if one of the types has no hits. I’m sure this is super basic, but how do I add an “if” to the merge, so if there are no posts, for example, it doesn’t hiccup?

            add_filter(‘relevanssi_hits_filter’, ‘order_the_results’);

            function order_the_results($hits) {

            global $wp_query;

            $alphabetize = array();

            if (!empty($hits)) {

            foreach ($hits[0] as $hit) {

            $alphavalue = get_post_meta($hit->ID, ‘alphabetize’, true);

            if (!isset($alphabetize[$alphavalue])) $alphabetize[$alphavalue] = array();

            array_push($alphabetize[$alphavalue], $hit);

            }

            // sortby ascending

            ksort($alphabetize);

            $sorted_hits = array();

            foreach ($alphabetize as $alphavalue => $alpha_hits) {

            $sorted_hits = array_merge($sorted_hits, $alpha_hits);

            }

            $hits[0] = $sorted_hits;

            foreach ($hits[0] as $hit) {

            if (!is_array($types[$hit->post_type])) $types[$hit->post_type] = array();

            array_push($types[$hit->post_type], $hit);

            }

            // Merge back to $hits in the desired order

            $hits[0] = array_merge($types[‘project’], $types[‘post’]);

            }

            return $hits;

            }

          • Merging empty arrays shouldn’t be a problem, so it should be enough if you add

            $types[‘project’] = array();
            $types[‘post’] = array();

            somewhere before the loop.

          • That did it! THANK YOU SO MUCH! Here’s the pastebin if anyone else needs something similar: http://pastebin.com/jmjWZik1

  • Barbara House

    I currently have a need to filter the results of the search to remove certain custom taxonomy terms based on user role permissions. I’m thinking this hits filter could be the answer – basically do a “if logged in user has this permission, exclude these tax terms, else etc.” Does that sound like the best way to do this?

    • I’d use ‘relevanssi_modify_wp_query’ to set a tax_query depending on user permissions. That way you don’t have to spend resources on fetching and processing posts the user cannot see.

  • J_avila

    Hi, I’m trying to sort the search results by custom tax. It’s an doctors listing but I want to positioning an specific doctor, with an tax called “nivel” (with 3 different levels), inside of a custom post type called “medicos” I want to order the search results (lvl1, lvl2, lvl3) can you help me is kind of urgent.

    • See the example “Sorting by category”. Instead of get_the_category(), you can use get_the_terms() to get custom taxonomy terms.

  • Very weird. When I use the post_type bit of code, it returns the correct results but pooches my theme layout. Very weird. I update my functions file and boom, layout pooched. I remove it and save it and it’s all good again. Put the code back in, save it and boom, it’s pooched (but returns the correct results).

    I find what I need to show Woo Products first in my search results and I can’t get it to not break my theme. I’ve looked under the hood and find nothing wrong.

    What happens is that my main content area gets centered and my sidebar gets layered on top of the right edge of the content area and it’s about 50% of it’s normal size.

    I certainly don’t expect a fix, I’m just recording an odd behaviour in case anyone else has experienced it.

    • Broken divs in the excerpts, perhaps?

      • hadn’t considered that. Thanks, I’ll look into it. Don’t typically use div’s in the excerpts but my partner may have done something I didn’t catch

  • Marcelo Lewin

    I would like to group my search results by category ID. Is there an easy way to do this?

    • If easy means “no programming involved”, then no. But the programming involved is not particularly tricky. Anyway, you do have a support request about this in the works, and I’m working on it; it’s just Christmas and this one man company is currently on Christmas vacation.

  • Leo Kolt

    What could be the problem? I put both codes in the file functions.php to sort the results by category, but when you insert the second year (), stops responding server showing error “500”…

    • 500 error means some kind of generic error. A typing mistake, likely.

      • Leo Kolt

        I need to insert these two codes entirely for each other? Not one instead of another and replacing one code is part of another code, right?

        • Yes, for the first part; the first one to theme functions.php, the second to the search results template. The second one will replace some existing code.

          • Leo Kolt

            Please help! Here is my search.php. I inserted the code in different places, but the search page gives an error 500. where to insert your code

          • Leo Kolt

          • Leo Kolt

            the code is not correctly inserted. here is a link to all the code

            http://pastebin.com/NRkPjN00

          • You need to edit the blog style template, not that template.

          • Leo Kolt

            Oh, no. It have such a file search.php. This code completely from search.php

          • Yes, but the code that actually displays the search results comes from the blog style template, not from the search.php template.

          • Leo Kolt

            So where must I paste your second code?

          • I don’t know the exact name of the template. Also, with your theme, you can’t just paste it, you need to edit the template. If you don’t understand how, I suggest you get help from someone who understands WP templates and can do the necessary changes for you.

  • Leo Kolt

    thanks for the concern. I found the file where to insert the code. But now I have another problem. I made the entries in the search for the two categories and the Everything else. But the posts from “Everything else”, unfortunately, are shown on the search page twice. There is an option to disable it? This link – http://pastebin.com/WCx5funX

    • Sounds like the problem is in the relevanssi_hits_filter filter.

      • Leo Kolt

        Is it possible to fix it?

        • Yes; I mean the problem is in your relevanssi_hits_filter function code.

          • Leo Kolt

            Can see what’s wrong with her? Thank you! http://pastebin.com/AjwHCStL

          • You’re merging $everything_else twice. You can do it all at once like this:

            $hits[0] = array_merge($reviews, $releases, $everything_else);

          • Leo Kolt

            This not working ๐Ÿ™

          • Did you remove the second array_merge() line? How is it not working?

          • Leo Kolt

            Yes, removed. He mixes all the posts and the category after that, but leaves all the posts by two ((

          • Please show me the complete function again.

          • Leo Kolt
          • You had another hole in the logic, all posts were added to $everything_else. This should be correct: http://pastebin.com/CGgcV9iV

          • Leo Kolt

            Almost all the works! Thank you! Only now stopped working for a second code pattern . It does not show the title for releases (

            http://pastebin.com/h4j4vWsu

          • You have the three if blocks there, and they’re in wrong order. Move the first one last, then it should work.

          • Leo Kolt

            Oh thanks! Everything is working!!

  • Jim

    Looking for a way to sort the output simply by post title. Am a little confused at the moment on it

    • Add this to your theme functions.php:

      add_filter(‘relevanssi_modify_wp_query’, ‘rlv_sort_by_title’);
      function rlv_sort_by_title($q) {
      $q->set(‘orderby’, ‘post_title’);
      $q->set(‘order’, ‘asc’);
      return $q;
      }

      • Jim

        Thanks – that is brilliant – much appreciated
        I know this removes some of the relevance advantages of the search but this is for a large number of pdf’s and for this I only need the titles and a search on a custom field – thanks again

  • Julja

    firstly started to do sorting by myself, but just in time decided read more documentation about relevanssi!
    Thanks a lot for info!
    But, as you, probably , guess, i have some issue)
    Can you just look at my code and tell me is there something wrong?
    http://pastebin.com/tB5mwciF
    in html i try to sort with , where name&value – meta_key name

    php i know bad)
    Can you help me?

    • Nothing obviously wrong in your code.

      • Julja

        weird. Maybe i have wrong understanding how it should look in html?
        i have no select, it’s buttons

        1
        2
        3

        and the loop absolutely standard
        if (have_posts()) {while( have_posts()) :the_post();
        get_template_part(‘content-loop’, get_post_type());
        endwhile;}
        any suggestions?

        • Have you debugged this at all? What’s going on in the filter? Is it triggering? Where does it fail? Line-by-line debugging is often the best way to figure out the problem.

          • Julja

            Undefined index: orderby
            how is that possible?

          • Have you defined it? Does your search results page URL have a &orderby=value in it?

  • Linus

    I must be stupid? I can’t get a single filter to fire. I’m doing some stuff in the top of my search.php file in my theme, but where i do it should not matter?
    Copy/paste any of the examples and nothing happens.
    Example;
    add_filter(‘relevanssi_hits_filter’, ‘products_first’);
    function products_first($hits) { var_dump($hits); }
    Does completely nothing.
    function products_first($hits) { ?>console.log(‘Test’);<?php }
    same thing.
    Why?

    • Try theme functions.php, top of the search.php may be too late.

  • Jesper Georgsson

    Awesome plugin – but I cant seem to solve one last bit. I would like my woocommerce products to be sorted after stock. Highest stock first, lowest last. Is this possible by alter one of the above solutions?

    Thanks, Jesper.

    • Yes, I suppose so. This is probably more helpful starting place: https://www.relevanssi.com/knowledge-base/woocommerce-popularity-and-price-sorting/

      If the stock is stored in a custom field, then it’s just a question of replacing the custom field name with the correct one.

      • Jesper Georgsson

        Hmm, if I alter that code pretty hard, remove the first part and the if isset parts, I seem to get some kind of correct results. Although – it hides my zero stock products. These are just supposed to be at the bottom. Do you know how? ๐Ÿ™‚

        My code:
        add_filter(‘relevanssi_hits_filter’, ‘rlv_price_sort’);
        function rlv_price_sort($hits) {
        global $wp_query, $price_sort, $sales_sort;

        $prices = array();
        foreach ($hits[0] as $hit) {
        $price = get_post_meta($hit->ID, ‘_stock’, 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;

        return $hits;
        }

        • Might be a problem with that $prices[$price] where $price is 0.

          Try this, does this add the zero stock products?

          $price = get_post_meta($hit->ID, ‘_stock’, true);
          if ($price == 0) $price = 1;

          • Jesper Georgsson

            Seems like I got it working! Big thanks Mikko! ๐Ÿ™‚

  • Nick Thomas

    Just wanted to join everyone in congratulating you on a terrific plug-in. I have been using WPSearch, which you give a lot of credit to, but have now found yours and noticed a real difference in results!

    My question is – can I manually ‘pin’ specific products to the top of the search results? My client wants the results in alphabetical order, which I have done using your snippet, but then also wants specific products to be listed at the beginning of the results, over-riding the search data. They want to rank up to 20 products this way!

    • Sure, just move those pinned posts to the top of the $hits[0] array with relevanssi_hits_filter filter function.

      • Nick Thomas

        Thanks for the lightning-fast response! I’ve bought a Premium copy of the plug-in as I wanted to ask for a bit more help…

        I’m afraid that I have limited coding skills – mainly copy-and-paste into the functions.php. Could you send me an example of the complete code I need to ‘pin’ products to the top of searches.

        Do I need to set-up a custom class for for this? Presumably, I need to enter some information on the product entry to indicate the level of importance for hero products?

        Also, a minor point – I have tried a search for ‘Scaler’ and get the expected response. However, if I search for ‘Scalers’ (plural) the search returns the full details page of the one item which contains the word ‘Scalers’ (with the ‘s’). I’ve tried adding the synonym setting “scalers=scaler” but this hasn’t had any effect.

        Here’s the URL if you want to try the search for yourself – https://perfectionplus.com

        • Go to support page and send me a message with more details. Do you want to pin only those posts that naturally appear in the search results, or do you have a list of posts that always need to appear in the top?

          There are different methods to this. You can provide a list of post IDs. If you want to control this from the admin, the easiest way is to use a custom field. If the order is significant, a custom field with a ranking number (“1” for the first post, “2” for the second and so on) is fairly easy to do.

          Your site only has one result for the word “scalers”, and is probably set up to display the full product page when there’s only match – that’s fairly common. Consider that Relevanssi doesn’t understand anything about language – it doesn’t know “scaler” and “scalers” mean the same thing.

          See the Relevanssi settings page sidebar for instructions on enabling the simple English stemmer – that might help.

          • Nick Thomas

            Brilliant. I’ll check-out the English stemmer – I’m sure that will fix that issue.

            The products to pin are ones that naturally appear in the search – not specific products for every search. Can I use the existing ‘Menu Order’ field for this?

            If you need more info, let me know and I’ll open a thread on the Support page.

          • Menu order is slightly harder to access from the code, so a custom field would be preferable.

          • Nick Thomas

            Awesome! Just noticed the Relevanssi Post Controls at the bottom of the Product page – entering the right key phrase does exactly what I need! Woopee – no coding necessary! Still very glad I paid you a little to help support this terrific plugin.

  • Sorintje

    Hi,

    First of all I love when someone is creating art with programming! This plugin is amazing! It fixed a lot of my problems. Thank you!

    I still have one problem: want to sort the search results by post type, I used the code above and it does the job but it duplicates my posts: post, attachment, post

    This is the code I used:

    add_filter(‘relevanssi_hits_filter’, ‘show_the_posts_first’);
    function show_the_posts_first($hits) {
    $types = array();

    $types[‘attachment’] = array();
    $types[‘post’] = array();

    // Split the post types in array $types
    if (!empty($hits)) {
    foreach ($hits[0] as $hit) {
    array_push($types[$hit->post_type], $hit);
    }
    }

    // Merge back to $hits in the desired order
    $hits[0] = array_merge($types[‘post’] , $types[‘attachment’] );
    return $hits;
    }

    When I don’t use this filter, the search results are sorted: attachment, post
    and is not duplicated.
    When I use the filter above, I get: post, attachment, post
    What is strange is that the first posts have excerpts snippets and the last ones don’t.

    Thank you for your time!

    • That’s weird. The code seems correct to me. Have you checked what’s inside $types[‘post’] and $types[‘attachment’] before the merge? If $types[‘attachment’] contains also posts, I’d take a closer look at the loop to see what’s happening inside.

      If $types[‘attachment’] doesn’t have posts and the $hits[0] has the correct content after the merge, then the problem is caused by either some other filter that’s modifying the results, or your search results template.

      • Sorintje

        How can I check what’s inside $types[‘post’] and $types[‘attachment’] ?

        • Just add a

          var_dump($types[‘post’]);

          in the function and run a search.

          • Sorintje

            I checked, before the merge, $types[‘post’] has only posts inside and $types[‘attachment’] only attachments.

            The problems is from my search results template because is managed by The Grid plugin. When I use the theme template, the results are correct.

            I don’t know how The Grid Search Template is injecting extra posts if is using the wordpress native query.

            If I disable the sorting filter, I don’t see the posts 2 times

          • It may well be The Grid is simply not compatible with Relevanssi. It may be The Grid gets the first set of results from Relevanssi just fine, then when it loads more through Ajax, it uses the native query to get posts.

          • Sorintje

            Yep! You are right! It was the Ajax loader. Using pagination is working correctly.
            Need to find a way to fix the Ajax ๐Ÿ™‚

            You are so good at this! I feel the need to give a 5 star feedback for your plugin on wordpress.org

          • That would be appreciated! Thanks!

          • Sorintje

            Done ๐Ÿ™‚