Skip to content
Closed
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
e440510
Replace direct cache operations with query-specific functions
spacedmonkey May 23, 2025
43f7a9e
Check key exists
spacedmonkey May 28, 2025
d13fe90
Check values.
spacedmonkey May 28, 2025
015e4f6
Change wp_cache_set_multiple_query_data
spacedmonkey May 28, 2025
17348ec
Learn to spell, Jonny
spacedmonkey May 28, 2025
e6440f1
Replace `wp_cache_set` with `wp_cache_set_query_data` in `class-wp-qu…
spacedmonkey May 28, 2025
f90fdbb
Refactor cache key handling in `class-wp-query` for improved clarity …
spacedmonkey May 28, 2025
d6eba79
Add expiration support to `wp_cache_set_query_data` and `wp_cache_set…
spacedmonkey Jun 5, 2025
552e6d5
Merge branch 'trunk' into fix/last-updated
spacedmonkey Jun 18, 2025
71578aa
Move query cache functions to `cache-compat.php` for better compatibi…
spacedmonkey Jun 18, 2025
39e6880
Update tests/phpunit/tests/functions/wpCacheSetQueryData.php
spacedmonkey Jun 18, 2025
f017cc0
Fix comments on tests
spacedmonkey Jun 18, 2025
6869363
Apply suggestions from code review
spacedmonkey Jul 8, 2025
6387897
Merge branch 'trunk' into fix/last-updated
spacedmonkey Jul 9, 2025
49cc290
Refactor `class-wp-user-query` to move cache timestamp handling to a …
spacedmonkey Jul 9, 2025
11605cf
Refactor `class-wp-user-query` to simplify `$blog_id` initialization …
spacedmonkey Jul 9, 2025
199703a
Refactor `class-wp-user-query` to simplify `$blog_id` initialization …
spacedmonkey Jul 9, 2025
c7b5e4d
Clarify documentation for `last_changed` parameter in query cache fun…
spacedmonkey Jul 9, 2025
0675270
Update src/wp-includes/cache-compat.php
jonnynews Jul 11, 2025
0c295ed
Merge branch 'trunk' into fix/last-updated
spacedmonkey Jul 22, 2025
20ea1fa
Rename query cache functions to use `salted` naming convention, updat…
spacedmonkey Jul 22, 2025
6807090
Refactor `last_changed` handling in `WP_Query` to use array structure…
spacedmonkey Jul 22, 2025
5d61bf7
Fix conditional logic for `isset` checks in query cache validation fo…
spacedmonkey Jul 22, 2025
e3b2eb4
Refactor query cache tests to replace `last_changed` with `salt` for …
spacedmonkey Jul 22, 2025
d1248c6
Update PHPUnit test to expect `salt` instead of `last_changed` for qu…
spacedmonkey Jul 22, 2025
42b3dee
Refactor PHPUnit tests for query cache to use `salted` naming convent…
spacedmonkey Jul 22, 2025
38a28a2
Feedback on @peterwilsoncc.
spacedmonkey Jul 23, 2025
bd142f1
Docs standards fixes.
peterwilsoncc Jul 23, 2025
12a45c7
API consistency: return success/failure results of setting cache.
peterwilsoncc Jul 23, 2025
238c41e
Apply suggestions from code review
peterwilsoncc Aug 18, 2025
df2dabf
Merge branch 'trunk' into fix/last-updated
peterwilsoncc Aug 18, 2025
45909c6
Update src/wp-includes/cache-compat.php
peterwilsoncc Aug 20, 2025
9b390e1
Merge branch 'trunk' into fix/last-updated
spacedmonkey Aug 22, 2025
310b0de
Merge branch 'trunk' into fix/last-updated
spacedmonkey Aug 31, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 113 additions & 0 deletions src/wp-includes/cache-compat.php
Original file line number Diff line number Diff line change
Expand Up @@ -199,3 +199,116 @@ function wp_cache_supports( $feature ) {
return false;
}
endif;

