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.

(Moderator's note: The original title was "How to know the number of custom type posts having a specific taxonomy")

I'm stuck with the function wp_count_posts()!

I created custom post types called 'artwork' to display artworks in a gallery. I also created a custom taxonomy called 'artworkcat' to sort each artwork into a specific category ('webdesign', 'logo', 'print').

I would like to use the wp_count_posts() to know how many posts I have using the 'artwork' custom post type, in a specific category.

If that's not clear, I give you a practical example : I would like to know how many posts I have in this 'artwork' custom post type, with the 'artworkcat' taxonomy called 'webdesign'.

Does wp_count_posts() work for this, adding some parameters ?

Thanks for the help !

share|improve this question
And, if someone knows how to get a list of all the 'categories' existing inside the taxonomy 'artworkcat', that would help too ! –  Pierre Oct 28 '10 at 16:56

4 Answers 4

wp_count_posts() will not work for this, it does not accept a taxonomy parameter. You can do the following:

$taxonomy = 'artworkcat';
$term_slug = 'webdesign';
$post_type = 'artwork';

$term = get_term_by( 'slug', $term_slug, $taxonomy_type );

$count = $wpdb->get_var($wpdb->prepare("SELECT COUNT(*) FROM $wpdb->posts
INNER JOIN $wpdb->term_relationships
ON ($wpdb->posts.ID = $wpdb->term_relationships.object_id)
INNER JOIN $wpdb->term_taxonomy
ON ($wpdb->term_relationships.term_taxonomy_id = $wpdb->term_taxonomy.term_taxonomy_id)
WHERE $wpdb->posts.post_type = $post_type
AND $wpdb->term_taxonomy.taxonomy = $taxonomy
AND $wpdb->term_taxonomy.term_id = {$term->term_id};"));

To get a list of terms inside a taxonomy, use get_terms(). E.g.: get_terms('artworkcat')

share|improve this answer
Thanks for the help sorich87. I just don't know how to use this $count. Is this going to return an array or a value ? –  Pierre Oct 28 '10 at 17:37
You are welcome. It will return a value. –  sorich87 Oct 28 '10 at 17:41

Sorich's code is great if you're comfortable manipulating SQL queries. If you'd rather build a simple query, you can use get_posts() to return an array of post objects that match the desired query parameters and count them at the same time, returning a value. I've used this to count all sorts of combinations, as it's easy to modify.

$args = array(
    'post_type' => 'artwork',
    'post_status' => 'any',
    'genre' => 'romantic'
$num = count( get_posts( $args ) );

Change the post_status arg to "publish" if you only want to count published items.

And if you have the Query Multiple Taxonomies plugin by scribu installed, you can add multiple taxonomies to the args...

share|improve this answer

Hi @Pierre:

@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;


    $term_ids = get_terms($taxonomy,'fields=ids');
    $query = new WP_Query(array(
      'post_type' => $post_type,
      'posts_per_page' => '-1',
      'category__in' => $term_ids,


    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}.name AS term_name,
{$wpdb->terms}.slug AS term_slug,
COUNT(*) as post_count
    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.

share|improve this answer

Somatic had the cleanest answer, but missed one thing. You should specify the numberposts to be -1 so that it counts them all. Like this:

$args = array(
    'post_type' => 'artwork',
    'post_status' => 'published',
    'genre' => 'romantic',
    'numberposts' => -1
$num = count( get_posts( $args ) );

just replace genere with your taxonomy slug and romantic with the specific term.

share|improve this answer
If you use this code, which is perfectly suited to its purpose, you should change 'published' to 'publish', that is 'post_status => 'publish', –  Malachy Aug 17 at 12:18

Your Answer


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