Counting Posts of a Given Post Type Having a Specific Taxonomy?

(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()!

Read More

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 !

Related posts

Leave a Reply

6 comments

  1. 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.

  2. 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')

  3. 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…

  4. @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.

  5. Hello,

    I believe that the simple and most efficient way to count posts in custom post type or in a taxonomy is:

    $total_posts = wp_count_posts($post_type = 'game'); //or what ever else
    

    Then to echo it as follow:

    <?php echo $total_posts->publish; ?>
    <?php echo $total_posts->draft; ?>
    <?php echo $total_posts->future; ?> // for scheduled posts
    

    Hope this help.