Query: Improve WP_Query's cache key generation for taxonomy queries.

Modify how `WP_Query` determines whether a database query contains a taxonomy component and accounts for term changes when generating the cache key. This presents a stale cache been used under some circumstances.

Props Chouby, costdev, peterwilsoncc.
See #22176.



git-svn-id: https://develop.svn.wordpress.org/trunk@54111 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Peter Wilson 2022-09-09 02:04:18 +00:00
parent 42d3773de9
commit 48f17267fb
2 changed files with 92 additions and 1 deletions

View File

@ -3094,7 +3094,7 @@ class WP_Query {
$key = md5( serialize( $cache_args ) . $new_request );
$last_changed = wp_cache_get_last_changed( 'posts' );
if ( ! empty( $this->tax_query->queried_terms ) ) {
if ( ! empty( $this->tax_query->queries ) ) {
$last_changed .= wp_cache_get_last_changed( 'terms' );
}

View File

@ -2,6 +2,7 @@
/**
* @group query
* @covers WP_Query::get_posts
*/
class Test_Query_CacheResults extends WP_UnitTestCase {
/**
@ -893,4 +894,94 @@ class Test_Query_CacheResults extends WP_UnitTestCase {
$this->assertEmpty( $posts2 );
$this->assertNotSame( $query1->found_posts, $query2->found_posts );
}
/**
* @ticket 22176
*/
public function test_query_cache_should_exclude_post_with_excluded_term() {
$term_id = self::$t1;
// Post 0 has the term applied
$post_id = self::$posts[0];
$args = array(
'fields' => 'ids',
'tax_query' => array(
array(
'taxonomy' => 'category',
'terms' => array( $term_id ),
'operator' => 'NOT IN',
),
),
);
$post_ids_q1 = get_posts( $args );
$this->assertNotContains( $post_id, $post_ids_q1, 'First query includes the post ID.' );
$num_queries = get_num_queries();
$post_ids_q2 = get_posts( $args );
$this->assertNotContains( $post_id, $post_ids_q2, 'Second query includes the post ID.' );
$this->assertSame( $num_queries, get_num_queries(), 'Second query is not cached.' );
}
/**
* @ticket 22176
*/
public function test_query_cache_should_exclude_post_when_excluded_term_is_added_after_caching() {
$term_id = self::$t1;
// Post 1 does not have the term applied.
$post_id = self::$posts[1];
$args = array(
'fields' => 'ids',
'tax_query' => array(
array(
'taxonomy' => 'category',
'terms' => array( $term_id ),
'operator' => 'NOT IN',
),
),
);
$post_ids_q1 = get_posts( $args );
$this->assertContains( $post_id, $post_ids_q1, 'First query does not include the post ID.' );
wp_set_object_terms( $post_id, array( $term_id ), 'category' );
$num_queries = get_num_queries();
$post_ids_q2 = get_posts( $args );
$this->assertNotContains( $post_id, $post_ids_q2, 'Second query includes the post ID.' );
$this->assertNotSame( $num_queries, get_num_queries(), 'Applying term does not invalidate previous cache.' );
}
/**
* @ticket 22176
*/
public function test_query_cache_should_not_exclude_post_when_excluded_term_is_removed_after_caching() {
$term_id = self::$t1;
// Post 0 has the term applied.
$post_id = self::$posts[0];
$args = array(
'fields' => 'ids',
'tax_query' => array(
array(
'taxonomy' => 'category',
'terms' => array( $term_id ),
'operator' => 'NOT IN',
),
),
);
$post_ids_q1 = get_posts( $args );
$this->assertNotContains( $post_id, $post_ids_q1, 'First query includes the post ID.' );
// Clear the post of terms.
wp_set_object_terms( $post_id, array(), 'category' );
$num_queries = get_num_queries();
$post_ids_q2 = get_posts( $args );
$this->assertContains( $post_id, $post_ids_q2, 'Second query does not include the post ID.' );
$this->assertNotSame( $num_queries, get_num_queries(), 'Removing term does not invalidate previous cache.' );
}
}