Properly invalidate the cache for `wp_count_posts()` on insert, trash, or when transitioning `post_status` inside of `_transition_post_status()`. Introduces `_count_posts_cache_key()`. Adds unit tests.

Props mark8barnes, for bringing this to our attention in an initial patch.
Fixes #21879.


Built from https://develop.svn.wordpress.org/trunk@27081


git-svn-id: http://core.svn.wordpress.org/trunk@26954 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
Scott Taylor 2014-02-03 19:42:13 +00:00
parent 2f6d9d37cc
commit 4830eeb9ad
1 changed files with 30 additions and 6 deletions

View File

@ -2076,6 +2076,26 @@ function unstick_post($post_id) {
update_option('sticky_posts', $stickies);
}
/**
* Return the cache key for wp_count_posts() based on the passed arguments
*
* @since 3.9.0
*
* @param string $type Optional. Post type to retrieve count
* @param string $perm Optional. 'readable' or empty.
* @return string The cache key.
*/
function _count_posts_cache_key( $type = 'post', $perm = '' ) {
$cache_key = 'posts-' . $type;
if ( 'readable' == $perm && is_user_logged_in() ) {
$post_type_object = get_post_type_object( $type );
if ( ! current_user_can( $post_type_object->cap->read_private_posts ) ) {
$cache_key .= '_' . $perm . '_' . get_current_user_id();
}
}
return $cache_key;
}
/**
* Count number of posts of a post type and if user has permissions to view.
*
@ -2101,16 +2121,15 @@ function wp_count_posts( $type = 'post', $perm = '' ) {
if ( ! post_type_exists( $type ) )
return new stdClass;
$user = wp_get_current_user();
$cache_key = 'posts-' . $type;
$cache_key = _count_posts_cache_key( $type, $perm );
$query = "SELECT post_status, COUNT( * ) AS num_posts FROM {$wpdb->posts} WHERE post_type = %s";
if ( 'readable' == $perm && is_user_logged_in() ) {
$post_type_object = get_post_type_object($type);
if ( !current_user_can( $post_type_object->cap->read_private_posts ) ) {
$cache_key .= '_' . $perm . '_' . $user->ID;
$query .= " AND (post_status != 'private' OR ( post_author = '$user->ID' AND post_status = 'private' ))";
if ( ! current_user_can( $post_type_object->cap->read_private_posts ) ) {
$query .= $wpdb->prepare( " AND (post_status != 'private' OR ( post_author = %d AND post_status = 'private' ))",
get_current_user_id()
);
}
}
$query .= ' GROUP BY post_status';
@ -4885,6 +4904,11 @@ function _transition_post_status($new_status, $old_status, $post) {
}
}
if ( $new_status !== $old_status ) {
wp_cache_delete( _count_posts_cache_key( $post->post_type ), 'counts' );
wp_cache_delete( _count_posts_cache_key( $post->post_type, 'readable' ), 'counts' );
}
// Always clears the hook in case the post status bounced from future to draft.
wp_clear_scheduled_hook('publish_future_post', array( $post->ID ) );
}