Posted on

Using the relevanssi_where hook

If you want to add extra filters to the search results, you can add them using a hook. Relevanssi searches for results in the _relevanssi table, where terms and post_ids are listed. The various filtering methods work by listing either allowed or forbidden post ids in the query WHERE clause. Using the relevanssi_where hook you can add your own restrictions to the WHERE clause.

These restrictions must be in the general format of

AND doc IN (' . {a list of post ids, which could be a subquery} . ')

For more details, check the source code where the filter is applied in the relevanssi_search()function. This is stricly an advanced hacker option for the kind of people who’re used to using filters and MySQL WHERE clauses and it is possible to break the search results completely by doing something wrong here.

 

  • Lore

    Could you post a sample of this code?

    I am trying to search only in specified custom fields, not in the entirety of the posts. So for example, if you’re on a scholarly site and you want to search only in the custom field ‘Theorems’, and you do not want to search in the custom field ‘References’, both of which are present in all posts, how would you do this?

    I tried the hits filter and meta_query. Perhaps a sample of the ‘where’ hook would be helpful. Thanks!

    • Search like this:

      http://www.example.com/?s=term1&customfield_key=Theorems&customfield_value=term2

      would return all posts with “term1” anywhere in them and “term2” in the custom field “Theorems”. This only works for one custom field at the time, and you can’t search for multiple terms at the same time, but that’s the easiest solution.

      However, I have a better solution for you.

      add_filter('relevanssi_match', 'cfdetail');
      function cfdetail($match) {
              $cf = unserialize($match->customfield_detail);
              if ($cf) {
                  if (!in_array('Theorems', array_keys($cf))) {
                      $match->weight = 0;
                  }
              }
              else {
                      $match->weight = 0;
              }
      	return $match;
      }

      This function sets the weight to 0 for all search terms that are not found in the Theorems custom field. Clean solution, I’d say.

      • Lore

        I am still working on this.
        I looked in the database for customfield_detail. Is this supposed to be the listing of all custom fields in which this search term appears? If so, I may have a problem.

        I checked a couple of search terms which both exist in 3 custom fields, but it says:
        a:2:{s:11:”meta_inputs”;i:1;s:12:”meta_special”;i:1;}
        I rebuilt the index just to be sure. In one case the search term was in three fields on one post. In the other it was all by itself in a custom field that’s not listed in its customfield_detail entry.

        Have I misunderstood?
        Thanks.

        • Yes, you’ve understood it right. If the term appears in three custom fields, the customfield_detail column should list all three.

  • Lore

    It doesn’t appear as it should.
    I’ll check and recheck that tonight.

    The information is in the database because it appears just fine when Posts are displayed. I’ve rebuilt the index. Is it a bug? Would a copy of my database or access to my installation help?

    PS- Your script (above) works nicely. I was still working on modifying it to my needs when I found this issue that’s messing with results.

    Thanks!

    • Curious… And you’re sure you’ve listed all those custom fields to be indexed? Or are you using the “all” or “visible” setting? If the settings are correct, then sorting this out will require closer debugging.

      • Lore

        I have set ‘Custom Fields to Index’:
        meta_results, meta_inputs, meta_purpose, meta_special, meta_references
        Exactly like that with no quotes, although there appeared to be a tab space before the last one. I will reindex and test it again now in case that tab-space was the issue, although I’m pretty sure your code strips the whitespaces and stuff so I doubt it’s that.
        How does debugging work? Can I help?

  • Lore

    OK, tested again:
    I looked at ‘sampling’ in database:
    a:2:{s:11:”meta_inputs”;i:1;s:12:”meta_special”;i:1;}
    I searched on ‘sampling’ and got:
    1. A post where it exists in Inputs and Special.
    2. A post where it exists in the title only.
    3. A post where it exists in the References only.

    I looked at ‘schedule in db:
    a:2:{s:12:”meta_results”;i:1;s:12:”meta_purpose”;i:1;}
    Search results:
    1. A page in which schedule exists in both Results and Purpose.
    (First 5 results same, exists in both fields.)
    6. Exists in Results, Inputs, Purpose.
    7. Exists in Purpose only.
    8. Exists only in Special only.

    Search on ‘new’:
    a:2:{s:12:”meta_special”;i:1;s:15:”meta_references”;i:1;}
    1. Exists in title, Results and Purpose.
    2-3. Exists in References only.
    4. Exists in 4/5 fields.

  • For “sampling”, you should actually find three rows in the Relevanssi database, one for each post where the search term appears. The line here matches the post 1, but you should also have a line with the meta_references mentioned in the customfield_detail column. Is there one?

    Based on the sample lines, it would seem to me that all five custom fields are being indexed.

  • Lore

    Confirmed — There’s no bug, good. 🙂
    Still working on the function!

  • amccaleb

    Hi there – I love your plugin! I am looking to filter my search results by post-meta data – specifically, a number of my posts will have this:

    _Original Post ID

    and I would want to filter them out of the search results (always) so that they do not appear (these posts are duplicates of previously posted content). I have looked into your filters and hooks but am not quite sure how I might implement this.

    There are two logic statements that could determine whether to display a post in the search result: either [if post has _Original Post ID] or [if _Original Post ID !>0] then we would display that post.

    I am slowly getting the hang of this wordpress stuff and would greatly appreciate the guidance!

    • This is how you filter by meta field: https://codex.wordpress.org/Class_Reference/WP_Query#Custom_Field_Parameters

      Relevanssi supports these methods.

      • amccaleb

        Thanks for that. I have been plugging away at this but I am not sure I am formatting things correctly for the pluggin.

        Do you have an example of the relecanssi_where hook fully implemented using the AND doc IN (‘ . {a list of post ids, which could be a subquery} . ‘)

        Here is my code:

        ‘color’, ‘meta_value’ => ‘blue’, ‘meta_compare’ => ‘!=’ ) );
        $match .= ” AND doc IN ($query)”;
        return $match;
        }
        ?>

        Thanks!

      • Guest

        I believe I was a bit off on that last one, but I think I found a solution: (if you know a more efficient way to achieve this, please share! my search results “flicker” as the restriction is added)

        ‘_Original Post ID’,
        ‘meta_value’ => ‘null’,
        ‘meta_compare’ => ‘!=’
        );

        $query = new WP_Query( $args );
        $temp = array();

        while ( $query->have_posts() ) : $query->the_post();
        $temp[] = get_the_ID() ;
        endwhile;

        $meta_check_query = implode(‘,’, $temp);
        $query_restrictions .= ” AND doc NOT IN ($meta_check_query)”;
        return $query_restrictions;
        }
        ?>

      • Guest

        I believe I was a bit off on that last one, but I think I found a solution: (if you know a more efficient way to achieve this, please share! my search results “flicker” as the restriction is added)

        ‘null’,
        ‘meta_compare’ => ‘!=’
        );

        $query = new WP_Query( $args );
        $temp = array();

        while ( $query->have_posts() ) : $query->the_post();
        $temp[] = get_the_ID() ;
        endwhile;

        $meta_check_query = implode(‘,’, $temp);
        $query_restrictions .= ” AND doc NOT IN ($meta_check_query)”;
        return $query_restrictions;
        }
        ?>

  • amccaleb

    I apologize, I don’t know why it keep cutting off the code (I treid deleting the bad messages) If you know a more efficient way to solve this problem, please let me know! My search results “flicker” each time as it computes the restrictions.

    ‘_Original Post ID’,’meta_value’ => ‘null’,’meta_compare’ => ‘!=’);

    $query = new WP_Query( $args );
    $temp = array();
    while ( $query->have_posts() ) : $query->the_post();
    $temp[] = get_the_ID() ;
    endwhile;

    $meta_check_query = implode(‘,’, $temp);
    $query_restrictions .= ” AND doc NOT IN ($meta_check_query)”;
    return $query_restrictions;}
    ?>

    • Send me the code to mikko @ mikkosaari.fi or put it in a Pastebin, because the comment system mangles it.

  • Guest 1

    Does the relevanssi support ajax filter ?

    • What exactly do you mean?

      • Guest 1

        I want to integrate between relevanssi and another ajax filter plugin.
        I think this function “relevanssi_do_query” may help me.

        • Yes, that’s the way to go.

          • Guest 1

            Thanks

          • Guest 1

            when i use relevanssi_do_query function, does the did you mean functionality take this function operation in it’s count?

          • The did you mean functionality has nothing to do with this; it’s based on query logs (which any invocation of relevanssi_do_query() involves) in the free version and the index content in the Premium.

          • Guest 1

            Ok, thanks alot.