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:
Use a complete SQL query with $wpdb->get_results()
,
Get a list of $post->ID
s for all posts in your taxonomy and then pass them using the 'post__id'
argument, or
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-ID
s 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.