Skip to content

Commit dee022f

Browse files
ellatrixclaude
andcommitted
Support subtype-registered meta keys in cache invalidation lookup
Search across all registered subtypes when the caller does not provide one, so that keys registered for a specific post type are still found by wp_cache_set_posts_last_changed which only has the meta key. Adds tests for subtype registration. Co-Authored-By: Claude Opus 4.6 <[email protected]>
1 parent 55daa04 commit dee022f

2 files changed

Lines changed: 58 additions & 0 deletions

File tree

src/wp-includes/meta.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1664,6 +1664,8 @@ function registered_meta_key_exists( $object_type, $meta_key, $object_subtype =
16641664
* @return bool True if the meta key invalidates query caches, false otherwise.
16651665
*/
16661666
function wp_meta_key_invalidates_query_cache( $object_type, $meta_key, $object_subtype = '' ) {
1667+
global $wp_meta_keys;
1668+
16671669
$meta_keys = get_registered_meta_keys( $object_type, $object_subtype );
16681670

16691671
if ( isset( $meta_keys[ $meta_key ] ) ) {
@@ -1678,6 +1680,15 @@ function wp_meta_key_invalidates_query_cache( $object_type, $meta_key, $object_s
16781680
}
16791681
}
16801682

1683+
// When no subtype is given, search across all registered subtypes.
1684+
if ( '' === $object_subtype && is_array( $wp_meta_keys ) && isset( $wp_meta_keys[ $object_type ] ) ) {
1685+
foreach ( $wp_meta_keys[ $object_type ] as $registered_keys ) {
1686+
if ( isset( $registered_keys[ $meta_key ] ) ) {
1687+
return $registered_keys[ $meta_key ]['invalidates_query_cache'];
1688+
}
1689+
}
1690+
}
1691+
16811692
// Unregistered keys default to invalidating caches.
16821693
return true;
16831694
}

tests/phpunit/tests/meta/invalidatesQueryCache.php

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ public static function wpTearDownAfterClass() {
2121

2222
public function tear_down() {
2323
unregister_meta_key( 'post', 'nocache_meta' );
24+
unregister_meta_key( 'post', 'nocache_meta', 'post' );
2425
unregister_meta_key( 'post', 'normal_meta' );
2526
parent::tear_down();
2627
}
@@ -193,4 +194,50 @@ public function test_meta_query_allows_regular_key() {
193194

194195
$this->assertStringContainsString( 'some_regular_key', $sql['where'], 'Regular meta key should appear in WHERE clause.' );
195196
}
197+
198+
/**
199+
* A key registered for a specific post type should skip cache invalidation.
200+
*/
201+
public function test_subtype_registration_skips_cache_invalidation() {
202+
register_post_meta(
203+
'post',
204+
'nocache_meta',
205+
array( 'invalidates_query_cache' => false )
206+
);
207+
208+
wp_cache_set_last_changed( 'posts' );
209+
$before = wp_cache_get_last_changed( 'posts' );
210+
211+
usleep( 1000 );
212+
add_post_meta( self::$post_id, 'nocache_meta', 'value1' );
213+
214+
$after = wp_cache_get_last_changed( 'posts' );
215+
$this->assertSame( $before, $after, 'last_changed should not change for non-cacheable meta registered on a specific post type.' );
216+
}
217+
218+
/**
219+
* A key registered for a specific post type should be refused in meta queries.
220+
*
221+
* @expectedIncorrectUsage WP_Meta_Query::get_sql_for_clause
222+
*/
223+
public function test_subtype_registration_refuses_meta_query() {
224+
register_post_meta(
225+
'post',
226+
'nocache_meta',
227+
array( 'invalidates_query_cache' => false )
228+
);
229+
230+
$meta_query = new WP_Meta_Query(
231+
array(
232+
array(
233+
'key' => 'nocache_meta',
234+
'value' => 'test',
235+
),
236+
)
237+
);
238+
239+
$sql = $meta_query->get_sql( 'post', 'wp_posts', 'ID' );
240+
241+
$this->assertStringNotContainsString( 'nocache_meta', $sql['where'], 'Non-cacheable meta key should not appear in WHERE clause.' );
242+
}
196243
}

0 commit comments

Comments
 (0)