Question

I would like to show an archive of posts that have two taxonomy terms in common. So for example, I'd like to show all posts that have both the terms "sauce" and "cheese" in the custom food taxonomy.

The trick is that I'd like to do this using the url. The closest I've come is with:

example.com?food[]=sauce&food[]=cheese

Upon inspecting the $query from the pre_get_posts filter, I can see that:

WP_Tax_Query::__set_state(array(
   'queries' => 
  array (
    0 => 
    array (
      'taxonomy' => 'food',
      'terms' => 
      array (
        0 => 'sauce',
        1 => 'cheese',
      ),
      'field' => 'slug',
      'operator' => 'IN',
      'include_children' => true,
    ),
  ),

So then I change the operator to AND like so:

add_action('pre_get_posts', function($query) {

    $query->tax_query->queries[0]['operator'] = 'AND';

});

But my results are always including posts that have at least one term instead of posts that have all terms.

According to Query Monitor, the main query is as such (and you can see that it's looking for posts that have either of the two term IDs.

SELECT SQL_CALC_FOUND_ROWS wp_posts.ID
FROM wp_posts
LEFT JOIN wp_term_relationships
ON (wp_posts.ID = wp_term_relationships.object_id)
WHERE 1=1
AND ( wp_term_relationships.term_taxonomy_id IN (6,9) )

So, how can I formulate a url to get only posts with both taxonomy-terms?

Was it helpful?

Solution 2

When I registered my taxonomy, I left out the argument for 'rewrite', which then defaulted to true. So by default, WordPress wanted to rewrite the url as /food/whatever/. The tricky thing was that it did accept the format ?food=whatever , but wouldn't accept two different terms in that format when joined with a plus.

The solution was to specify the rewrite arg of register_taxonomy() like so:

register_taxonomy( 'food', 'post', [
   ...
   'rewrite' => [
      'slug' => 'filter',
      'with_front' => false,
   ],
   ...
]);

And then I can use /food/sauce+cheese like @jdm2112 and the docs specify.

OTHER TIPS

Looks like you can define the AND logical operator with the URL parameters, specifically adding the "+" between your terms like this: url?taxonomy=term1+term2

This will ensure that only posts containing all terms listed are returned.

Example: https://example.com/blog?food=sauce+cheese

[tax_query] => WP_Tax_Query Object
        (
        [queries] => Array
            (
                [0] => Array
                    (
                        [taxonomy] => food
                        [terms] => Array
                            (
                                [0] => sauce
                            )
                        [field] => slug
                        [operator] => IN
                        [include_children] => 1
                    )
                [1] => Array
                    (
                        [taxonomy] => food
                        [terms] => Array
                            (
                                [0] => cheese
                            )
                        [field] => slug
                        [operator] => IN
                        [include_children] => 1
                    )
            )
        [relation] => AND

Notice the relation is definitely AND between the terms.

In local testing, I can confirm the returned posts are only those that contain BOTH terms.

Licensed under: CC-BY-SA with attribution
Not affiliated with wordpress.stackexchange
scroll top