One of the new things in 3.1 that hasn’t got a lot of discussion yet is the new Advanced Taxonomy Queries mechanism. At the moment, this is still being actively developed, but the basic structure is finalized enough to give at least a semi-coherent explanation on how to use it. Since 3.1 is now going into beta, it’s unlikely to change much.

What’s a Query?

In WordPress land, a “query” is anything that gets Posts. There’s a lot of ways to do this.

  • You can use query_posts to modify the main query of the page being displayed.
  • You can create a new WP_Query, to get some set of posts to display in its own custom Loop.
  • You can do a get_posts to get some limited set of posts for display in some special way.

Regardless of the method, you have to pass parameters to it in order to specify which posts you want. If you’ve used this at all before, then you’ve used parameters like cat=123, or tag=example, or category_name=bob and so forth. When custom taxonomies were developed, you were eventually able to specify things like taxonomy=foo and term=bar and so on.

Querying for Posts

The problem with these is that people sometimes want to specify more than one of these parameters, and not all parameters worked well together. Things like cat=a and tag=b, or cat=a and tag is not b, and so forth. This is because cat and tag are both forms of taxonomies, and the code didn’t handle that well. Sure, some of it worked, for specific cases, but those were mostly there by accident rather than by design. In other words, those cases worked because the system just happened to get it right for that particular instance.

Well, all these old methods still work, but they have been made into a more comprehensive system of generically specifying arbitrary taxonomies to match against. When you specify cat=123, it’ll actually be converting it to this new method internally.

Query Strings are for Suckers

One side effect of this new system is that it doesn’t really work with query strings very well. It can be done, but it’s a lot easier and more sensible if you just start getting into the array method of doing things instead. What’s the array method? I’ll explain:

Imagine you used to have a query that looked like this:

query_posts('cat=123&author=456');

A simple query, really. The problem with it is that WordPress has to parse that query before it can use it. But there is another way to write that query as well:

query_posts(array(
  'cat' => 123,
  'author' => 456,
) );

Essentially, you separate out each individual item into its own element in an array. This actually saves you some time in the query because it doesn’t have to parse it (there’s very little savings though).

The advantage of this is that you can build your arrays using any method of array handling you like. Here’s another way to do it:

$myquery['cat'] = 123;
$myquery['author'] = 456;
query_posts($myquery);

Simple, no? But what if you have to deal with the $query_string? The $query_string is that old variable that is built by WordPress. It comes from the “default” query for whatever page you happen to be on. One of the main uses for it was to deal with “paging”. A common method of doing it was like this:

query_posts($query_string . '&cat=123&author=456');

If you use arrays, you have to deal with that yourself a bit. There’s a couple of possible ways to do it. The easiest is probably to just parse the query string yourself, then modify the result as you see fit. For example:

$myquery = wp_parse_args($query_string);
$myquery['cat'] = 123;
$myquery['author'] = 456;
query_posts($myquery);

I started out with the $query_string, used wp_parse_args to turn it into an array, then overwrote the bits I wanted to change and performed the query. This is a handy technique I’m sure a lot of people will end up using.

On to Advanced Taxonomies

Advanced Taxonomy queries use a new parameter to the query functions called “tax_query”. The tax_query is an array of arrays, with each array describing what you want it to match on.

Let’s lead by example. We want to get everything in the category of “foo” AND a tag of “bar”. Here’s our query:

$myquery['tax_query'] = array(
	array(
		'taxonomy' => 'category',
		'terms' => array('foo'),
		'field' => 'slug',
	),
	array(
		'taxonomy' => 'post_tag',
		'terms' => array('bar'),
		'field' => 'slug',
	),
);
query_posts($myquery);

Here we’ve specified two arrays, each of which describes the taxonomy and terms we want to match it against. It’ll match against both of them, and only return the results where both are true.

There’s two things of note here:

First is that the “field” is the particular field we want to match. In this case, we have the slugs we want, so we used “slug”. You could also use “term_id” if you had the ID numbers of the terms you wanted.

Second is that the “terms” is an array in itself. It doesn’t actually have to be, for this case, as we only have one term in each, but I did it this way to illustrate that we can match against multiple terms for each taxonomy. If I used array(‘bar1′,’bar2′) for the post_tag taxonomy, then I’d get anything with a category of foo AND a tag of bar1 OR bar2.

And that second item illustrates an important point as well. The matches here are actually done using the “IN” operator. So the result is always equivalent to an “include” when using multiple terms in a single taxonomy. We can actually change that to an “exclude”, however, using the “operator” parameter:

$myquery['tax_query'] = array(
	array(
		'taxonomy' => 'category',
		'terms' => array('foo', 'bar'),
		'field' => 'slug',
		'operator' => 'NOT IN',
	),
);
query_posts($myquery);

The above query will get any post that is NOT in either the “foo” or “bar” category.

But what about terms across multiple taxonomies? So far we’ve only seen those being AND’d together. Well, the “relation” parameter takes care of that:

