22/**
33 * Tests for the `invalidates_query_cache` parameter of `register_meta()`.
44 *
5+ * Cache correctness relies on two complementary mechanisms:
6+ *
7+ * 1. Cache invalidation (wp_cache_set_posts_last_changed): the authoritative
8+ * check. Meta write hooks always provide the object ID, so the post type
9+ * is always known. This guarantees non-cacheable meta never incorrectly
10+ * bumps the 'posts' last_changed timestamp.
11+ *
12+ * 2. Meta query blocking (WP_Meta_Query): a conservative safety net. It only
13+ * refuses a non-cacheable key when the post type is known from the parent
14+ * WP_Query context. Without context, the key is allowed through — it's
15+ * better to allow a query than to incorrectly block a legitimate one.
16+ *
517 * @group meta
618 * @group cache
719 *
@@ -152,7 +164,8 @@ public function test_registered_cacheable_meta_still_invalidates_cache() {
152164 }
153165
154166 /**
155- * WP_Meta_Query should refuse to query by a non-cacheable meta key.
167+ * WP_Meta_Query should refuse to query by a non-cacheable meta key
168+ * when the WP_Query context provides a post type.
156169 *
157170 * @expectedIncorrectUsage WP_Meta_Query::get_sql_for_clause
158171 */
@@ -163,6 +176,9 @@ public function test_meta_query_refuses_non_cacheable_key() {
163176 array ( 'invalidates_query_cache ' => false )
164177 );
165178
179+ $ query = new WP_Query ();
180+ $ query ->query_vars ['post_type ' ] = 'post ' ;
181+
166182 $ meta_query = new WP_Meta_Query (
167183 array (
168184 array (
@@ -172,12 +188,39 @@ public function test_meta_query_refuses_non_cacheable_key() {
172188 )
173189 );
174190
175- $ sql = $ meta_query ->get_sql ( 'post ' , 'wp_posts ' , 'ID ' );
191+ $ sql = $ meta_query ->get_sql ( 'post ' , 'wp_posts ' , 'ID ' , $ query );
176192
177193 $ this ->assertStringNotContainsString ( 'nocache_meta ' , $ sql ['where ' ], 'Non-cacheable meta key should not appear in WHERE clause. ' );
178194 $ this ->assertStringNotContainsString ( 'nocache_meta ' , $ sql ['join ' ], 'Non-cacheable meta key should not appear in JOIN clause. ' );
179195 }
180196
197+ /**
198+ * WP_Meta_Query should allow a non-cacheable meta key when no WP_Query
199+ * context is available. Without knowing the post type, refusing the query
200+ * could incorrectly block legitimate usage. Cache correctness is still
201+ * guaranteed by the invalidation side, which always knows the post type.
202+ */
203+ public function test_meta_query_allows_non_cacheable_key_without_context () {
204+ register_post_meta (
205+ '' ,
206+ 'nocache_meta ' ,
207+ array ( 'invalidates_query_cache ' => false )
208+ );
209+
210+ $ meta_query = new WP_Meta_Query (
211+ array (
212+ array (
213+ 'key ' => 'nocache_meta ' ,
214+ 'value ' => 'test ' ,
215+ ),
216+ )
217+ );
218+
219+ $ sql = $ meta_query ->get_sql ( 'post ' , 'wp_posts ' , 'ID ' );
220+
221+ $ this ->assertStringContainsString ( 'nocache_meta ' , $ sql ['where ' ], 'Non-cacheable meta key should be allowed without WP_Query context. ' );
222+ }
223+
181224 /**
182225 * WP_Meta_Query should work normally for regular meta keys.
183226 */
@@ -248,7 +291,10 @@ public function test_subtype_registration_refuses_meta_query_for_matching_post_t
248291
249292 /**
250293 * A key registered as non-cacheable for one post type should be allowed
251- * in meta queries targeting a different post type.
294+ * in meta queries targeting a different post type. The query-side check
295+ * is conservative — it only refuses when the post type is known to be
296+ * non-cacheable. Cache correctness for the other post type is enforced
297+ * by the invalidation side.
252298 */
253299 public function test_subtype_registration_allows_meta_query_for_different_post_type () {
254300 register_post_meta (
@@ -305,8 +351,10 @@ public function test_subtype_registration_refuses_meta_query_for_array_with_matc
305351 }
306352
307353 /**
308- * A key registered for a specific post type should not skip cache invalidation
309- * when written to a different post type.
354+ * A key registered as non-cacheable for one post type should still
355+ * invalidate the cache when written to a different post type. The
356+ * invalidation side always knows the exact post type from the object ID,
357+ * so per-post-type behavior is always correct.
310358 */
311359 public function test_subtype_registration_does_not_skip_cache_for_different_post_type () {
312360 register_post_meta (
0 commit comments