Make WordPress Core

Changeset 27081


Ignore:
Timestamp:
02/03/2014 07:41:40 PM (11 years ago)
Author:
wonderboymusic
Message:

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.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/post.php

    r26911 r27081  
    20782078
    20792079/**
     2080 * Return the cache key for wp_count_posts() based on the passed arguments
     2081 *
     2082 * @since 3.9.0
     2083 *
     2084 * @param string $type Optional. Post type to retrieve count
     2085 * @param string $perm Optional. 'readable' or empty.
     2086 * @return string The cache key.
     2087 */
     2088function _count_posts_cache_key( $type = 'post', $perm = '' ) {
     2089    $cache_key = 'posts-' . $type;
     2090    if ( 'readable' == $perm && is_user_logged_in() ) {
     2091        $post_type_object = get_post_type_object( $type );
     2092        if ( ! current_user_can( $post_type_object->cap->read_private_posts ) ) {
     2093            $cache_key .= '_' . $perm . '_' . get_current_user_id();
     2094        }
     2095    }
     2096    return $cache_key;
     2097}
     2098
     2099/**
    20802100 * Count number of posts of a post type and if user has permissions to view.
    20812101 *
     
    21022122        return new stdClass;
    21032123
    2104     $user = wp_get_current_user();
    2105 
    2106     $cache_key = 'posts-' . $type;
     2124    $cache_key = _count_posts_cache_key( $type, $perm );
    21072125
    21082126    $query = "SELECT post_status, COUNT( * ) AS num_posts FROM {$wpdb->posts} WHERE post_type = %s";
    21092127    if ( 'readable' == $perm && is_user_logged_in() ) {
    21102128        $post_type_object = get_post_type_object($type);
    2111         if ( !current_user_can( $post_type_object->cap->read_private_posts ) ) {
    2112             $cache_key .= '_' . $perm . '_' . $user->ID;
    2113             $query .= " AND (post_status != 'private' OR ( post_author = '$user->ID' AND post_status = 'private' ))";
     2129        if ( ! current_user_can( $post_type_object->cap->read_private_posts ) ) {
     2130            $query .= $wpdb->prepare( " AND (post_status != 'private' OR ( post_author = %d AND post_status = 'private' ))",
     2131                get_current_user_id()
     2132            );
    21142133        }
    21152134    }
     
    48864905    }
    48874906
     4907    if ( $new_status !== $old_status ) {
     4908        wp_cache_delete( _count_posts_cache_key( $post->post_type ), 'counts' );
     4909        wp_cache_delete( _count_posts_cache_key( $post->post_type, 'readable' ), 'counts' );
     4910    }
     4911
    48884912    // Always clears the hook in case the post status bounced from future to draft.
    48894913    wp_clear_scheduled_hook('publish_future_post', array( $post->ID ) );
  • trunk/tests/phpunit/tests/post.php

    r25975 r27081  
    830830        return $counts;
    831831    }
     832
     833    function test_wp_count_posts_insert_invalidation() {
     834        $post_ids = $this->factory->post->create_many( 10 );
     835        $initial_counts = wp_count_posts();
     836
     837        $key = array_rand( $post_ids );
     838        $_post = get_post( $post_ids[$key], ARRAY_A );
     839        $_post['post_status'] = 'draft';
     840        wp_insert_post( $_post );
     841        $post = get_post( $post_ids[$key] );
     842        $this->assertEquals( 'draft', $post->post_status );
     843        $this->assertNotEquals( 'publish', $post->post_status );
     844
     845        $after_draft_counts = wp_count_posts();
     846        $this->assertEquals( 1, $after_draft_counts->draft );
     847        $this->assertEquals( 9, $after_draft_counts->publish );
     848        $this->assertNotEquals( $initial_counts->publish, $after_draft_counts->publish );
     849    }
     850
     851    function test_wp_count_posts_trash_invalidation() {
     852        $post_ids = $this->factory->post->create_many( 10 );
     853        $initial_counts = wp_count_posts();
     854
     855        $key = array_rand( $post_ids );
     856
     857        wp_trash_post( $post_ids[$key] );
     858
     859        $post = get_post( $post_ids[$key] );
     860        $this->assertEquals( 'trash', $post->post_status );
     861        $this->assertNotEquals( 'publish', $post->post_status );
     862
     863        $after_trash_counts = wp_count_posts();
     864        $this->assertEquals( 1, $after_trash_counts->trash );
     865        $this->assertEquals( 9, $after_trash_counts->publish );
     866        $this->assertNotEquals( $initial_counts->publish, $after_trash_counts->publish );
     867    }
    832868}
Note: See TracChangeset for help on using the changeset viewer.