@somatic's answer is probably the best for most sites; it is certainly the simplest. And if you are very comfortable with SQL you can use @sorich87's answer. Or you can use my hybrid solution below.
There was a very similar question asked last week (definitely read the answer to that question before reading the answer I left for you here):
Taking the answer from that and modifying it slightly you get a call that look like this:
$post_counts = CountPostsForPostTypeAndCategory::count('artwork','artworkcat');
foreach($post_counts as $post_counts) {
echo "{$post_counts->term_name}: {$post_counts->post_count}<br/>";
}
And here is that class which you can copy into your theme's functions.php
file or use in the .php
file of a plugin you might be writing. It is probably overkill (and probably overly complex) for your needs but in case you want a hybrid solution it should give you want you want and if you have lots of posts (hundreds?) it will perform better than loading all posts into an array just to be able to count them:
class CountPostsForPostTypeAndCategory {
static $term_ids;
static $taxonomy;
static function count($post_type,$taxonomy) {
self::$taxonomy = $taxonomy;
add_action('posts_fields',array(__CLASS__,'posts_fields'));
add_action('posts_where',array(__CLASS__,'posts_where'));
add_action('posts_join',array(__CLASS__,'posts_join'));
add_action('posts_groupby',array(__CLASS__,'posts_groupby'));
$term_ids = get_terms($taxonomy,'fields=ids');
$query = new WP_Query(array(
'post_type' => $post_type,
'posts_per_page' => '-1',
'category__in' => $term_ids,
));
remove_action('posts_fields',$array(__CLASS__,'posts_fields'));
remove_action('posts_where',array(__CLASS__,'posts_where'));
remove_action('posts_join',array(__CLASS__,'posts_join'));
remove_action('posts_groupby',array(__CLASS__,'posts_groupby'));
return $query->posts;
}
static function posts_where($where) {
global $wpdb;
$taxonomy = self::$taxonomy;
$where = preg_replace("#({$wpdb->term_taxonomy}.taxonomy) = 'category'#","\\1 = '{$taxonomy}'",$where);
return $where;
}
static function posts_join($join) {
global $wpdb;
$join .= " INNER JOIN {$wpdb->terms} ON {$wpdb->terms}.term_id = {$wpdb->term_taxonomy}.term_id ";
return $join;
}
static function posts_groupby($groupby) {
global $wpdb;
$groupby = " {$wpdb->posts}.post_type, {$wpdb->terms}.term_id";
return $groupby;
}
static function posts_fields($field_list) {
global $wpdb;
$field_list =<<<SQL
{$wpdb->terms}.term_id,
{$wpdb->terms}.name AS term_name,
{$wpdb->terms}.slug AS term_slug,
COUNT(*) as post_count
SQL;
return $field_list;
}
}
A couple things to explain. WP_Query()
doesn't let us query for a list of taxonomy term IDs, but it does let us query for a list of category IDs. But what are categories? They are a a taxonomy named 'category'
? That's why I set up WP_Query()
to query by category IDs using your taxonomy term IDs, but then I do a string replace in the posts_where
hook to replace 'category'
with '{$taxonomy}'
, or in your case with 'artworkcat'
.
All the apparent complexity around the add_action()
and remove_action()
is simply to allow you to only use those hooks when you need them and not to leave them laying around where they could potentially affect your other queries.