if ( ! function_exists( 'wp_cache_get_salted' ) ) :
/**
* Retrieves cached query data if valid and unchanged.
*
* @since 6.9.0
*
* @param string $cache_key The cache key used for storage and retrieval.
* @param string $group The cache group used for organizing data.
* @param string|string[] $salt The timestamp (or multiple timestamps if an array) indicating when the cache group(s) were last updated.
* @return mixed|false The cached data if valid, or false if the cache does not exist or is outdated.
*/
function wp_cache_get_salted( $cache_key, $group, $salt ) {
$salt = is_array( $salt ) ? implode( ':', $salt ) : $salt;
$cache = wp_cache_get( $cache_key, $group );

if ( ! is_array( $cache ) ) {
return false;
}

if ( ! isset( $cache['salt'] ) || ! isset( $cache['data'] ) || $salt !== $cache['salt'] ) {
return false;
}

return $cache['data'];
}
endif;

if ( ! function_exists( 'wp_cache_set_salted' ) ) :
/**
* Stores query-related data in the cache.
*
* @since 6.9.0
*
* @param string $cache_key The cache key under which to store the data.
* @param mixed $data The data to be cached.
* @param string $group The cache group to which the data belongs.
* @param string|string[] $salt The timestamp (or multiple timestamps if an array) indicating when the cache group(s) were last updated.
* @param int $expire Optional. When to expire the cache contents, in seconds.
* Default 0 (no expiration).
* @return bool True on success, false on failure.
*/
function wp_cache_set_salted( $cache_key, $data, $group, $salt, $expire = 0 ) {
$salt = is_array( $salt ) ? implode( ':', $salt ) : $salt;
return wp_cache_set(
$cache_key,
array(
'data' => $data,
'salt' => $salt,
),
$group,
$expire
);
}
endif;

if ( ! function_exists( 'wp_cache_get_multiple_salted' ) ) :
/**
* Retrieves multiple items from the cache and validates their freshness.
*
* @since 6.9.0
*
* @param array $cache_keys Array of cache keys to retrieve.
* @param string $group The group of the cache to check.
* @param string|string[] $salt The timestamp (or multiple timestamps if an array) indicating when the cache group(s) were last updated.
* @return array An associative array containing cache values. Values are `false` if they are not found or outdated.
*/
function wp_cache_get_multiple_salted( $cache_keys, $group, $salt ) {
$salt = is_array( $salt ) ? implode( ':', $salt ) : $salt;
$cache = wp_cache_get_multiple( $cache_keys, $group );

foreach ( $cache as $key => $value ) {
if ( ! is_array( $value ) ) {
$cache[ $key ] = false;
continue;
}
if ( ! isset( $value['salt'], $value['data'] ) || $salt !== $value['salt'] ) {
$cache[ $key ] = false;
continue;
}
$cache[ $key ] = $value['data'];
}

return $cache;
}
endif;

