From a83077e4761e532c8d13b6ba73b32c95e540fa94 Mon Sep 17 00:00:00 2001 From: Steve Parks Date: Wed, 26 Aug 2026 14:20:03 +0200 Subject: [PATCH 1/3] Fix: `statamic:static:warm` drops `--header` values on paginated pages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `statamic:static:warm` attaches `--header` values to its main request pass: ```php // requests(), line ~221 return new Request('GET', $uri, $headers); ``` but `warmPaginatedPages()` — which follows an index page's `X-Statamic-Pagination` header to warm pages 2..n — builds its requests without them: ```php // warmPaginatedPages(), line ~136 $requests = $urls->map(fn (string $url) => new Request('GET', $url))->all(); ``` So a warm run with `--header "X-My-Token: …"` identifies `/tags` to whatever is in front of the origin and does **not** identify `/tags?page=2`. Anything keyed on that header — a CDN/WAF skip rule, an origin allowlist, basic-auth-by-header on a staging site — applies to page 1 of every paginated URL and nothing else. This is invisible until the thing in front of the origin starts acting on unidentified traffic, at which point every paginated page silently fails to cache while the command still reports success (the follow-up pool's rejections are printed, but see the second bug below, which makes them name the wrong URL). In my case, on a site behind Cloudflare with a skip rule matching the warm's header: in a 15-hour window where bot protection was challenging automated traffic, the origin's own warm took 1,782 managed challenges against 4,191 skips — one client, one user-agent, split purely by whether a request was a pagination follow-up. Guzzle cannot pass a managed challenge, so none of those pages entered the cache. ### The fix Parse the headers the same way the main pass does and pass them into the paginated requests. ### Notes - No behaviour change for anyone not passing `--header`. --- src/Console/Commands/StaticWarm.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Console/Commands/StaticWarm.php b/src/Console/Commands/StaticWarm.php index d8b3867aa26..5071b477a44 100644 --- a/src/Console/Commands/StaticWarm.php +++ b/src/Console/Commands/StaticWarm.php @@ -133,7 +133,9 @@ private function warmPaginatedPages(string $url, int $currentPage, int $totalPag return $url; }); - $requests = $urls->map(fn (string $url) => new Request('GET', $url))->all(); + $headers = $this->parseHeaders($this->option('header')); + + $requests = $urls->map(fn (string $url) => new Request('GET', $url, $headers))->all(); $pool = new Pool($this->client(), $requests, [ 'concurrency' => $this->concurrency(), From 95f61daf545d734d374f591a7e8a732b293a288e Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Wed, 26 Aug 2026 11:09:48 -0400 Subject: [PATCH 2/3] Update StaticWarm.php --- src/Console/Commands/StaticWarm.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Console/Commands/StaticWarm.php b/src/Console/Commands/StaticWarm.php index 5071b477a44..2f717f8ec4a 100644 --- a/src/Console/Commands/StaticWarm.php +++ b/src/Console/Commands/StaticWarm.php @@ -134,7 +134,7 @@ private function warmPaginatedPages(string $url, int $currentPage, int $totalPag }); $headers = $this->parseHeaders($this->option('header')); - + $requests = $urls->map(fn (string $url) => new Request('GET', $url, $headers))->all(); $pool = new Pool($this->client(), $requests, [ From bc42fc9cf46ae851979749884ba15e4093d09e9b Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Wed, 26 Aug 2026 12:53:31 -0400 Subject: [PATCH 3/3] Trigger CI re-run (GitHub Actions was having an outage)