• mauricionieto1994

    (@mauricionieto1994)


    Hello!

    Right now I am doing an implementation of ElasticSearch into my WordPress/WooCommerce site. I already configured my searches and the sync of product changes to alter the ElasticSearch information. But I am having issues trying to tie the ElasticSearch response to the product query of the frontend.

    What ElasticSearch does for me is, I send whatever string I want to search for, and then Elastic returns to me an array of (12) product IDs that match best with the query string (These products were previously sent and then constantly updated as the product changes). So in the end, I always end up with 12 product IDs.

    Then, on the frontend I have the Woocommerce searchbar, and I want to hook/filter this search so that instead of asking the database to search for whatever was typed there, go ask my external ElasticSearch service, and then search for those 12 specific IDs on my database and display them. This should theoretically reduce the searchtime because I am giving the query the specific IDs I need, and also give me more relevant results.

    I have so far tried two approaches:

    1) Use the ‘pre_get_posts’ filter
    I tried to use this filter by using the $query->set( 'post__in' , $a ); clause, where $a is the array of IDs I want, but I found two issues, One is that it still takes a long time because the search query is still sent through the query object, this pretty much beats the purpose of the fact that I gave the 12 IDs already to the query, it’s too slow. And also, I tried to use $query->is_main_query() so that no other query is affected, but even with this, the products on my sidebar gets affected too!

    The second approach is what I feel like, sometahing closer to what I need, but I’m having one issue with it:

    2) Use the ‘posts_clauses’ filter
    This filter allows me to filter out each SQL Clause (where,join,groupby,orderby, and so on.) so that I pretty much leave a query that asks for 12 IDs. This works great, the only issue that I have with this is that I have no way of knowing which Query is it I’m doing at any given time. I (again) tried to use the $query->is_main_query() , tried to use this in combination with the ‘pre_get_posts’ to add a param to the query so that I could use the global $wp_query; and see what query is running at the time. But no luck, the filter works, but it affects all the query searches on the screen I am at.

    As I said, this hook has exactly what I need, which is parse my own SQL Query I need from the server, with the IDs that ElasticSearch gives me. But I need a way to identify that I am affecting the main query of the frontend searchbar, and only that one!

    I am willing to try other approaches to hijack this query and give it 12 IDs, and I am also willing to elaborate further on the matter, since I’ve been stuck with this for a week now, and I am starting to lose hope.

    Thanks to anyone who read it all and hopefully someone could chime in to help?

Viewing 4 replies - 1 through 4 (of 4 total)
  • Moderator bcworkz

    (@bcworkz)

    There are not many ways to manage which queries your code would apply to. One is through distinctive properties of the WP_Query object. Often some combination of properties will identify the correct query.

    Another is to add your callback soon before the query is made through another action hook which only fires for your specific need. You’d need to dig through code that executes just prior to the target query to find a suitable hook. Your callback can remove itself from the action stack once it has made its changes so it would not affect any subsequent queries.

    Yet another is by checking various global or super-global properties like the referrer URL in $_SERVER. Or your search form could have an identifying hidden field whose presence in $_REQUEST would let you know the request’s main query is the one you want to alter.

    Thread Starter mauricionieto1994

    (@mauricionieto1994)

    @bcworkz Thank you for your reply.

    Just today I did try to add a hidden input field on the searchbar, but I couldn’t find it at least on the $wp_query global, so perhaps I should look into the $_REQUEST object instead.

    My issue is, wouldn’t the value on the $_REQUEST object persevere thorought the execution of the petition? Hence I’m in the same problem of not knowing if I am affecting the proper Query? Which would leave me having to check the priority of all the hooks I have to know that I affect only the main query?

    Thanks for taking the time to read my post.

    Moderator bcworkz

    (@bcworkz)

    If the petition involves a sequence of requests, then you’re right, it will not persist through subsequent requests without some extra effort. On the initial request you’d need to set the value in something more persistent like a session variable or cookie. Alternately, include it as a query string in the redirected URL for every step of the process.

    In any case, $_REQUEST values should be considered somewhat volatile. Any code can alter or unset any value. I prefer to copy such values to something less volatile like an object property ASAP in code execution.

    Form field values will not show up in query vars unless the field name is whitelisted as a legit query var through the “query_vars” filter.

    Thread Starter mauricionieto1994

    (@mauricionieto1994)

    @bcworkz Thank you for your help.

    I ended up making it work through my 1st method mentioned. I was able to properly identify the main query through the “pre_get_posts” filter.

    I defined the $query->set( 'post__in' , $a ); clause so I only get the IDs I want.

    Plus I unsetted some other vars to lighten the query, since ElasticSearch does the heavylifting for me.

    
    $query->set('meta_query' , []);
    $query->set('tax_query' , []);
    $query->set('meta_key' , []);
    $query->set('orderby' , '');
    unset($query->query_vars['s']);
    

    Then I rearanged the order (as to not defeat the purpose of ElasticSearch) so that the products showed up in the order I included them in the post__in clause with this:

    $query->set('orderby' , 'post__in');

    This entire implementation is quite finicky , requiring multiple filters to make it work, but it seems to be working so far.

    Thanks for your help.

Viewing 4 replies - 1 through 4 (of 4 total)
  • The topic ‘How to Hijack WordPress Query with ‘posts_clauses’ filter for example?’ is closed to new replies.