$myquery['tax_query'] = array(
	'relation' => 'OR',
	array(
		'taxonomy' => 'category',
		'terms' => array('foo'),
		'field' => 'slug',
	),
	array(
		'taxonomy' => 'post_tag',
		'terms' => array('bar'),
		'field' => 'slug',
	),
);
query_posts($myquery);

This gets us anything with a category of foo OR a tag of bar. Note that the relation is global to the query, so it appears outside the arrays in the tax_query, but still in the tax_query array itself. For clarity, I recommend always putting it first.

Useful Gallery Example

By combining these in different ways, you can make complex queries. What’s more, you can use it with any taxonomy you like. Here’s one I recently used:

$galleryquery = wp_parse_args($query_string);
$galleryquery['tax_query'] = array(
	'relation' => 'OR',
	array(
		'taxonomy' => 'post_format',
		'terms' => array('post-format-gallery'),
		'field' => 'slug',
	),
	array(
		'taxonomy' => 'category',
		'terms' => array('gallery'),
		'field' => 'slug',
	),
);
query_posts($galleryquery);

This gets any posts in either the gallery category OR that have a gallery post-format. Handy for making a gallery page template. I used the wp_parse_args($query_string) trick to make it able to handle paging properly, among other things.

Speed Concerns

Advanced taxonomy queries are cool, but be aware that complex queries are going to be slower. Not much slower, since the code does attempt to do things smartly, but each taxonomy you add is the equivalent of adding a JOIN. While the relevant tables are indexed, joins are still slower than non-joins. So it won’t always be a good idea to build out highly complex queries.

Still, it’s better than rolling your own complicated code to get a lot of things you don’t need and then parsing them out yourself. A whole lot easier too.

Shortlink:

