Your problem is that you are not resetting all the needed query variables, like WP_Query::$is_page
, WP_Query::$is_single
and WP_Query::$is_archive
.
Also note that 'pre_get_posts'
is fired for all queries, the main and the secondaries, so you should check that you are working on the main query.
Finally, when you get data from $_GET
you should sanitize it before to use it, a good way is to use filter_input()
or filter_input_array()
.
Your method should appear something like this:
public static function pre_get_posts($query)
{
$data = filter_input_array(INPUT_GET, array(
'tag-search' => FILTER_SANITIZE_STRING,
'terms' => FILTER_SANITIZE_STRING,
'method' => FILTER_SANITIZE_STRING,
));
if( $query->is_main_query() && !empty($data['tag-search']) && !empty($data['terms']) ) {
$query->init(); // this resets ALL vars
$query->is_search = true;
// set tax query array
$tax_query = array(
'taxonomy' => $data['tag-search'],
'field' => 'slug',
'terms' => explode(',', $data['terms']),
);
// is AND method?
if( strtolower( $data['method'] ) === 'and' ) {
$tax_query['operator'] = 'AND';
}
// set tax query
$query->set( 'tax_query', array($tax_query) );
}
}
Doing so you do not need to filter the template (so you can remove your template_redirect()
method): search.php
will be loaded by WordPress because it will correctly recognize the query as a search.
PS: 'pre_get_post'
is an action, not a filter, so you don’t need to return the query neither if you modify it.