From 4830eeb9ad34ddac3145ff2ace8ba98a14ac2330 Mon Sep 17 00:00:00 2001 From: Scott Taylor Date: Mon, 3 Feb 2014 19:42:13 +0000 Subject: [PATCH] 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 --- wp-includes/post.php | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/wp-includes/post.php b/wp-includes/post.php index 7c537f9eab..02cc7d5a5e 100644 --- a/wp-includes/post.php +++ b/wp-includes/post.php @@ -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 ) ); }