Wordpress - Custom Taxonomy WP_Query for All Terms in a Taxonomy?

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


Something like this might work:

$args = array(
    'post_type' => 'post',
    'tax_query' => array(
        array(
            'taxonomy' => 'your_custom_taxonomy',
            'operator' => 'EXISTS'
        ),
    ),
);
$query = new WP_Query( $args );

You are basically asking for any post assigned to any term within your_custom_taxonomy.


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.