Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

Is there an easy way to query for any posts that is tagged with any term from a particular taxonomy?

I know this technique:

$custom_taxonomy_query = new WP_Query( 
 array(
  'taxonomy_name' => 'term_slug',
 )
);

But I would like to either pass a wildcard in place of term_slug, or perhaps just an empty string. Then that would give me all posts that are tagged by any term in that taxonomy, not just one specific term.

Thanks for your help, Dave

share|improve this question

4 Answers 4

up vote 1 down vote accepted

In retrospect, I've did a mashup of MikeSchinkel and t31os suggestion. It's possible to inject that to existing queries on the fly, but it needs WordPress 3.1:

Plugin to get an RSS Feed for posts containing any term from a taxonomy.

share|improve this answer

I encountered a similar situation Dave. This code did the trick for my purposes. It's not the leanest option in the world but it does the job well:

// Get all term ID's in a given taxonomy
$taxonomy = 'taxonomy_name';
$taxonomy_terms = get_terms( $taxonomy, array(
    'hide_empty' => 0,
    'fields' => 'ids'
) );

// Use the new tax_query WP_Query argument (as of 3.1)
$taxonomy_query = new WP_Query( array(
    'tax_query' => array(
        array(
            'taxonomy' => $taxonomy,
            'field' => 'id',
            'terms' => $taxonomy_terms,
        ),
    ),
) );

Hopefully this help you or anyone else experiencing the issue.

Kevin

share|improve this answer
    
This was extremely helpful for me. Thanks @kevinlearynet –  Aaron Holbrook Oct 22 '12 at 20:26

Hi @Dave Morris:

You are correct, WordPress decides if you don't have a term they'll just ignore your taxonomy.

There are three (3) main approaches you could try:

  1. Use a complete SQL query with $wpdb->get_results(),

  2. Get a list of $post->IDs for all posts in your taxonomy and then pass them using the 'post__id' argument, or

  3. Annotate the SQL used by WP_Query with one of the hooks that let's you add a SQL INNER JOIN referencing the taxonomy tables.

I try to avoid complete SQL in WordPress until either it can't be helped or it's simply returning a list of IDs. And in this case I'd avoid pulling a list of $post-IDs for use with the 'post__id' argument because it could run into performance issues and even memory problems if you had lots of posts. So that leaves us with #3.

I've created a class to extend WP_Query called PostsByTaxonomy which uses the 'posts_join' hook. You can see it here:

class PostsByTaxonomy extends WP_Query {
  var $posts_by_taxonomy;
  var $taxonomy;
  function __construct($args=array()) {
    add_filter('posts_join',array(&$this,'posts_join'),10,2);
    $this->posts_by_taxonomy = true;
    $this->taxonomy = $args['taxonomy'];
    unset($args['taxonomy']);
    parent::query($args);
  }
  function posts_join($join,$query) {
    if (isset($query->posts_by_taxonomy)) {
      global $wpdb;
      $join .=<<<SQL
INNER JOIN {$wpdb->term_relationships} ON {$wpdb->term_relationships}.object_id={$wpdb->posts}.ID
INNER JOIN {$wpdb->term_taxonomy} ON {$wpdb->term_taxonomy}.term_taxonomy_id={$wpdb->term_relationships}.term_taxonomy_id
  AND {$wpdb->term_taxonomy}.taxonomy='{$this->taxonomy}'
SQL;
    }
    return $join;
  }
}

You would call this class as you see below. The argument 'taxonomy' is an required but you can pass any (all?) of the other parameters that WP_Query expects as well, such as 'posts_per_page':

$query = new PostsByTaxonomy(array(
  'taxonomy' => 'category',
  'posts_per_page' => 25,
));
foreach($query->posts as $post) {
  echo " {$post->post_title}\n";
}

You can copy the PostsByTaxonomy class to your theme's functions.php file, or you can use it within a .php file of a plugin you may be writing.

If you want to test it quickly I've posted a self-contained version of the code to Gist which you can download and copy to your web server's root as test.php, modify for your use case, and then request from your browser using a URL like http://example.com/test.php.

UPDATE

To omit Sticky Posts from the posts included in the query, try this:

$query = new PostsByTaxonomy(array(
  'taxonomy' => 'category',
  'posts_per_page' => 25,
  'caller_get_posts' => true,
));

Or if it is important to you that the PostsByTaxonomy class never include sticky posts you could put it into the constructor:

  function __construct($args=array()) {
    add_filter('posts_join',array(&$this,'posts_join'),10,2);
    $this->posts_by_taxonomy = true;
    $this->taxonomy = $args['taxonomy'];
    $args['caller_get_posts'] = true     // No Sticky Posts
    unset($args['taxonomy']);
    parent::query($args);
  }

UPDATE 2

After posting the above I learned 'caller_get_posts' will be deprecated and 'ignore_sticky_posts' will be used in WordPress 3.1.

share|improve this answer
    
Mike, Thanks for your help. I'm unable to get that to work for some reason. It's not returning only posts with terms assigned from my custom taxonomy. It always seems to return other posts. However, it doesn't return all posts, so it's definitely doing something... Am I able to use the $query->have_posts() function to iterate? Neither method seems to be working for me, either way. –  Dave Morris Nov 6 '10 at 13:40
    
Ah, this is interesting. I found the query in the mysql log that gets the two posts I'm expecting, and it works. But for some reason, five posts are coming back when I loop over $query->posts. The only other thing I notice is that directly after the custom taxonomy posts query runs, another query runs that grabs three more posts, by their post_id's. And then I guess all five posts are put into one results array. –  Dave Morris Nov 6 '10 at 14:07
    
I think I figured it out. This custom query seems to include sticky posts, even though they are not in that custom taxonomy. Any ideas on how to honor sticky posts properly, or at least to get them out of this particular query? Thanks, Dave –  Dave Morris Nov 6 '10 at 14:14
    
Well they are "sticky", right? :) It's weird behavior, I think, but if you use caller_get_posts=1 and they should go away: codex.wordpress.org/Function_Reference/… Hope this helps. –  MikeSchinkel Nov 6 '10 at 16:54
    
That if(isset($query->posts_by_taxonomy)) is a nice trick to combine the object-oriented methodology with the hook methodology of WordPress. –  Jan Fabry Nov 6 '10 at 18:21

You should just be able to set the taxonomy and negate to include a term..

Eg.

<?php
$your_query = new WP_query;
$your_query->query( array( 'taxonomy' => 'your-taxonomy-name' ) );
?>

Which would pretty much be the same as the query a taxonomy archive performs.

share|improve this answer
    
That doesn't work. –  Dave Morris Nov 5 '10 at 23:43
    
Line 1432 of query.php checks whether taxonomy OR term are empty, so you can't just not pass a slug... Any other ideas? –  Dave Morris Nov 5 '10 at 23:50
    
@t31os - That was might first reaction as well; I've actually been tripped up by it more than once since I keep forgetting. But @Dave Morris is right; if it's not a taxonomy/term pair then WP_Query just throws it away. –  MikeSchinkel Nov 6 '10 at 7:47
3  
@t31os - Yup, WP_Query is unfortunately not implemented in such an elegant manner. It's almost 1200 lines of hard-coded special cases. –  MikeSchinkel Nov 6 '10 at 17:06
3  
"almost 1200 lines of hard-coded special cases." ... that made me lol, had to +1 the comment... ;) –  t31os Nov 6 '10 at 17:19

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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