2

Using the pre_get_posts hook, I'm trying to allow users to narrow down their search by limiting it to posts with certain (multiple) tags applied.

This is my hook and function:

add_filter('pre_get_posts', array($this, 'pre_get_posts'), 0);

function pre_get_posts( $query ) {
if ( !is_admin() && $query->is_search ) {
    $query->set( 'post_type', array( 'post', 'resource', 'initiative') );
    if (isset($_GET['tags'])) {
        $tax_query = array(
            array(
            'taxonomy' => 'post_tag',
            'field' => 'slug',
            'terms' => $_GET['tags'],
            'operator' => 'AND',
            )
        );
        $tax_query = new WP_Tax_Query($tax_query);
        $query->set('tax_query', $tax_query);
    }
}
return $query;

}

As you can see, I'm also expanding the search to include two custom post types. In the results of a search, the custom post types are added correctly and I can see them in the query that's generated, so I know that the hook and function are being called correctly. The post_tag part of the query is not added though.

The WP_Query Object's query_vars element correctly (I think) contains the tax_query, but the WP_Query Object contains its own tax_query which is empty, and the SQL in the request also doesn't have it. Here's a (slightly stripped-down) var_dump of the WP_Query Object:

WP_Query Object (
[query_vars] => Array
    (
        [s] => ecosystem

        [post_type] => Array
            (
                [0] => post
                [1] => resource
                [2] => initiative
            )

        [tax_query] => WP_Tax_Query Object
            (
                [queries] => Array
                    (
                        [0] => Array
                            (
                                [taxonomy] => post_tag
                                [terms] => Array
                                    (
                                        [0] => culture-change
                                        [1] => peace
                                    )

                                [include_children] => 1
                                [field] => slug
                                [operator] => AND
                            )

                    )

                [relation] => AND
            )
        [search_terms_count] => 1
        [search_terms] => Array
            (
                [0] => ecosystem
            )

        [search_orderby_title] => Array
            (
                [0] => jcgy_posts.post_title LIKE '%ecosystem%'
            )

        [order] => DESC
    )

[tax_query] => WP_Tax_Query Object
    (
        [queries] => Array
            (
            )

        [relation] => AND
    )

[query] => Array
    (
        [s] => ecosystem
    )

[request] => SELECT SQL_CALC_FOUND_ROWS DISTINCT jcgy_posts.* FROM jcgy_posts  LEFT JOIN jcgy_postmeta as jcgy_postmeta on jcgy_posts.ID = jcgy_postmeta.post_id AND jcgy_postmeta.meta_key = '_EventStartDate' WHERE 1=1  AND (((jcgy_posts.post_title LIKE '%ecosystem%') OR (jcgy_posts.post_content LIKE '%ecosystem%')))  AND jcgy_posts.post_type IN ('post', 'resource', 'initiative') AND (jcgy_posts.post_status = 'publish' OR jcgy_posts.post_author = 1 AND jcgy_posts.post_status = 'private')  ORDER BY jcgy_posts.post_title LIKE '%ecosystem%' DESC, post_date DESC LIMIT 0, 10

All the research I've done tells me that I've structured my addition to the query correctly, yet clearly something isn't working. I am tearing my hair out. Any ideas?

1 Answer 1

3

I did get the thing working, though I'm not entirely sure how.

I made two changes: Removed the "convert array to Tax_Query object" step (which I only put in because using an array wasn't working before) Added a direct assignment of the array to the $query object (rather than just using the set() method).

My final (working) function is:

function pre_get_posts( $query ) {
if ( !is_admin() && $query->is_search ) {

    if (isset($_GET['post_types'])) {
        $query->set( 'post_type', $_GET['post_types']);
    } else {
        $query->set( 'post_type', array( 'post', 'resource', 'initiative') );
    }
    if (isset($_GET['tags'])) {
        $tax_query = array(
            array(
            'taxonomy' => 'post_tag',
            'field' => 'slug',
            'terms' => $_GET['tags'],
            'operator' => 'AND',
            )
        );
        $query->set('tax_query', $tax_query); // do I need both of these lines?
        $query->tax_query = $tax_query;       // let's leave them both in for safety
    }
}
return $query;

}

2
  • Yeah, I don't think that WP_Tax_Query() is intended for that purpose. As far as I can tell, you can't pass a WP_Tax_Query() object in as parameter to a WP_Query--it just expects an array, as you have now. So that could be why it was being stripped. I've previously only used the WP_Tax_Query class to build actual SQL clauses. Pretty sure that's what it's used for internally.
    – MathSmath
    Commented Jun 24, 2014 at 22:13
  • Using this was giving me an error in /wp-includes/canonical.php. I found what appears to be the solution, $query->parse_tax_query( $tax_query );
    – Peter G
    Commented Nov 29, 2016 at 0:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.