if ( ! function_exists( 'wp_cache_set_multiple_salted' ) ) :
/**
* Stores multiple pieces of query data in the cache.
*
* @since 6.9.0
*
* @param mixed $data Data to be stored in the cache for all keys.
* @param string $group Group to which the cached data belongs.
* @param string|string[] $salt The timestamp (or multiple timestamps if an array) indicating when the cache group(s) were last updated.
* @param int $expire Optional. When to expire the cache contents, in seconds.
* Default 0 (no expiration).
* @return bool[] Array of return values, grouped by key. Each value is either
* true on success, or false on failure.
*/
function wp_cache_set_multiple_salted( $data, $group, $salt, $expire = 0 ) {
$salt = is_array( $salt ) ? implode( ':', $salt ) : $salt;
$new_cache = array();
foreach ( $data as $key => $value ) {
$new_cache[ $key ] = array(
'data' => $value,
'salt' => $salt,
);
}
return wp_cache_set_multiple( $new_cache, $group, $expire );
}
endif;
14 changes: 7 additions & 7 deletions src/wp-includes/class-wp-comment-query.php
Original file line number Diff line number Diff line change
Expand Up @@ -451,8 +451,8 @@ public function get_comments() {
$key = md5( serialize( $_args ) );
$last_changed = wp_cache_get_last_changed( 'comment' );

$cache_key = "get_comments:$key:$last_changed";
$cache_value = wp_cache_get( $cache_key, 'comment-queries' );
$cache_key = "get_comments:$key";
$cache_value = wp_cache_get_salted( $cache_key, 'comment-queries', $last_changed );
if ( false === $cache_value ) {
$comment_ids = $this->get_comment_ids();
if ( $comment_ids ) {
Expand All @@ -463,7 +463,7 @@ public function get_comments() {
'comment_ids' => $comment_ids,
'found_comments' => $this->found_comments,
);
wp_cache_add( $cache_key, $cache_value, 'comment-queries' );
wp_cache_set_salted( $cache_key, $cache_value, 'comment-queries', $last_changed );
} else {
$comment_ids = $cache_value['comment_ids'];
$this->found_comments = $cache_value['found_comments'];
Expand Down Expand Up @@ -1044,9 +1044,9 @@ protected function fill_descendants( $comments ) {
if ( $_parent_ids ) {
$cache_keys = array();
foreach ( $_parent_ids as $parent_id ) {
$cache_keys[ $parent_id ] = "get_comment_child_ids:$parent_id:$key:$last_changed";
$cache_keys[ $parent_id ] = "get_comment_child_ids:$parent_id:$key";
}
$cache_data = wp_cache_get_multiple( array_values( $cache_keys ), 'comment-queries' );
$cache_data = wp_cache_get_multiple_salted( array_values( $cache_keys ), 'comment-queries', $last_changed );
foreach ( $_parent_ids as $parent_id ) {
$parent_child_ids = $cache_data[ $cache_keys[ $parent_id ] ];
if ( false !== $parent_child_ids ) {
Expand Down Expand Up @@ -1080,10 +1080,10 @@ protected function fill_descendants( $comments ) {

$data = array();
foreach ( $parent_map as $parent_id => $children ) {
$cache_key = "get_comment_child_ids:$parent_id:$key:$last_changed";
$cache_key = "get_comment_child_ids:$parent_id:$key";
$data[ $cache_key ] = $children;
}
wp_cache_set_multiple( $data, 'comment-queries' );
wp_cache_set_multiple_salted( $data, 'comment-queries', $last_changed );
}

++$level;
Expand Down
6 changes: 3 additions & 3 deletions src/wp-includes/class-wp-network-query.php
Original file line number Diff line number Diff line change
Expand Up @@ -249,8 +249,8 @@ public function get_networks() {
$key = md5( serialize( $_args ) );
$last_changed = wp_cache_get_last_changed( 'networks' );

$cache_key = "get_network_ids:$key:$last_changed";
$cache_value = wp_cache_get( $cache_key, 'network-queries' );
$cache_key = "get_network_ids:$key";
$cache_value = wp_cache_get_salted( $cache_key, 'network-queries', $last_changed );

if ( false === $cache_value ) {
$network_ids = $this->get_network_ids();
Expand All @@ -262,7 +262,7 @@ public function get_networks() {
'network_ids' => $network_ids,
'found_networks' => $this->found_networks,
);
wp_cache_add( $cache_key, $cache_value, 'network-queries' );
wp_cache_set_salted( $cache_key, $cache_value, 'network-queries', $last_changed );
} else {
$network_ids = $cache_value['network_ids'];
$this->found_networks = $cache_value['found_networks'];
Expand Down
38 changes: 21 additions & 17 deletions src/wp-includes/class-wp-query.php
Original file line number Diff line number Diff line change
Expand Up @@ -2882,13 +2882,16 @@ public function get_posts() {
$comments_request = "SELECT $distinct {$wpdb->comments}.comment_ID FROM {$wpdb->comments} $cjoin $cwhere $cgroupby $corderby $climits";

$key = md5( $comments_request );
$last_changed = wp_cache_get_last_changed( 'comment' ) . ':' . wp_cache_get_last_changed( 'posts' );
$last_changed = array(
wp_cache_get_last_changed( 'comment' ),
wp_cache_get_last_changed( 'posts' ),
);

$cache_key = "comment_feed:$key:$last_changed";
$comment_ids = wp_cache_get( $cache_key, 'comment-queries' );
$cache_key = "comment_feed:$key";
$comment_ids = wp_cache_get_salted( $cache_key, 'comment-queries', $last_changed );
if ( false === $comment_ids ) {
$comment_ids = $wpdb->get_col( $comments_request );
wp_cache_add( $cache_key, $comment_ids, 'comment-queries' );
wp_cache_set_salted( $cache_key, $comment_ids, 'comment-queries', $last_changed );
}
_prime_comment_caches( $comment_ids );

Expand Down Expand Up @@ -3246,15 +3249,21 @@ public function get_posts() {
$id_query_is_cacheable = false;
}

$last_changed = (array) wp_cache_get_last_changed( 'posts' );
if ( ! empty( $this->tax_query->queries ) ) {
$last_changed[] = wp_cache_get_last_changed( 'terms' );
}

if ( $q['cache_results'] && $id_query_is_cacheable ) {
$new_request = str_replace( $fields, "{$wpdb->posts}.*", $this->request );
$cache_key = $this->generate_cache_key( $q, $new_request );

$cache_found = false;
if ( null === $this->posts ) {
$cached_results = wp_cache_get( $cache_key, 'post-queries', false, $cache_found );
$cached_results = wp_cache_get_salted( $cache_key, 'post-queries', $last_changed );

if ( $cached_results ) {
$cache_found = true;
/** @var int[] */
$post_ids = array_map( 'intval', $cached_results['posts'] );

Expand Down Expand Up @@ -3312,7 +3321,7 @@ public function get_posts() {
'max_num_pages' => $this->max_num_pages,
);

wp_cache_set( $cache_key, $cache_value, 'post-queries' );
wp_cache_set_salted( $cache_key, $cache_value, 'post-queries', $last_changed );
}

return $this->posts;
Expand Down Expand Up @@ -3350,7 +3359,7 @@ public function get_posts() {
'max_num_pages' => $this->max_num_pages,
);

wp_cache_set( $cache_key, $cache_value, 'post-queries' );
wp_cache_set_salted( $cache_key, $cache_value, 'post-queries', $last_changed );
}

return $post_parents;
Expand Down Expand Up @@ -3448,7 +3457,7 @@ public function get_posts() {
'max_num_pages' => $this->max_num_pages,
);

wp_cache_set( $cache_key, $cache_value, 'post-queries' );
wp_cache_set_salted( $cache_key, $cache_value, 'post-queries', $last_changed );
}

if ( ! $q['suppress_filters'] ) {
Expand Down Expand Up @@ -3486,11 +3495,11 @@ public function get_posts() {
$comment_key = md5( $comments_request );
$comment_last_changed = wp_cache_get_last_changed( 'comment' );

$comment_cache_key = "comment_feed:$comment_key:$comment_last_changed";
$comment_ids = wp_cache_get( $comment_cache_key, 'comment-queries' );
$comment_cache_key = "comment_feed:$comment_key";
$comment_ids = wp_cache_get_salted( $comment_cache_key, 'comment-queries', $comment_last_changed );
if ( false === $comment_ids ) {
$comment_ids = $wpdb->get_col( $comments_request );
wp_cache_add( $comment_cache_key, $comment_ids, 'comment-queries' );
wp_cache_set_salted( $comment_cache_key, $comment_ids, 'comment-queries', $comment_last_changed );
}
_prime_comment_caches( $comment_ids );

Expand Down Expand Up @@ -5062,12 +5071,7 @@ static function ( &$value ) use ( $wpdb, $placeholder ) {
$sql = $wpdb->remove_placeholder_escape( $sql );
$key = md5( serialize( $args ) . $sql );

$last_changed = wp_cache_get_last_changed( 'posts' );
if ( ! empty( $this->tax_query->queries ) ) {
$last_changed .= wp_cache_get_last_changed( 'terms' );
}

$this->query_cache_key = "wp_query:$key:$last_changed";
$this->query_cache_key = "wp_query:$key";
return $this->query_cache_key;
}

Expand Down
6 changes: 3 additions & 3 deletions src/wp-includes/class-wp-site-query.php
Original file line number Diff line number Diff line change
Expand Up @@ -357,8 +357,8 @@ public function get_sites() {
$key = md5( serialize( $_args ) );
$last_changed = wp_cache_get_last_changed( 'sites' );

$cache_key = "get_sites:$key:$last_changed";
$cache_value = wp_cache_get( $cache_key, 'site-queries' );
$cache_key = "get_sites:$key";
$cache_value = wp_cache_get_salted( $cache_key, 'site-queries', $last_changed );

if ( false === $cache_value ) {
$site_ids = $this->get_site_ids();
Expand All @@ -370,7 +370,7 @@ public function get_sites() {
'site_ids' => $site_ids,
'found_sites' => $this->found_sites,
);
wp_cache_add( $cache_key, $cache_value, 'site-queries' );
wp_cache_set_salted( $cache_key, $cache_value, 'site-queries', $last_changed );
} else {
$site_ids = $cache_value['site_ids'];
$this->found_sites = $cache_value['found_sites'];
Expand Down
17 changes: 9 additions & 8 deletions src/wp-includes/class-wp-term-query.php
Original file line number Diff line number Diff line change
Expand Up @@ -777,8 +777,9 @@ public function get_terms() {
}

if ( $args['cache_results'] ) {
$cache_key = $this->generate_cache_key( $args, $this->request );
$cache = wp_cache_get( $cache_key, 'term-queries' );
$cache_key = $this->generate_cache_key( $args, $this->request );
$last_changed = wp_cache_get_last_changed( 'terms' );
$cache = wp_cache_get_salted( $cache_key, 'term-queries', $last_changed );

if ( false !== $cache ) {
if ( 'ids' === $_fields ) {
Expand Down Expand Up @@ -806,7 +807,7 @@ public function get_terms() {
if ( 'count' === $_fields ) {
$count = $wpdb->get_var( $this->request ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
if ( $args['cache_results'] ) {
wp_cache_set( $cache_key, $count, 'term-queries' );
wp_cache_set_salted( $cache_key, $count, 'term-queries', $last_changed );
}
return $count;
}
Expand All @@ -815,7 +816,7 @@ public function get_terms() {

if ( empty( $terms ) ) {
if ( $args['cache_results'] ) {
wp_cache_add( $cache_key, array(), 'term-queries' );
wp_cache_set_salted( $cache_key, array(), 'term-queries', $last_changed );
}
return array();
}
Expand Down Expand Up @@ -899,7 +900,7 @@ public function get_terms() {
}

if ( $args['cache_results'] ) {
wp_cache_add( $cache_key, $term_cache, 'term-queries' );
wp_cache_set_salted( $cache_key, $term_cache, 'term-queries', $last_changed );
}

$this->terms = $this->format_terms( $term_objects, $_fields );
Expand Down Expand Up @@ -1171,8 +1172,8 @@ protected function generate_cache_key( array $args, $sql ) {
// Replace wpdb placeholder in the SQL statement used by the cache key.
$sql = $wpdb->remove_placeholder_escape( $sql );

$key = md5( serialize( $cache_args ) . $sql );
$last_changed = wp_cache_get_last_changed( 'terms' );
return "get_terms:$key:$last_changed";
$key = md5( serialize( $cache_args ) . $sql );

return "get_terms:$key";
}
}
Loading
Loading