‘posts_where’ filter not applying ‘WP_Query’ in `wp_ajax`

I have a function which adds a posts_join and a posts_where to searches in WP_Query. It works fine on a normal, php rendered search page. However i’m also using it for a ajax product search and the additional posts_join and a posts_where don’t seem to apply.

Here’s the join and where:

function search_by_meta_join($join) {
    global $wpdb;

    if (is_search()) {
        $join .= " LEFT JOIN {$wpdb->postmeta} pm_ean ON {$wpdb->posts}.ID = pm_ean.post_id AND (pm_ean.meta_key = 'ean') ";
        $join .= " LEFT JOIN {$wpdb->postmeta} pm_code ON {$wpdb->posts}.ID = pm_code.post_id AND (pm_code.meta_key = 'product_code') ";
    }

    return $join;
}
add_filter('posts_join', 'search_by_meta_join');

function search_by_meta_where($where) {
    global $wpdb;

    if (is_search()) {
        $where = preg_replace(
            "/\(\s*{$wpdb->posts}.post_title\s+LIKE\s*(\'[^\']+\')\s*\)/",
            "({$wpdb->posts}.post_title LIKE $1) OR (pm_ean.meta_value LIKE $1) OR (pm_code.meta_value LIKE $1) ", $where
        );
    }

    return $where;
}
add_filter('posts_where', 'search_by_meta_where');

And here’s my ajax function:

    $args = array(
      'posts_per_page' => 12,
      'post_type' => 'product',
//      'offset' => filter_var($_GET['offset'], FILTER_SANITIZE_NUMBER_INT),
//      'post_status' => 'publish',
//      'order' => 'ASC',
//      'orderby' => 'title',
    );

    // Search query
    if (isset($_GET['searchQuery']) && $_GET['searchQuery'] != '') {
        $args['s'] = filter_var($_GET['searchQuery'], FILTER_SANITIZE_STRING);
    }

    // Category filter
//    if (isset($_GET['category']) && $_GET['category'] !== 0) {
//        $args['tax_query'][] = [
//            'taxonomy' => 'product-category',
//            'field' => 'term_id',
//            'terms' => filter_var($_GET['category'], FILTER_SANITIZE_NUMBER_INT),
//        ];
//    }

    $loop = new WP_Query($args);
    $products = array();

As I say it works on a normal search page like so:

global $query_string;

wp_parse_str($query_string, $search_query);

$search = new WP_Query($search_query);

Am I missing something for the ajax function to use it?

2 Answers
2

is_search() is only true if the main query is for the search results. When you create your own query with new WP_Query, you’re not using the main query. Additionally, AJAX requests do not even have a main query, so functions like is_search(), is_archive() etc. do not work.

If you want to check if a specific query is a search, you should use the is_search() method of the query, like this:

$query->is_search();

The posts_join and posts_where filters are applied to all queries, but the callbacks to those filters receive the current query object as an argument, and you can use this to check for any search queries so that you can apply your filter:

function search_by_meta_join( $join, $query ) { // <-- Note the additional argument.
    global $wpdb;

    if ( $query->is_search() ) { // <-- Note that we are checking the current query, not the main query.
    }

    return $join;
}
add_filter('posts_join', 'search_by_meta_join', 10, 2 ); // <-- Note the '2' which indicates we're accepting 2 arguments.

function search_by_meta_where( $where, $query ) { // <-- Note the additional argument.
    global $wpdb;

    if ( $query->is_search() ) { // <-- Note that we are checking the current query, not the main query.

    }

    return $where;
}
add_filter( 'posts_where', 'search_by_meta_where', 10, 2 );// <-- Note the '2' which indicates we're accepting 2 arguments.

The same principle applies whenever you’re filtering pre_get_posts as well. You should always use the query object that’s passed to the filter to check these things, otherwise your changes will apply to all queries on the search page, including menus, widgets, and secondary queries, not just the specific search query.

Leave a Comment