count number of posts (public , private , protected) by category name

I wanted to count number of posts (public, private, protected) according to a category name suppose blog . To get all the posts no matter what category i used $total_pages = wp_count_posts()->publish;

But i cant figure out how to count number of posts for a category name blog

Related posts

2 comments

  1. Here is another flexible way to count posts:

    Idea:

    First I was going to write the SQL query directly, but then I thought it would be more flexible if we could instead just modify the SQL query generated by WP_Query() so it would only return the results count instead of post objects.

    Example:

    I’ve been playing with these things today and this is what came out of it:

    $args = array(
              'post_type'           => 'post',
              'post_status'         => 'publish',
              'category_name'       => 'reykjavik',
           );
    
    $q = new WPSE_121749_Query_Count( $args );
    echo $q->count();
    

    where you can change $args to your likings and WPSE_121749_Query_Count is an extension of WP_Query.

    Output:

    In the above example the output of echo $q->count(); is 95 since
    the output of print_r( $q->posts ); is:

    Array ( [0] => 95 )
    

    and it doesn’t contain any post objects, since we only want the count.

    The Class:

    There are many hooks available to modify the WP_Query and I use three filters and one action but there might be better ways to do this using other hooks.

    Here is the first version of the class:

    /**
     * Class WPSE_121749_Query_Count
     *
     */
    class WPSE_121749_Query_Count extends WP_Query 
    {       
    public function __construct( $args = array() )
    {
        add_filter( 'posts_request',    array( $this, 'posts_request'   ) );
        add_filter( 'posts_orderby',    array( $this, 'posts_orderby'   ) );
        add_filter( 'post_limits',      array( $this, 'post_limits'     ) );
        add_action( 'pre_get_posts',    array( $this, 'pre_get_posts'   ) );
    
        parent::__construct( $args );
    }
    
    public function count()
    {
        if( isset( $this->posts[0] ) )
            return $this->posts[0];
    
        return '';          
    }
    
    public function posts_request( $request )
    {
        remove_filter( current_filter(), array( $this, __FUNCTION__ ) );
        return sprintf( 'SELECT COUNT(*) FROM ( %s ) as t', $request );
    }
    
    public function pre_get_posts( $q )
    {
        $q->query_vars['fields'] = 'ids';
        remove_action( current_filter(), array( $this, __FUNCTION__ ) );
    }
    
    public function post_limits( $limits )
    {
        remove_filter( current_filter(), array( $this, __FUNCTION__ ) );
        return '';
    }
    
    public function posts_orderby( $orderby )
    {
        remove_filter( current_filter(), array( $this, __FUNCTION__ ) );
        return '';
    }
    
    }
    
  2. To count only published post for a category, is easy get the count argument of the category object.
    However, note that if category is associated with some CPTs the count is the total of all posts belonging to a particular term, no matter what post_type they are.

    $cat = get_category('blog');
    $post_with_blog_category = $cat->count;
    

    If you want to count also other post status, only way is to run a WP_Query and look at number of post found.
    You can use a function to make it more flexible and reusable:

    function count_posts_by_tax( $term = '', $tax = 'category', $type = 'post' ) {
      if ( empty( $term ) ) return false;
      $q = new_WP_Query( array(
        'post_type' => $type,
        'post_status' => 'any',
        'posts_per_page' => -1,
        'tax_query' => array(
           array(
             'taxonomy' => $tax,
             'terms' => array($term),
             'field' => is_int($term) ? 'id' : 'slug'
           )
         )
      ) );
      if ( ! $q->found_posts ) return 0;
      $statuses = wp_list_pluck( $q->posts, 'post_status' );
      return (object) array_count_values( $statuses );
    }
    

    Now you can use it like so:

    $count = count_posts_by_tax('blog');
    
    $published_blog_posts = $count->publish;
    $private_blog_posts = $count->private;
    $prending_blog_posts = $count->pending;
    $draft_blog_posts = $count->draft;
    

    Function is flexible enough to work for other taxonomies than category and with other post types than standard post, just pass the 2nd and the 3rd param to function.

    Please note that the function run a SQL query to retrieve all posts in all statuses… if you have hundreds of posts, it can be very slow and hurts the page load consistently.

    If you have a lot of posts and you need to count them based on a category and for different post statuses, I suggest you to create a custom function that hook into the category/post association and when it happen update a value in db, probably an option or a transient. Once you want the count for different post statuses, you should also hook into post status transition to make the count consistent.
    Sure is longer and more complex work, but the performance increment worth the work, especially if you have (or plan to have) a great number of posts.

Comments are closed.