Title: wp_count_posts
Published: April 25, 2014
Last modified: February 24, 2026

---

# wp_count_posts( string $type, string $perm ): stdClass

## In this article

 * [Description](https://developer.wordpress.org/reference/functions/wp_count_posts/?output_format=md#description)
 * [Parameters](https://developer.wordpress.org/reference/functions/wp_count_posts/?output_format=md#parameters)
 * [Return](https://developer.wordpress.org/reference/functions/wp_count_posts/?output_format=md#return)
 * [Source](https://developer.wordpress.org/reference/functions/wp_count_posts/?output_format=md#source)
 * [Hooks](https://developer.wordpress.org/reference/functions/wp_count_posts/?output_format=md#hooks)
 * [Related](https://developer.wordpress.org/reference/functions/wp_count_posts/?output_format=md#related)
 * [Changelog](https://developer.wordpress.org/reference/functions/wp_count_posts/?output_format=md#changelog)
 * [User Contributed Notes](https://developer.wordpress.org/reference/functions/wp_count_posts/?output_format=md#user-contributed-notes)

[ Back to top](https://developer.wordpress.org/reference/functions/wp_count_posts/?output_format=md#wp--skip-link--target)

Counts number of posts of a post type and if user has permissions to view.

## 󠀁[Description](https://developer.wordpress.org/reference/functions/wp_count_posts/?output_format=md#description)󠁿

This function provides an efficient method of finding the amount of post’s type 
a blog has. Another method is to count the amount of items in [get_posts()](https://developer.wordpress.org/reference/functions/get_posts/),
but that method has a lot of overhead with doing so. Therefore, when developing 
for 2.5+, use this function instead.

The $perm parameter checks for ‘readable’ value and if the user can read private
posts, it will display that for the user that is signed in.

## 󠀁[Parameters](https://developer.wordpress.org/reference/functions/wp_count_posts/?output_format=md#parameters)󠁿

 `$type`stringoptional

Post type to retrieve count. Default `'post'`.

`$perm`stringoptional

`'readable'` or empty. Default empty.

## 󠀁[Return](https://developer.wordpress.org/reference/functions/wp_count_posts/?output_format=md#return)󠁿

 stdClass An object containing the number of posts for each status, or an empty 
object if the post type does not exist.

## 󠀁[Source](https://developer.wordpress.org/reference/functions/wp_count_posts/?output_format=md#source)󠁿

    ```php
    function wp_count_posts( $type = 'post', $perm = '' ) {
    	global $wpdb;

    	if ( ! post_type_exists( $type ) ) {
    		return new stdClass();
    	}

    	$cache_key = _count_posts_cache_key( $type, $perm );

    	$counts = wp_cache_get( $cache_key, 'counts' );
    	if ( false !== $counts ) {
    		// We may have cached this before every status was registered.
    		foreach ( get_post_stati() as $status ) {
    			if ( ! isset( $counts->{$status} ) ) {
    				$counts->{$status} = 0;
    			}
    		}

    		/** This filter is documented in wp-includes/post.php */
    		return apply_filters( 'wp_count_posts', $counts, $type, $perm );
    	}

    	if (
    		'readable' === $perm &&
    		is_user_logged_in() &&
    		! current_user_can( get_post_type_object( $type )->cap->read_private_posts )
    	) {
    		// Optimized query uses subqueries which can leverage DB indexes for better performance. See #61097.
    		$query = "
    			SELECT post_status, COUNT(*) AS num_posts
    			FROM (
    				SELECT post_status
    				FROM {$wpdb->posts}
    				WHERE post_type = %s AND post_status != 'private'
    				UNION ALL
    				SELECT post_status
    				FROM {$wpdb->posts}
    				WHERE post_type = %s AND post_status = 'private' AND post_author = %d
    			) AS filtered_posts
    		";
    		$args  = array( $type, $type, get_current_user_id() );
    	} else {
    		$query = "
    			SELECT post_status, COUNT(*) AS num_posts
    			FROM {$wpdb->posts}
    			WHERE post_type = %s
    		";
    		$args  = array( $type );
    	}

    	$query .= ' GROUP BY post_status';

    	$results = (array) $wpdb->get_results(
    		$wpdb->prepare( $query, ...$args ), // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Placeholders are used in the string contained in the variable.
    		ARRAY_A
    	);
    	$counts  = array_fill_keys( get_post_stati(), 0 );

    	foreach ( $results as $row ) {
    		$counts[ $row['post_status'] ] = $row['num_posts'];
    	}

    	$counts = (object) $counts;
    	wp_cache_set( $cache_key, $counts, 'counts' );

    	/**
    	 * Filters the post counts by status for the current post type.
    	 *
    	 * @since 3.7.0
    	 *
    	 * @param stdClass $counts An object containing the current post_type's post
    	 *                         counts by status.
    	 * @param string   $type   Post type.
    	 * @param string   $perm   The permission to determine if the posts are 'readable'
    	 *                         by the current user.
    	 */
    	return apply_filters( 'wp_count_posts', $counts, $type, $perm );
    }
    ```

[View all references](https://developer.wordpress.org/reference/files/wp-includes/post.php/)
[View on Trac](https://core.trac.wordpress.org/browser/tags/6.9.4/src/wp-includes/post.php#L3404)
[View on GitHub](https://github.com/WordPress/wordpress-develop/blob/6.9.4/src/wp-includes/post.php#L3404-L3481)

## 󠀁[Hooks](https://developer.wordpress.org/reference/functions/wp_count_posts/?output_format=md#hooks)󠁿

 [apply_filters( ‘wp_count_posts’, stdClass $counts, string $type, string $perm )](https://developer.wordpress.org/reference/hooks/wp_count_posts/)

Filters the post counts by status for the current post type.

## 󠀁[Related](https://developer.wordpress.org/reference/functions/wp_count_posts/?output_format=md#related)󠁿

| Uses | Description | 
| [wp_cache_set()](https://developer.wordpress.org/reference/functions/wp_cache_set/)`wp-includes/cache.php` |

Saves the data to the cache.

  | 
| [_count_posts_cache_key()](https://developer.wordpress.org/reference/functions/_count_posts_cache_key/)`wp-includes/post.php` |

Returns the cache key for [wp_count_posts()](https://developer.wordpress.org/reference/functions/wp_count_posts/) based on the passed arguments.

  | 
| [post_type_exists()](https://developer.wordpress.org/reference/functions/post_type_exists/)`wp-includes/post.php` |

Determines whether a post type is registered.

  | 
| [get_post_stati()](https://developer.wordpress.org/reference/functions/get_post_stati/)`wp-includes/post.php` |

Gets a list of post statuses.

  | 
| [current_user_can()](https://developer.wordpress.org/reference/functions/current_user_can/)`wp-includes/capabilities.php` |

Returns whether the current user has the specified capability.

  | 
| [wp_cache_get()](https://developer.wordpress.org/reference/functions/wp_cache_get/)`wp-includes/cache.php` |

Retrieves the cache contents from the cache by key and group.

  | 
| [is_user_logged_in()](https://developer.wordpress.org/reference/functions/is_user_logged_in/)`wp-includes/pluggable.php` |

Determines whether the current visitor is a logged in user.

  | 
| [apply_filters()](https://developer.wordpress.org/reference/functions/apply_filters/)`wp-includes/plugin.php` |

Calls the callback functions that have been added to a filter hook.

  | 
| [get_current_user_id()](https://developer.wordpress.org/reference/functions/get_current_user_id/)`wp-includes/user.php` |

Gets the current user’s ID.

  | 
| [get_post_type_object()](https://developer.wordpress.org/reference/functions/get_post_type_object/)`wp-includes/post.php` |

Retrieves a post type object by name.

  | 
| [wpdb::get_results()](https://developer.wordpress.org/reference/classes/wpdb/get_results/)`wp-includes/class-wpdb.php` |

Retrieves an entire SQL result set from the database (i.e., many rows).

  | 
| [wpdb::prepare()](https://developer.wordpress.org/reference/classes/wpdb/prepare/)`wp-includes/class-wpdb.php` |

Prepares a SQL query for safe execution.

  |

[Show 8 more](https://developer.wordpress.org/reference/functions/wp_count_posts/?output_format=md#)
[Show less](https://developer.wordpress.org/reference/functions/wp_count_posts/?output_format=md#)

| Used by | Description | 
| [wp_dashboard_right_now()](https://developer.wordpress.org/reference/functions/wp_dashboard_right_now/)`wp-admin/includes/dashboard.php` |

Dashboard widget that displays some basic stats about the site.

  | 
| [get_available_post_statuses()](https://developer.wordpress.org/reference/functions/get_available_post_statuses/)`wp-admin/includes/post.php` |

Returns all the possible statuses for a post type.

  | 
| [WP_Posts_List_Table::get_views()](https://developer.wordpress.org/reference/classes/wp_posts_list_table/get_views/)`wp-admin/includes/class-wp-posts-list-table.php` |  | 
| [WP_Posts_List_Table::prepare_items()](https://developer.wordpress.org/reference/classes/wp_posts_list_table/prepare_items/)`wp-admin/includes/class-wp-posts-list-table.php` |  |

## 󠀁[Changelog](https://developer.wordpress.org/reference/functions/wp_count_posts/?output_format=md#changelog)󠁿

| Version | Description | 
| [2.5.0](https://developer.wordpress.org/reference/since/2.5.0/) | Introduced. |

## 󠀁[User Contributed Notes](https://developer.wordpress.org/reference/functions/wp_count_posts/?output_format=md#user-contributed-notes)󠁿

 1.   [Skip to note 7 content](https://developer.wordpress.org/reference/functions/wp_count_posts/?output_format=md#comment-content-1276)
 2.    [Codex](https://profiles.wordpress.org/codex/)  [  10 years ago  ](https://developer.wordpress.org/reference/functions/wp_count_posts/#comment-1276)
 3.  [You must log in to vote on the helpfulness of this note](https://login.wordpress.org?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fwp_count_posts%2F%23comment-1276)
     Vote results for this note: 3[You must log in to vote on the helpfulness of this note](https://login.wordpress.org?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fwp_count_posts%2F%23comment-1276)
 4.  **Get the Publish Status Post Count**
 5.  To get the published status type, you would call the [wp_count_posts()](https://developer.wordpress.org/reference/functions/wp_count_posts/)
     function and then access the ‘publish’ property.
 6.      ```php
         $count_posts = wp_count_posts();
     
         if ( $count_posts ) {
         	$published_posts = $count_posts->publish;
         }
         ```
     
 7.  If you are developing for PHP5 only, then you can use shorthand, if you only want
     to get one status. This will not work in PHP4 and if you want to maintain backwards
     compatibility, then you must use the above code.
 8.      ```php
         $published_posts = wp_count_posts()->publish;
         ```
     
 9.   [Log in to add feedback](https://login.wordpress.org/?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fwp_count_posts%2F%3Freplytocom%3D1276%23feedback-editor-1276)
 10.  [Skip to note 8 content](https://developer.wordpress.org/reference/functions/wp_count_posts/?output_format=md#comment-content-2764)
 11.   [Mike Ritter](https://profiles.wordpress.org/ritterml/)  [  8 years ago  ](https://developer.wordpress.org/reference/functions/wp_count_posts/#comment-2764)
 12. [You must log in to vote on the helpfulness of this note](https://login.wordpress.org?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fwp_count_posts%2F%23comment-2764)
     Vote results for this note: 2[You must log in to vote on the helpfulness of this note](https://login.wordpress.org?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fwp_count_posts%2F%23comment-2764)
 13. This function returns an object whose properties you can access:
 14.     ```php
          stdClass Object ( [publish] => 12 [future] => 0 [draft] => 0 [pending] => 0 [private] => 0 [trash] => 1 [auto-draft] => 1 [inherit] => 0 [request-pending] => 0 [request-confirmed] => 0 [request-failed] => 0 [request-completed] => 0 ) 1
         ```
     
 15. So, to find out if you have more than 1 post published try:
 16.     ```php
         if( wp_count_posts()->publish > 1 ) :
         	return true;
         else:
         	return false;
         endif;
         ```
     
 17.  [Log in to add feedback](https://login.wordpress.org/?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fwp_count_posts%2F%3Freplytocom%3D2764%23feedback-editor-2764)
 18.  [Skip to note 9 content](https://developer.wordpress.org/reference/functions/wp_count_posts/?output_format=md#comment-content-1275)
 19.   [Codex](https://profiles.wordpress.org/codex/)  [  10 years ago  ](https://developer.wordpress.org/reference/functions/wp_count_posts/#comment-1275)
 20. [You must log in to vote on the helpfulness of this note](https://login.wordpress.org?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fwp_count_posts%2F%23comment-1275)
     Vote results for this note: 0[You must log in to vote on the helpfulness of this note](https://login.wordpress.org?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fwp_count_posts%2F%23comment-1275)
 21. **Basic Example**
 22. The default usage returns a count of the posts that are published. This will be
     an object, you can var_dump() the contents to debug the output.
 23.     ```php
         $count_posts = wp_count_posts();
         ```
     
 24.  * This comment is a bit misleading. The first sentence is incorrect. Without 
        wp_debug set to true we do not receive the warning that it, as the rest of 
        the comment states, returns an object, not “a count of the posts that are published”.
      * [Mike Ritter](https://profiles.wordpress.org/ritterml/) [8 years ago](https://developer.wordpress.org/reference/functions/wp_count_posts/#comment-2767)
 25.  [Log in to add feedback](https://login.wordpress.org/?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fwp_count_posts%2F%3Freplytocom%3D1275%23feedback-editor-1275)
 26.  [Skip to note 10 content](https://developer.wordpress.org/reference/functions/wp_count_posts/?output_format=md#comment-content-1277)
 27.   [Codex](https://profiles.wordpress.org/codex/)  [  10 years ago  ](https://developer.wordpress.org/reference/functions/wp_count_posts/#comment-1277)
 28. [You must log in to vote on the helpfulness of this note](https://login.wordpress.org?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fwp_count_posts%2F%23comment-1277)
     Vote results for this note: 0[You must log in to vote on the helpfulness of this note](https://login.wordpress.org?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fwp_count_posts%2F%23comment-1277)
 29. **Count Drafts**
 30. Counting drafts is handled the same way as the publish status.
 31.     ```php
         $count_posts = wp_count_posts();
     
         if ( $count_posts ) {
         	$draft_posts = $count_posts->draft;
         }
         ```
     
 32.  [Log in to add feedback](https://login.wordpress.org/?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fwp_count_posts%2F%3Freplytocom%3D1277%23feedback-editor-1277)
 33.  [Skip to note 11 content](https://developer.wordpress.org/reference/functions/wp_count_posts/?output_format=md#comment-content-1278)
 34.   [Codex](https://profiles.wordpress.org/codex/)  [  10 years ago  ](https://developer.wordpress.org/reference/functions/wp_count_posts/#comment-1278)
 35. [You must log in to vote on the helpfulness of this note](https://login.wordpress.org?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fwp_count_posts%2F%23comment-1278)
     Vote results for this note: 0[You must log in to vote on the helpfulness of this note](https://login.wordpress.org?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fwp_count_posts%2F%23comment-1278)
 36. **Count Pages**
 37. Counting pages status types are done in the same way as posts and make use of 
     the first parameter. Finding the number of posts for the post status is done the
     same way as for posts.
 38.     ```php
         $count_pages = wp_count_posts( $post_type = 'page' );
         ```
     
 39.  [Log in to add feedback](https://login.wordpress.org/?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fwp_count_posts%2F%3Freplytocom%3D1278%23feedback-editor-1278)
 40.  [Skip to note 12 content](https://developer.wordpress.org/reference/functions/wp_count_posts/?output_format=md#comment-content-1279)
 41.   [Codex](https://profiles.wordpress.org/codex/)  [  10 years ago  ](https://developer.wordpress.org/reference/functions/wp_count_posts/#comment-1279)
 42. [You must log in to vote on the helpfulness of this note](https://login.wordpress.org?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fwp_count_posts%2F%23comment-1279)
     Vote results for this note: 0[You must log in to vote on the helpfulness of this note](https://login.wordpress.org?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fwp_count_posts%2F%23comment-1279)
 43. **Other Uses**
 44. The [wp_count_posts()](https://developer.wordpress.org/reference/functions/wp_count_posts/)
     can be used to find the number for post statuses of any post type. This includes
     attachments or any post type added in the future, either by a plugin or part of
     the WordPress Core.
 45.  [Log in to add feedback](https://login.wordpress.org/?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fwp_count_posts%2F%3Freplytocom%3D1279%23feedback-editor-1279)

You must [log in](https://login.wordpress.org/?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fwp_count_posts%2F)
before being able to contribute a note or feedback.