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. git-svn-id: https://develop.svn.wordpress.org/trunk@27081 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
parent
9fd8c54ef9
commit
28bab15d16
|
@ -2076,6 +2076,26 @@ function unstick_post($post_id) {
|
||||||
update_option('sticky_posts', $stickies);
|
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.
|
* 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 ) )
|
if ( ! post_type_exists( $type ) )
|
||||||
return new stdClass;
|
return new stdClass;
|
||||||
|
|
||||||
$user = wp_get_current_user();
|
$cache_key = _count_posts_cache_key( $type, $perm );
|
||||||
|
|
||||||
$cache_key = 'posts-' . $type;
|
|
||||||
|
|
||||||
$query = "SELECT post_status, COUNT( * ) AS num_posts FROM {$wpdb->posts} WHERE post_type = %s";
|
$query = "SELECT post_status, COUNT( * ) AS num_posts FROM {$wpdb->posts} WHERE post_type = %s";
|
||||||
if ( 'readable' == $perm && is_user_logged_in() ) {
|
if ( 'readable' == $perm && is_user_logged_in() ) {
|
||||||
$post_type_object = get_post_type_object($type);
|
$post_type_object = get_post_type_object($type);
|
||||||
if ( !current_user_can( $post_type_object->cap->read_private_posts ) ) {
|
if ( ! current_user_can( $post_type_object->cap->read_private_posts ) ) {
|
||||||
$cache_key .= '_' . $perm . '_' . $user->ID;
|
$query .= $wpdb->prepare( " AND (post_status != 'private' OR ( post_author = %d AND post_status = 'private' ))",
|
||||||
$query .= " AND (post_status != 'private' OR ( post_author = '$user->ID' AND post_status = 'private' ))";
|
get_current_user_id()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$query .= ' GROUP BY post_status';
|
$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.
|
// Always clears the hook in case the post status bounced from future to draft.
|
||||||
wp_clear_scheduled_hook('publish_future_post', array( $post->ID ) );
|
wp_clear_scheduled_hook('publish_future_post', array( $post->ID ) );
|
||||||
}
|
}
|
||||||
|
|
|
@ -829,4 +829,40 @@ class Tests_Post extends WP_UnitTestCase {
|
||||||
$counts->publish = 7;
|
$counts->publish = 7;
|
||||||
return $counts;
|
return $counts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function test_wp_count_posts_insert_invalidation() {
|
||||||
|
$post_ids = $this->factory->post->create_many( 10 );
|
||||||
|
$initial_counts = wp_count_posts();
|
||||||
|
|
||||||
|
$key = array_rand( $post_ids );
|
||||||
|
$_post = get_post( $post_ids[$key], ARRAY_A );
|
||||||
|
$_post['post_status'] = 'draft';
|
||||||
|
wp_insert_post( $_post );
|
||||||
|
$post = get_post( $post_ids[$key] );
|
||||||
|
$this->assertEquals( 'draft', $post->post_status );
|
||||||
|
$this->assertNotEquals( 'publish', $post->post_status );
|
||||||
|
|
||||||
|
$after_draft_counts = wp_count_posts();
|
||||||
|
$this->assertEquals( 1, $after_draft_counts->draft );
|
||||||
|
$this->assertEquals( 9, $after_draft_counts->publish );
|
||||||
|
$this->assertNotEquals( $initial_counts->publish, $after_draft_counts->publish );
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_wp_count_posts_trash_invalidation() {
|
||||||
|
$post_ids = $this->factory->post->create_many( 10 );
|
||||||
|
$initial_counts = wp_count_posts();
|
||||||
|
|
||||||
|
$key = array_rand( $post_ids );
|
||||||
|
|
||||||
|
wp_trash_post( $post_ids[$key] );
|
||||||
|
|
||||||
|
$post = get_post( $post_ids[$key] );
|
||||||
|
$this->assertEquals( 'trash', $post->post_status );
|
||||||
|
$this->assertNotEquals( 'publish', $post->post_status );
|
||||||
|
|
||||||
|
$after_trash_counts = wp_count_posts();
|
||||||
|
$this->assertEquals( 1, $after_trash_counts->trash );
|
||||||
|
$this->assertEquals( 9, $after_trash_counts->publish );
|
||||||
|
$this->assertNotEquals( $initial_counts->publish, $after_trash_counts->publish );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue