Query caches have historically used the last changed timestamp as a salt. While this has proven effective for most sites, it leads to an excessive number of caches which can be problematic on high-traffic and heavily updated sites. WordPress 6.9 introduces changes to how cache keys are created in order to ensure efficient use of object caches and help caches clean up after themselves.
These changes are compatible with existing implementations of persistent caching drop-ins. Vendors are not required to make any changes to their code to support these features in WordPress 6.9. As with other caching functions, the functions are pluggable should vendors wish to optimize for their particular caching implementation. These new functions are:
wp_cache_get_salted( string $cache_key, string $group, string|string[] $salt ): mixed
wp_cache_set_salted( string $cache_key, mixed $data, string $group, string|string[] $salt, int $expire = 0 ): bool
wp_cache_get_multiple_salted( string[] $cache_keys, string $group, string|string[] $salt ): mixed[]
wp_cache_set_multiple_salted( mixed[] $data, string $group, string|string[] $salt, int $expire = 0 ): bool[]
What Behavior is Changing
Previous behavior in WordPress 6.8 and earlier:
- A post object is saved
- WordPress stores the last changed time of the posts table
- WP Query is called
- WordPress caches the database query using a key containing the last changed time
- Another post is saved, updating the posts table’s last changed time
- The previous cache becomes unreachable
- WP Query is called
- WordPress does not see a cached query
- WordPress caches the database query using a new key containing the updated last changed time
New behavior in WordPress 6.9
- A post object is saved
- WordPress stores the last changed time of the posts table
- WP Query is called
- WordPress caches the database query alongside the last changed time
- Another post is saved, updating the posts table’s last changed time
- WP Query is called
- WordPress hits the previously generated cache
- WordPress uses the last changed value to determine if the cache is up-to-date
- WordPress replaces the previously generated cache with the new results
While both operations perform two cache lookups, the new behavior re-uses the existing cache key and does an in memory comparison of the last changed time. This prevents the cache from containing unreachable cache keys.
The same change in behavior applies to other Query classes such as term queries, comment queries, user queries, etc.
Checking/setting query caches directly
Broadly, the caches affected are in the following cache groups:
comment-queries
network-queries
post-queries
site-queries
term-queries
user-queries
The following specific cache keys are affected and will now be different. If you have been directly checking or setting caches that start with the following keys, you will need to adjust your code.
get_comments
get_comment_child_ids
get_network_ids
comment_feed
wp_query
get_sites
wp_get_archives
adjacent_post
get_page_by_path
find_post_by_old_slug
get_objects_in_term
count_user_postscount_user_posts
Additionally, keys that are generated by WP_User_Query:generate_cache_key and WP_Term_Query::generate_cache_key are affected as well. However, these keys are md5 hashes and thus are less likely to be used directly.
When using the new wp_cache_*_salted functions and passing in an array of salts, the order of items in the array must be consistent. If you are using the changed caches in core Core is the set of software required to run WordPress. The Core Development Team builds WordPress., please review the order in core and use the same order to ensure cache hits.
If you need to support multiple versions of WordPress when updating your code, you can use code that looks similar to:
if (function_exists( 'wp_cache_get_salted` ) ){
$data = wp_cache_get_salted( $cache_key, 'comment-queries', $last_changed );
} else {
// your current code here
}
See [60697] for specific examples of how core has been updated and [60941] for an example of how these new functions help cache previously uncached code.
On Upgrade to WordPress 6.9
With the update to cache keys, it’s expected that you may see a short term increase in cache misses upon upgrade. You may wish to preemptively evict the old cache keys in order to prevent stale entries from sticking around, potentially leading to unnecessary evictions based on your cache policies.
For more information, please see #59592.
Props to @desrosj, @peterwilsoncc, and @spacedmonkey for review. Props to @spacedmonkey for comments on the ticket Created for both bug reports and feature development on the bug tracker. that could be easily reused here.
#6-9, #cache-api, #dev-notes, #dev-notes-6-9