Skip to content

Commit 401e58f

Browse files
committed
Backport: Add invalidates_query_cache meta parameter (Core PR #11290)
Prevents RTC meta keys (wp_sync_awareness, wp_sync_update) from invalidating the posts cache group's last_changed timestamp on every write. This avoids cache invalidation storms during high-frequency collaborative editing. Uses hook-based interception with a standalone registry since Core's register_meta() cannot be modified. When WordPress 7.0 ships with the native implementation, this backport is automatically disabled via function_exists guard. New file: lib/compat/wordpress-7.0/post-meta-cache.php - gutenberg_register_non_cacheable_post_meta() to register keys - wp_post_meta_invalidates_query_cache() public API - Replaces Core hooks with conditional version that checks registry Modified: lib/compat/wordpress-7.0/collaboration.php - Register RTC meta keys as non-cacheable Modified: lib/load.php - Load post-meta-cache.php before collaboration.php See: https://core.trac.wordpress.org/ticket/64696 See: WordPress/wordpress-develop#11290
1 parent e0fda0e commit 401e58f

3 files changed

Lines changed: 117 additions & 0 deletions

File tree

lib/compat/wordpress-7.0/collaboration.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,22 @@ function gutenberg_rest_api_crdt_post_meta() {
9898
add_action( 'init', 'gutenberg_rest_api_crdt_post_meta' );
9999
}
100100

101+
if ( ! function_exists( 'wp_collaboration_register_non_cacheable_meta' ) ) {
102+
/**
103+
* Registers RTC meta keys as non-cache-invalidating.
104+
*
105+
* These keys are written at high frequency during collaborative editing
106+
* and should not bump the `last_changed` timestamp in the posts cache group.
107+
*
108+
* @since 20.3.0
109+
*/
110+
function gutenberg_collaboration_register_non_cacheable_meta() {
111+
gutenberg_register_non_cacheable_post_meta( 'wp_sync_awareness' );
112+
gutenberg_register_non_cacheable_post_meta( 'wp_sync_update' );
113+
}
114+
add_action( 'init', 'gutenberg_collaboration_register_non_cacheable_meta' );
115+
}
116+
101117
if ( ! function_exists( 'wp_collaboration_inject_setting' ) ) {
102118
/**
103119
* Registers the real-time collaboration setting.
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
<?php
2+
/**
3+
* Post meta cache invalidation control.
4+
*
5+
* Backports the `invalidates_query_cache` parameter from WordPress Core.
6+
* Allows specific post meta keys to be marked as non-cache-invalidating,
7+
* preventing unnecessary `last_changed` bumps in the posts cache group.
8+
*
9+
* @package gutenberg
10+
* @since 20.3.0
11+
*
12+
* @see https://core.trac.wordpress.org/ticket/64696
13+
* @see https://github.com/WordPress/wordpress-develop/pull/11290
14+
*/
15+
16+
if ( ! function_exists( 'wp_post_meta_invalidates_query_cache' ) ) {
17+
18+
/**
19+
* Manages the registry of non-cache-invalidating post meta keys.
20+
*
21+
* When called with a meta key, registers it as non-cacheable.
22+
* Always returns the full list of registered keys.
23+
*
24+
* @since 20.3.0
25+
* @access private
26+
*
27+
* @param string|null $meta_key Optional. Meta key to register. Default null.
28+
* @return string[] Array of non-cacheable meta keys.
29+
*/
30+
function gutenberg_non_cacheable_post_meta_keys( $meta_key = null ) {
31+
static $keys = array();
32+
33+
if ( null !== $meta_key && ! in_array( $meta_key, $keys, true ) ) {
34+
$keys[] = $meta_key;
35+
}
36+
37+
return $keys;
38+
}
39+
40+
/**
41+
* Registers a post meta key as non-cache-invalidating.
42+
*
43+
* Meta keys registered this way will not bump the `last_changed`
44+
* timestamp in the `posts` cache group when added, updated, or deleted.
45+
*
46+
* @since 20.3.0
47+
*
48+
* @param string $meta_key Meta key to register as non-cacheable.
49+
*/
50+
function gutenberg_register_non_cacheable_post_meta( $meta_key ) {
51+
gutenberg_non_cacheable_post_meta_keys( $meta_key );
52+
}
53+
54+
/**
55+
* Checks whether a post meta key invalidates query caches when updated.
56+
*
57+
* Unregistered meta keys are assumed to invalidate query caches.
58+
*
59+
* @since 20.3.0
60+
*
61+
* @param string $meta_key Metadata key.
62+
* @param string $post_type Post type to check. Not used in the backport
63+
* but included for API compatibility with Core.
64+
* @return bool True if the meta key invalidates query caches, false otherwise.
65+
*/
66+
function wp_post_meta_invalidates_query_cache( $meta_key, $post_type = '' ) {
67+
$non_cacheable = gutenberg_non_cacheable_post_meta_keys();
68+
return ! in_array( $meta_key, $non_cacheable, true );
69+
}
70+
71+
/**
72+
* Conditionally sets the last changed time for the 'posts' cache group.
73+
*
74+
* Skips cache invalidation for meta keys registered as non-cacheable
75+
* via `gutenberg_register_non_cacheable_post_meta()`.
76+
*
77+
* @since 20.3.0
78+
*
79+
* @param int $meta_id Meta ID.
80+
* @param int $object_id Object ID.
81+
* @param string $meta_key Meta key.
82+
*/
83+
function gutenberg_cache_set_posts_last_changed( $meta_id, $object_id, $meta_key ) {
84+
if ( $meta_key && ! wp_post_meta_invalidates_query_cache( $meta_key ) ) {
85+
return;
86+
}
87+
88+
wp_cache_set_posts_last_changed();
89+
}
90+
91+
// Replace Core's unconditional cache invalidation hooks with the
92+
// conditional version that checks the meta key registry.
93+
remove_action( 'added_post_meta', 'wp_cache_set_posts_last_changed' );
94+
remove_action( 'updated_post_meta', 'wp_cache_set_posts_last_changed' );
95+
remove_action( 'deleted_post_meta', 'wp_cache_set_posts_last_changed' );
96+
97+
add_action( 'added_post_meta', 'gutenberg_cache_set_posts_last_changed', 10, 3 );
98+
add_action( 'updated_post_meta', 'gutenberg_cache_set_posts_last_changed', 10, 3 );
99+
add_action( 'deleted_post_meta', 'gutenberg_cache_set_posts_last_changed', 10, 3 );
100+
}

lib/load.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ function gutenberg_is_experiment_enabled( $name ) {
7272
require __DIR__ . '/compat/wordpress-7.0/class-gutenberg-rest-static-templates-controller.php';
7373
require __DIR__ . '/compat/wordpress-7.0/class-wp-icons-registry.php';
7474
require __DIR__ . '/compat/wordpress-7.0/class-wp-rest-icons-controller.php';
75+
require __DIR__ . '/compat/wordpress-7.0/post-meta-cache.php';
7576
require __DIR__ . '/compat/wordpress-7.0/collaboration.php';
7677
require __DIR__ . '/compat/wordpress-7.0/template-activate.php';
7778
require __DIR__ . '/compat/wordpress-7.0/rest-api.php';

0 commit comments

Comments
 (0)