Fix: register cache-invalidation hooks under WP-CLI when there is no request URI - #1068
Conversation
…request URI When $wp_cache_request_uri is empty (WP-CLI, and some cron runners), wp_cache_postload() returned before wp_cache_phase2() could run, so none of the cache-invalidation hooks registered. Publishing a scheduled post from the CLI therefore left the stale page in the cache. Register the invalidation hooks (via the existing idempotent wpsc_register_post_hooks()) on the empty-request-URI path too. The serving path stays skipped, since a request with no URI never serves a cached page. Adds a WP-runtime-free smoke test with add_action()/has_action() doubles. Fixes Automattic#1007
There was a problem hiding this comment.
Pull request overview
This PR fixes cache invalidation when WordPress runs without a request URI (notably WP-CLI / some cron runners) by ensuring the post-change invalidation hooks are still registered even though the cache-serving path is skipped.
Changes:
- Register
wpsc_register_post_hooks()fromwp_cache_postload()when$wp_cache_request_uriis empty (and caching is enabled), restoring invalidation behavior for CLI/cron contexts. - Add a smoke test to assert invalidation hooks are registered in the empty-URI path, plus minimal
add_action()/has_action()hook doubles for the smoke tier. - Add a changelog entry documenting the fix.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
wp-cache-phase2.php |
Registers invalidation hooks even when request URI is empty, while still skipping cache serving. |
tests/php/smoke/WpCachePostloadTest.php |
Adds regression smoke coverage for hook registration under empty request URI. |
tests/php/bootstrap-smoke.php |
Extends smoke bootstrap with add_action() / has_action() doubles backed by the existing filter registry. |
changelog/fix-cli-cache-invalidation |
Notes the WP-CLI scheduled-post cache invalidation fix. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // them here so content changes still clear the cache. wpsc_register_post_hooks() | ||
| // wires only the content-change hooks (not the serving ones) and is | ||
| // idempotent, so this is safe alongside the normal request path. |
Thanks @thisismyurl, this is careful work and the reasoning in the description is good. I went to merge it and then couldn't reproduce the bug it fixes, so I dug in. I think the hooks are already registered on the CLI and the change is a no-op in practice.
function wp_super_cache_init_action() {
load_plugin_textdomain( 'wp-super-cache', false, basename( __DIR__ ) . '/languages' );
wpsc_register_post_hooks();
}
add_action( 'init', 'wp_super_cache_init_action' );
I checked that directly on trunk, before applying your branch: That's from Then I ran the actual scenario from #1007. Two false starts worth mentioning, because they nearly convinced me the bug was real: my first attempts published the post through a loopback request to With that set, a scheduled post backdated so the event is due, and the home page cached: The debug log, same PID, no request URI: The early return you're targeting does happen, and the cache is cleared a second later in the same process anyway. So I don't want to merge this as a fix for #1007, and I'd rather not close that issue with it, because the reporter's site would behave exactly as before. A few things you got right that I don't want to lose:
Two small things if you do carry on with the branch:
The original report might still be real, I just don't think registration is the cause. Two things I'd look at next:
Was the original reporter on multisite? That's the first thing I'd ask them. Happy to be wrong about any of this, my repro was on wp-env with PHP 8.3 and WordPress 7.1, so shout if it behaves differently on your setup. |
Hey Donncha,
#1007 — the report is that scheduled posts published through WP-CLI don't clear the cache, and that's exactly what's happening.
wp_cache_postload()bails as soon as$wp_cache_request_uriis empty, which is the normal state under WP-CLI (there's no request). The early return is right for the serving side — there's no page to serve on the CLI — but it also skipswp_cache_phase2(), and that's wherewpsc_register_post_hooks()wires uppublish_post,transition_post_status, and the rest. So when wp-cron fires under the CLI and a scheduled post goes live, nothing is listening, and the stale page survives.The fix registers just the invalidation hooks on that empty-URI path and leaves the serving path skipped as it was. It leans on the existing
wpsc_register_post_hooks()— that only wires the content-change hooks, not the serving ones, and it's guarded by a static$done, so calling it here can't double-register on a normal request. Four lines, and they only run when there's no request URI.For the test I added a small smoke case (
WpCachePostloadTest) that sets an empty request URI, runs postload, and asserts the invalidation hooks registered. It neededadd_action/has_actiondoubles, which the smoke bootstrap didn't have yet, so I added them next to the existingadd_filterone. I checked it's a real guard — with the fix the hooks register, and reverting the four lines makes the test fail.One thing I'm not sure about: whether you'd rather scope the registration more tightly — only under
WP_CLI— instead of "whenever there's no request URI." I went with the no-URI condition because it's the actual precondition for the bug and it's what the function already branches on, but I'm happy to switch to a CLI-specific guard if you'd prefer.Fixes #1007
(full disclosure: AI helped me identify the issue and verify my work)