182 Comments

  1. Is there a way to query for posts in either two taxonomy terms while also excluding from two categories? By setting the “relation” to “OR” the query being returned is:

    WHERE 1=1
    AND ( wp_term_relationships.term_taxonomy_id IN (74) OR tt1.term_taxonomy_id IN (92) OR wp_posts.ID NOT IN (
    SELECT object_id
    FROM wp_term_relationships
    WHERE term_taxonomy_id IN (36,37)
    ) )

    • So you want it to be in either of two tags, but not in either of two categories?

      
      $myquery['tax_query'] = array(
      	'relation' => 'AND',
      	array(
      		'taxonomy' => 'category',
      		'terms' => array('cat1', 'cat2'),
      		'field' => 'slug',
      		'operator' => 'NOT IN',
      	),
      	array(
      		'taxonomy' => 'post_tag',
      		'terms' => array('tag1', 'tag2'),
      		'field' => 'slug',
      		'operator' => 'IN',
      	),
      );
      
      • Wow, thanks for the fast response!

        More along the lines of the:

        $myquery['tax_query'] = array(
        	'relation' => 'AND',
        	array(
        		'taxonomy' => 'category',
        		'terms' => array('36', '37'),
        		'field' => 'slug',
        		'operator' => 'NOT IN',
        	),
        	array(
        		'taxonomy' => 'department',
        		'terms' => array('food-and-beverage'),
        		'field' => 'slug',
        		'operator' => 'IN',
        	),
        	array(
        		'taxonomy' => 'topic',
        		'terms' => array('best-practice'),
        		'field' => 'slug',
        		'operator' => 'IN',
        	),	
        );
        
        • Where it’s excluding all posts in either category, while including posts in either the “department” taxonomy with a term of ‘food and beverage’ or the “topic” taxonomy with a term of ‘best practice’.

          The category exclusion is being called globally on the pre_get_posts filter whereas the tax query is being applied on a page where a user has chosen these two (or more) terms from these two (or more) taxonomies.

          • No, that won’t work. What you’ve done here is to require the post to be in both the food-and-beverage department AND in the best-practice topic.

            You can’t combine and’s and or’s like that. The query system doesn’t allow for queries that complex. All separate taxonomies must be a combined set of solely AND or solely OR. In individual taxonomies, the use of IN and NOT IN can be used to simulate different sets though.

            In other words, you cannot use parentheses. There is no way to create a tax_query which says tax1=A AND (tax2=B OR tax3=C).

  2. […] The Codex has a good article that introduces taxonomy queries. Otto has also published a great tutorial to cover the fundamentals of running advanced taxonomy queries. […]

  3. Hey,

    This is really helpful but I must be missing something. Codex confused me further. I’ve got this code:

    <?php
    	
    	
    
    // The Query
    $the_query = new WP_Query( $args = array(
    	'tax_query' => array(
    		'relation' => 'OR',
    		array(
    			'taxonomy' => 'category',
    			'field' => 'slug',
    			'terms' => array( '1424' )
    		),
    		array(
    			'taxonomy' => 'post_format',
    			'field' => 'slug',
    			'terms' => array( 'artist' )
    		)
    	)
    );
    $query = new WP_Query( $args );
    
    // The Loop
    while ( $the_query->have_posts() ) : $the_query->the_post();
    	echo '<li>';
    	the_title();
    	echo '</li>';
    endwhile;
    
    // Reset Post Data
    wp_reset_postdata();
    
    ?>	
    

    I want to display all posts in the ‘Discography’ category which match the Artist taxonomy. You can see an example of what I mean here: http://plastik.me/artist/summer-camp-2/

    So far I’ve managed to display posts in the discography category, but the second ‘Albums by this artist’ link doesn’t belong to that Artist.

    I’ve probably made some simple error but all of the queries I’ve tried thus far have caused fatal errors.

    Any ideas?
    Thanks in advance.
    Marc

  4. […] to Otto‘s excellent post on advanced taxonomy queries, I (mostly) understand how to create multi-taxonomy and multi-term queries. However, what I […]

  5. Hi Otto,

    Currently, I have a site where I have added a custom meta field to my “Categories” tag, to display whether or not this category should be a “featured” category on the homepage. I have the meta saving properly, but I am having a lot of trouble coming up with a query to grab all of my “featured” categories. Surely, I could write a simple “SELECT FROM” type of query, but I’m trying to avoid things like this (on principle alone, I feel what I’m trying to do should be very possible).

    Do you have any hints you may be able to help me out with?

    Thanks,

    –d

  6. I want to get all posts that matches ALL the given terms (by term id) in a custom taxonomy, but I can’t get it to work.

    If I set he operator to IN it returns all posts that matches ANY of the terms 8as expected), but if I set it to AND I can’t get it to return any posts (not even if I only give one term to match.

    what’s wrong with this code?:


    'tax_query' => array(
    array(
    'taxonomy' => 'movies',
    'field' => 'id',
    'terms' => array(65,67),
    'operator' => 'AND'
    )
    )

  7. I want to get all posts that matches ALL the given terms (by term id) in a custom taxonomy, but I can’t get it to work.

    If I set he operator to IN it returns all posts that matches ANY of the terms (as expected), but if I set it to AND I can’t get it to return any posts (not even if I only give one term to match.

    what’s wrong with this code?:

    'tax_query' => array(
      array(
        'taxonomy'	=> 'movies',
        'field'	 => 'id',
        'terms'	 => array(65,67),
        'operator' => 'AND'
      )
    )
    
    • i placed “term_id” in place of “id” and it worked for me. i.e

      'tax_query' => array(
      array(
      'taxonomy' => 'movies',
      'field' => 'term_id',
      'terms' => array(65,67),
      'operator' => 'AND'
      )
      )

      And thanks for your post it helped me to checks multiple condition.

  8. I have it working using the relation parameter like this:

    'tax_query' => array(
    
      'relation' => 'AND',
    
      array(
        'taxonomy'	=> 'movies',
        'field'	 => 'id',
        'terms'	 => array(65)
      ),
    
      array(
        'taxonomy'	=> 'movies',
        'field'	 => 'id',
        'terms'	 => array(67)
      )
    
    )
    

    But how is the ‘operator’ parameter supposed to work?

  9. […] have a pretty good understanding of the query function, thanks to the posts by Otto and Scribu. The problem is I’m struggling to figure out how to pass the variables in via a […]

  10. okay, something slightly more complicated.

    In my feed I’d like to have:
    1.) All posts in category “planet-site”
    2.) All posts with tags (‘linux’ AND ‘ubuntu’)
    3.) All posts with tags (‘linux’ AND ‘coding’)
    4.) All posts with tags (‘ubuntu’ AND ‘coding’)
    etc.…

    Any ideas how to accomplish this? Thanks in advance!

  11. Worked absolutely beautifully for me. Very well written and easily understandable. I was able to perform a search with three taxonomy criteria in play, and I didn’t have to edit a thing.

    The only mistake I made was typing my taxonomy in singular, when it should have been in plural form. My own bad!

    Thanks a million for this!

  12. Thank you very much for a very useful post. By the way I find myself stuck in another situation that’s not mentioned in this post.
    Consider that I have a taxonomy called “author” with about 8 post type called “post-type-1″, “post-type-2″, … “post-type-8″.
    I’m using this code to get all the posts from the taxonomy “author”:

    $args = array(‘post_type’ => array(‘post-type-1′,’post-type-2′,’post-type-3′,’post-type-4′,’post-type-5′,’post-type-6′,’post-type-7′,’post-type-8′));
    $news = new WP_Query($args);

    Of course my code works perfectly, but I find it very stupid from calling all the post-type in the same taxonomy at once. I’m looking for a better way of calling posts in a designated taxonomy (except the default “category”). Can any help me on this? Thank you.

  13. […] 3.1 introduced some awesome new taxonomy query features, and the URL parsing allows some rudimentary syntax to query multiple terms and choose if the query […]

  14. Thank you very much for your post. I’m just beginning with WordPress so i have maybe a stupid question :
    I understood everything to get all posts of a term from a taxonomy. But how can i do, to get only the last one of it and not all posts ? (This post will be shown on the home)
    I’ve got this :

    <?php 
    				$myquery['tax_query'] = array(
       				 array(
    			  'taxonomy' => 'types',
          		  'terms' => array('must-see'),
    			  'field' => 'slug',
    			  'showposts' => 1,
    				),
    				);
    				query_posts($myquery);
    while ( have_posts() ) : the_post(); ?> 

    I tried with “showposts” but it doesn’t work.
    And my last question is the same kind of thing. How should i write to have the same result than “showposts=3&offset=1″ ?

    I hope my english is ok sorry :)

  15. Great article, helped me out a lot!

    Question though:

    Ive created a custom post type and managed to generate a list of two custom taxonomie + the terms with checkboxes (to create a sort of filter).
    When checked and submitted the browsers url looks something like ?taxonomie=term&taxonomie2=term1&taxonomie2=term2

    Any idea how i can generate a dynamic query_post based upon this?
    Ive done it before with normal posts + tags, but never with custom posttypes + taxonomies + terms!

    Any help would be apriciated!

  16. i use the code above to exclude one term from a custom taxonomy (with a NOT IN operator) but than my pagination doesn’t work, it shows me always the same posts on every page… how can i fix that? thanks very much

  17. ………i have one custom post type ‘mag_article'(magazine) and 2 custom taxonomies (mag_article_category and mag_column), with several terms per each taxonomy. what i am trying is to show on the homepage 20 articles from both taxonomies except those who have the term (‘travelogues’) under the mag_article_category.. the code above works fine but the pagination doesn’t. thanks again.

  18. Very useful post, thanks. I have a quick question, if you wouldn’t mind – I’m a designer more than a programmer, so I’m trying to work this out.

    I have a custom post type (artists), with 2 taxonomies – countries and years. If I set up a taxonomy-countries.php template, it’ll return all the entries for the country selected in the URL. Can I add a query to this template to show only the results that are also match a particular year in the years taxonomy?

  19. […] Otto does a great job of explaining some of the additions to the taxonomy system in WordPress 3.1. I’ve been using this article as a reference for the past few days. … View this Bookmark […]

  20. hello Otto.

    is this code from your Useful Gallery Example correct?

    $galleryquery['tax_query'] = array(
        'tax_query' => array(
            'relation' => 'OR',
    

    I would have expected:

    $galleryquery['tax_query'] = array(
            'relation' => 'OR',
    

    cheers,
    Gregory

    • Edit: My bad. The examples are NOW correct as given. Fixed. :)

      • Otto, cool. thanks for that. lots to learn.

        so the tax_query array can be combined with other associative array items in a query array. I wonder if conflicts could be created if search criteria existed both within the tax_query and within the query array itself. I’ll have to play around and see what happens.

        thanks again. GREAT article!

        cheers,
        Gregory

      • hi again. sorry. I’m not very familiar with this and it’s confusing me.

        why are the following two examples different?

        $myquery['tax_query'] = array(
            'relation' => 'OR',
        
        $galleryquery['tax_query'] = array(
            'tax_query' => array(
                'relation' => 'OR',
        

        cheers,
        Gregory

  21. Hi,

    I have a site with Taxonomy for State (Eg Victoria, Qeensland ETC) this taxonomy is called listing_state.

    I also have a taxonomy called membership_type which can be Free Member or Paid <e,ber. These 2 taxconomies are for a post type called listings

    If I click on the link for Queensland it brings the results as expected sorted by post date using taxonomy-listing_state.php template. How would I sort the list so the Paid Memberships show before the Free memberships.

    I am using Genesis and Lifestyle theme

    Thanks Richard

    • don’t know if this helps:

      Multiple ‘orderby’ values
      Display pages ordered by ‘title’ and ‘menu_order’. (title is dominant):

      $query = new WP_Query( array( 'post_type' => 'page', 'orderby' => 'title menu_order', 'order' => 'ASC' ) );
      
  22. This query don’t work correctly regardless documentation o tax_query described.
    I think that don’t work the IN operator in tour-scenery. It consider the two values concatenated by the AND.
    operator.

    I want all posts of walking-hiking category AND small-groups type AND (italys-coasts-and-islands OR divine-countryside) scenery.

    [tax_query] => Array
    (
    [relation] => AND
    [0] => Array
    (
    [taxonomy] => category
    [field] => slug
    [terms] => Array
    (
    [0] => walking-hiking
    )

    [operator] => IN
    )

    [1] => Array
    (
    [taxonomy] => tour-type
    [field] => slug
    [terms] => Array
    (
    [0] => small-groups
    )

    [operator] => IN
    )

    [2] => Array
    (
    [taxonomy] => tour-scenery
    [field] => slug
    [terms] => Array
    (
    [0] => italys-coasts-and-islands,divine-countryside
    )

    [operator] => IN
    )

    )

  23. […] OR that have the “images” post format. Very powerful, very cool.Read more: Otto on WordPress, WordPress Codex.Super Admin Network DashboardIf you use WordPress Multisite you will see a new […]

  24. Hi Otto,

    I’m running coupon site on WordPress. I’m posting different offers link in taxonomy named ‘store’. I want to show most recent post of each taxonomy named ‘store’ on my homepage. I tried my best to build that query but could not succeeded.

    Kindly guide me how do i build this query for my site.

    My website url is http://importantcoupon.com/

    Thanks for your kind help.

  25. Hi Otto,

    You ended up with a note on “Speed Concerns” where you say “complex queries are going to be slower. …. each taxonomy you add is the equivalent of adding a JOIN. While the relevant tables are indexed, joins are still slower than non-joins. So it won’t always be a good idea to build out highly complex queries.”

    That confuses the hell out of me.

    What do you mean by a complex query? Everything is relative right? Here, I got no guide. Maybe this question clear it up a little.

    Look, I can have one taxonomy called “category”, ( the built in category taxonomy that comes with wp ), and have 3 top level elements in there as “media”, “audience”, and “featured”. Under the “media”, I can have “videos”, “audios”, “photos” and under the “audience”, I can have “for beginners”, “for intermediates”, “for advanced” and under the “FEATURED”, I can have “main_headlines”, “must_see”, “worth_a_look”. All that under one taxonomy, that is the “category” taxonomy. With this I can do efficient queries like “give me all videos for beginners that are featured as must_see and the tag is php”. that’s one way to do it.

    now, let’s put this into perspective…

    I can implement the same site with 3 taxonomies. ( Don’t just say, why cause there are merits in doing so. )

    Yes, I can have three custom taxonomies that are “media”, “audience”, and “featured” and I totally ignore the built-in category taxonomy. With this in mind, I can implement a site just like that. The same query above, would this time result crossing 3 custom taxonomies plus the tag taxonomy. Now we are talking 4 joins right?

    As to why would I want to go with the 3 custom taxonomy or what the merit is? Well, you definitely get a much better UI in the admin dashboard when classifying your posts. Each taxonomy has its own little island so to speak so you find things more clearly. In the single join approach, you have to sift thru lots of category terms and this will be a problem as your category list continue to grow.

    Now you tell me what’s a complex query? Is the 4 join considered enough complex so we live with the long category box? Or is it really not big of a deal therefore it should be implemented as such? Ofcourse, for a site that does not have must traffic, WHO CARES? The question is being asked for a site that need to serve 100K page views per day on a $10,000 budget server. Now, What do you do here?

  26. […] aware I use Genesis here on Itsonlybarney.com and I added the necessary code based on Otto‘s example code to exclude the Link post format from the loop here on the […]

  27. […] a possibilidade de ordenar colunas de listas no painel e também com as novas funcionalidades de queries de taxonomias e de metadados. Além disso é ainda muito possível que estejam a usar um ou mais plugins da […]

  28. How do i display all terms of custom taxonomy ‘industry’, and list all the titles of custom post types ‘merchants’ under each taxonomy term.

    I also want to display the post image and excerpts.

    Please help a newbiw out.

  29. I’ve been reading on this from the original forum post that started the bug fix, and I am still not clear on whether advanced taxonomy queries can be done with custom post types. I’m trying to query a custom post type with a tag and the solution continues to elude. Is this addressed somewhere? Thanks for your time.

  30. $myquery['tax_query'] = array(
                        array(
                            'taxonomy' => 'product-categories',
                            'terms' => array('ruou-whisky','ruou-cognac'),
                            'field' => 'slug',
                            'orderby' => 'rand',
                            'showposts' => 6 
                        ),                    
                );
    

    I tried with ‘showposts’ and ‘orderby’ but it doesn’t work.
    Can you help me ?

    • Move the orderby and showposts outside the inner array, and into the $myquery array itself.

      $myquery['tax_query'] = array(
                          array(
                              'taxonomy' => 'product-categories',
                              'terms' => array('ruou-whisky','ruou-cognac'),
                              'field' => 'slug',
                          ),                    
                  );
      $myquery['orderby'] = 'rand';
      $myquery['showposts'] = 6;
      
  31. Otto, I’ve been looking everywhere for an answer to this question. I have not found any plugins that would solve my problem and I’ve been Google searching to no avail, which surprises me, since it seems like a pretty straightforward thing to do.

    I’ve created a custom taxonomy called “imagetags” using the following code:


    // Register Custom Taxonomy
    function custom_imagetags_taxonomy() {
    $labels = array(
    'name' => _x( 'Image Tags', 'Taxonomy General Name', 'text_domain' ),
    'singular_name' => _x( 'Image Tag', 'Taxonomy Singular Name', 'text_domain' ),
    'menu_name' => __( 'Image Tags', 'text_domain' ),
    'all_items' => __( 'All Image Tags', 'text_domain' ),
    'parent_item' => __( 'Parent Image Tag', 'text_domain' ),
    'parent_item_colon' => __( 'Parent Image Tag:', 'text_domain' ),
    'new_item_name' => __( 'New Image Tag', 'text_domain' ),
    'add_new_item' => __( 'Add New Image Tag', 'text_domain' ),
    'edit_item' => __( 'Edit Image Tag', 'text_domain' ),
    'update_item' => __( 'Update Image Tag', 'text_domain' ),
    'separate_items_with_commas' => __( 'Separate Image Tags with Commas', 'text_domain' ),
    'search_items' => __( 'Search Image Tags', 'text_domain' ),
    'add_or_remove_items' => __( 'Add or Remove Image Tags', 'text_domain' ),
    'choose_from_most_used' => __( 'Choose From Popular Image Tags', 'text_domain' ),
    );

    $rewrite = array(
    'slug' => 'imagetags',
    'with_front' => true,
    'hierarchical' => false,
    );

    $args = array(
    'labels' => $labels,
    'hierarchical' => false,
    'public' => true,
    'show_ui' => true,
    'show_admin_column' => true,
    'show_in_nav_menus' => true,
    'show_tagcloud' => true,
    'rewrite' => $rewrite,
    );

    register_taxonomy( 'imagetags', 'attachment', $args );
    }

    // Hook into the 'init' action
    add_action( 'init', 'custom_imagetags_taxonomy', 0 );

    This creates an “imagetags” meta box where users can create taxonomy terms for later sorting images.

    Here’s my question:

    What would be the appropriate way to create a loop on a page template I’m calling taxonomy-imagetags.php?

    Nothing I’ve tried seems to work. Instead of listing all my attempts, I’m wondering if there is a custom query that would show image attachments based on terms created in the “imagetags” meta box.

    Would be a very generous bit of help, Otto. Thanks in advance.

    Jim

  32. Hey Otto – Hopefully you’re still monitoring this (and thanks for all the amazing work you do in the WordPress community). I’m having issues with a custom taxonomy query. Essentially, what I’m trying to do is execute a query for all entries into a custom post type by a specific author and with a specific tag on their author.php template. I’m using the Co-Authors Plus plugin and the author suggested using tax_query to pull author specific posts, but when combined with another taxonomy it just fails. Here is what I’d like to accomplish:

    $args = array(
    	'post_type' => array(
    		                    'sale',
    		                    'lease'
    	                		),
    	'tax_query' => array(
    							array(
    								'taxonomy' => 'author',
    								'field' => 'slug',
    								'terms' => $curauth->user_login
    							),
    							array(
    					          'taxonomy' => 'post_tag',
    					          'field' => 'slug',
    					          'terms' => array('sold')
    					        )
    						),
    );
    $query = new WP_Query( $args ); while($query->have_posts()) : $query->the_post();

    From what I understand, this should pull all entries from those custom post types by the current author with that specific tag. It works if I remove the author tax_query and vice versa, but not together. I’ve even tried using simple parameters in the main query like

    'tag' => 'sold'

    and

    'tag__in' => array(34)

    but those do not work either when combined with the author taxonomy.

    Any thoughts?

    • Do a var_dump on the $query after you create it, then look at the actual SQL it generates. It’s easier to debug something that way than to try to guess at what it’s doing.

      • Thanks for the quick response, I appreciate it. Good call on the var_dump, however… I’m still in the same situation, if not more confused. I checked the output for every author on the site and the SQL is there for all but two of them. I have double-checked to make sure that there are entries that would show up for the specified query, but still nothing. I’ve also just realized that tax_query for the author taxonomy using $curauth->user_login actually doesn’t work at all for these two, but it does for everyone else.

        So, I’ve now narrowed it down to the fact that $curauth->user_login doesn’t work once the query starts for just these two users.

        Have you ever seen an issue with slug length and tax_query? Otherwise… I’m at a loss.

        Here are the pages if this piques your curiosity:

        Not Working
        Not Working

        Working
        Working

        Again, I appreciate your time.

      • Just in case you or anyone else runs into this issue: I found a solution, although rather inelegant and not something I’d like to use long term. Submitted to github here:

        https://github.com/Automattic/Co-Authors-Plus/issues/107

  33. Hey Otto,

    I’ve got a custom post type for training courses. For those courses I’ve got taxonomies of “qualification-level”, “training-country” and “worker-cardre”.

    I’m trying to retrieve posts based on a keyword that matches in any of the taxonomies

    eg. for the keyword of “Australia” it should return posts that match “Australia” for “qualification-level” OR “training-country” OR “worker-cardre”. The code I’m using for the tax_query is below:


    $args = array();
    $args['post_type'] = "training";
    $args['showposts'] = 15;
    $args['paged'] = $paged;
    $args['orderby'] = "title";
    $args['order'] = "ASC";
    if( ! empty( $_SESSION['keywords'] ) ) {
    $args['tax_query'] = array(
    'relation' => 'OR',
    array(
    'taxonomy' => 'qualification-level',
    'terms' => array($_SESSION['keywords']),
    'field' => 'slug',
    ),
    array(
    'taxonomy' => 'training-country',
    'terms' => array($_SESSION['keywords']),
    'field' => 'slug',
    ),
    array(
    'taxonomy' => 'worker-cadre',
    'terms' => array($_SESSION['keywords']),
    'field' => 'slug',
    ),
    );
    }
    $search_query = new WP_Query($args);

    t is currently returning all results, even those that don’t match the keyword (eg, Vietnam).

    I’ve also tried with the 'operator' => 'IN' for each but that doesn’t seem to work either (still shows all results)

    Any chance you can help?

    Thanks.

  34. Hi Otto

    How can I implement a multiple search plugin if I have more than 4 taxonomy types and I’d like to be able to select a few taxonomies from first type and use AND operator, a few from second type and use OR operator and from the 4th to have again AND operator and between all taxonomy types to have an AND operator. Is that possible. I’m asking because as I can see, only one array is used to manage multiple taxonomies and IN operator is not useful enough for my needs.

    Thank you

  35. I am trying to show posts from posts within one category as well as several other post types from withing one category all on one page. I have the below code and it works but pagination does not work any help would be appreciated.

    ‘OR’,
    array(
    ‘taxonomy’ => ‘category’,
    ‘terms’ => array(‘outdoor-recreation’),
    ‘field’ => ‘slug’,
    ),
    array(
    ‘taxonomy’ => ‘outtake_category’,
    ‘terms’ => array(‘outdoor-recreation’),
    ‘field’ => ‘slug’,
    ),
    array(
    ‘taxonomy’ => ‘story_category’,
    ‘terms’ => array(‘outdoor-recreation’),
    ‘field’ => ‘slug’,
    ),
    );
    query_posts($myquery);
    ?>

    <div id=”post-“>

    <h2 id="post-“><a href="”>

    <?php
    if ( has_post_thumbnail()) {
    echo 'ID) . ‘” >';
    the_post_thumbnail();
    echo ‘
    ‘;
    }
    ?>

  36. Many thanks for really comprehensive posts!

    Is it possible to use the Operator ‘Not In’ with ‘taxonomy’ => ‘post_tag’. It appears to work perfectly with categories.

    Have tried to add the following (not a coder) to functions.php but i just get white screen.

    function xclude_tag($query) {
    if ( $query->is_home ) {
    $query->set(array(
              'taxonomy' => 'post_tag',
    	'field' => 'slug',
              'terms' => array('xhidex'),
              'operator' => 'NOT IN'
            )
    )
    }
      return $query;
    }
    add_filter('pre_get_posts', 'xclude_tag');

    Any obervations most welcome!

  37. Great article Otto. Very clear and well explained.

    Searching high and low for an answer to the following.

    I have a custom search box that takes a user input keyword(s). Then it limits the results to a custom post type (using post_type in the query args). That part works great.

    My confusion is how to use the search query to also parse the custom taxonomy category names. In addition, I have a number of custom meta fields added to the custom post type, and I’d like to search for the keyword in the meta values.

    For example: User searches for “Advertising”

    This should match any posts:
    – in the “Marketing & Advertising” category of my custom taxonomy.
    or
    – that contain “advertising” in the meta values
    or
    – that contain “advertising” in the standard post fields (title and content).

    Any insights or help?

  38. Hi, Great website. I need help with this. I am using Car demon, and I want to grab all vehicles where condition is “NEW”, body_style is “FOO”, and year is “2012” and can be order by year or style. I have been drafting multiple queries but Im a bit stuck! Some data is in the wp_postmeta(year) and the rest can be found in taxonomy/terms (vehicle_condition / New respectively)

  39. Here is my code
    $args = array(
    ‘post_type’ => ‘cars_for_sale’,
    ‘post_status’ => ‘publish’,

    ‘tax_query’ => array(
    array(
    ‘taxonomy’ => ‘name’,
    ‘field’ => ‘slug’,
    ‘terms’ => array(‘New’, ‘Fifth Truck’, ‘2013’),
    ‘operator’ => ‘AND’
    )
    )
    );
    Order by Price desc, year asc

  40. Hi, great post! i want to create a search form having 2 inputs. 1-drop down and 2-text input, having a common submit button. If 1 option is selected from the drop down menu, keeping the text input field empty, then the search should be made based on drop down menu. and vice versa. If both the fields are mentioned, i want the search form to produce results according to the input text.

  41. Hello my friends
    I have a problem with viper and same theme
    i use viper theme, that is ECommerce theme and free theme .
    When a product is finish in store, I can not delete product page for Google indexing .
    So , i should remove the product only of home page .
    But plugins not support to ‘product’ and ‘department’ options “taxonomy-department”.
    this plugins (wp-exclude-from-homepage.1.1.2 and wp-exclude-from-homepage.1.1.2 ) support for normal category but not support ‘department and other taxonomy ‘ !!!
    I want for example the products in “finish” categories are not displayed on my home page
    Purpose of “categories” is “product > department > finish” in my theme .

    Dear friends can you suggest a way for help me ?
    Please explain to me as a beginner.

    thank you

  42. […] of 5, or games that can help with focus or help with reading skills or have a recommended age of 5. Otto has a great write-up for getting started with taxonomy queries, where he also […]

  43. […] homepage loop what to display by telling it what NOT to display (as suggested by Roy Scribner and Otto); but this didn’t work, because the twentyfourteen theme takes a different approach to doing […]

  44. […] WordPress 3.1: Advanced Taxonomy Queries » Otto on WordPress […]

  45. Hi there i’m having a problem with taxonomy, custom post and category.

    I create a custom post type that allows categories, post_tags and a new taxonomy (created only for this type of post).

    I do a several test and found that when i add a category evaluation, like “cat”=>$wp_query->get(‘cat’) or somethig like array(‘taxonomy’ => ‘category’,’field’ => ‘term_id’,’terms’ => $wp_query->get(‘cat’)) it changes the post_type from my custom post to post

    This is my args for the new WP_query

    $args_ads=array(
    'post_status' => 'publish',
    //'cat'=>$wp_query->get('cat'),
    'tax_query' => array(
    array('taxonomy' => 'ubicaciones','field' => 'slug','terms' => 'ub-categoria','operator'=> 'IN'),
    array('taxonomy' => 'category','field' => 'term_id','terms' => $wp_query->get('cat'),'operator'=> 'IN')
    ),
    'post_type' => array('libreria'),
    'orderby' => 'rand');
    $query_ads = new WP_Query($args_ads);

    This is the query i get when i do a var_dump in the request field

    SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id) INNER JOIN wp_term_relationships AS tt1 ON (wp_posts.ID = tt1.object_id) WHERE 1=1 AND ( wp_term_relationships.term_taxonomy_id IN (74) AND tt1.term_taxonomy_id IN (7) ) AND wp_posts.post_type = 'post' AND (wp_posts.post_status = 'publish') GROUP BY wp_posts.ID ORDER BY RAND() DESC LIMIT 0, 15

    The only way that i found to solve my problem is remove the category evaluation in the query and allowing the query bring me ALL the results and inside the loop check if is it in that particular category. The problem for that is if i have over 200 custom post or maybe more (right now the site have 10.000 regular post) it will be insane to do it inside the loop.

    Some happens the same?

    • Do you have this in the register_post_type function call?

      'taxonomies' => array( 'category', 'post_tag' ),
      

      In order to query by a taxonomy, a post type needs to be explicitly told that it can support that taxonomy.

      Also, in a query, the post_type should not be an array unless you have more than one of them. Simplify and just use post_type => ‘libreria’ instead of wrapping it in a needless array.

  46. hi otto,
    thanks for your code and explanations.
    i used the case of getting posts from certain categories ANS certain tags.
    unfortunatly the array of tags does’nt work, meaning only the first tag in the list is detected.

    see taxonomy “orte”. here only posts from the fist tag -> “tag1″ are shown together with the first category.

    'AND',
    array(
    'taxonomy' => 'category',
    'terms' => array('cat1', 'cat2', 'cat3'),
    'field' => 'slug',
    ),
    array(
    'taxonomy' => 'orte',
    'terms' => array('tag1','tag2','tag3','tag4'),
    'field' => 'slug',
    ),
    );
    query_posts($myquery);
    ?>

    is there something wrong in the code?

    thanks for your help.

    • here a better version of the code.

      &amp;lt;?php
                $myquery['tax_query'] = array(
                		'relation' =&amp;gt; 'AND',
                    array(
                        'taxonomy' =&amp;gt; 'category',
                        'terms' =&amp;gt; array('cat1', 'cat2', 'cat3'),
                        'field' =&amp;gt; 'slug',
                    ),
                    array(
                        'taxonomy' =&amp;gt; 'orte',
                        'terms' =&amp;gt; array('tag1','tag2','tag3','tag4'),
                        'field' =&amp;gt; 'slug',
                    ),
                );
                query_posts($myquery);
                ?&amp;gt;
      
       
      • I don’t know what “orte” is, but an array of tags works just fine, like any other array of terms. Maybe you need to specify an operator there to get the results you’re looking for.

        • thanks for your answer.
          “orte” is the german word for “places”, my own custom taxonomy.
          i tried before with different operators, but it did not help.

          what helped now for me, is changing from slug to term_id.
          now the array works for me.

          for example:

          'field' =&amp;gt; 'term_id',
           'terms' =&amp;gt; array('251','375','249'),
          
  47. Is it possible to use tax_query to retrieve posts of the same taxonomy.

    echo GeoMashup::map( array(
    	'map_content' =&amp;gt; 'global',
            'tax_query' =&amp;gt; array(
                    'relation' =&amp;gt; 'AND',
    		array(
    			'taxonomy' =&amp;gt; 'post_tag',
    			'field' =&amp;gt; 'slug',			
                            'terms' =&amp;gt; 'cebu'
    		     ),
    		array(
    			'taxonomy' =&amp;gt; 'post_tag',
    			'field' =&amp;gt; 'slug',			
                            'terms' =&amp;gt; 'budget hotel',
                            'operator' =&amp;gt; 'IN',
                          )
     	                    )
    ) ); 
    ?&amp;gt;
    

Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Need to post PHP code? Wrap it in [php] and [/php] tags.