diff --git a/src/Console/Commands/StaticWarm.php b/src/Console/Commands/StaticWarm.php
index 7737f9d380..82a1c05e65 100644
--- a/src/Console/Commands/StaticWarm.php
+++ b/src/Console/Commands/StaticWarm.php
@@ -76,8 +76,6 @@ public function handle()
private function warm(): void
{
- $client = new Client($this->clientConfig());
-
$this->output->newLine();
$this->line('Compiling URLs...');
@@ -97,7 +95,7 @@ private function warm(): void
} else {
$this->line('Visiting '.count($requests).' URLs...');
- $pool = new Pool($client, $requests, [
+ $pool = new Pool($this->client(), $requests, [
'concurrency' => $this->concurrency(),
'fulfilled' => [$this, 'outputSuccessLine'],
'rejected' => [$this, 'outputFailureLine'],
@@ -109,6 +107,27 @@ private function warm(): void
}
}
+ private function warmPaginatedPages(string $url, int $currentPage, int $totalPages, string $pageName): void
+ {
+ $urls = collect(range($currentPage, $totalPages))->map(function ($page) use ($url, $pageName) {
+ return "{$url}?{$pageName}={$page}";
+ });
+
+ $requests = $urls->map(fn (string $url) => new Request('GET', $url))->all();
+
+ $pool = new Pool($this->client(), $requests, [
+ 'concurrency' => $this->concurrency(),
+ 'fulfilled' => function (Response $response, $index) use ($urls) {
+ $this->components->twoColumnDetail($this->getRelativeUri($urls->get($index)), '✓ Cached');
+ },
+ 'rejected' => [$this, 'outputFailureLine'],
+ ]);
+
+ $promise = $pool->promise();
+
+ $promise->wait();
+ }
+
private function concurrency(): int
{
$strategy = config('statamic.static_caching.strategy');
@@ -116,6 +135,11 @@ private function concurrency(): int
return config("statamic.static_caching.strategies.$strategy.warm_concurrency", 25);
}
+ private function client(): Client
+ {
+ return new Client($this->clientConfig());
+ }
+
private function clientConfig(): array
{
return [
@@ -128,12 +152,18 @@ private function clientConfig(): array
public function outputSuccessLine(Response $response, $index): void
{
- $this->components->twoColumnDetail($this->getRelativeUri($index), '✓ Cached');
+ $this->components->twoColumnDetail($this->getRelativeUri($this->uris()->get($index)), '✓ Cached');
+
+ if ($response->hasHeader('X-Statamic-Pagination')) {
+ [$currentPage, $totalPages, $pageName] = $response->getHeader('X-Statamic-Pagination');
+
+ $this->warmPaginatedPages($this->uris()->get($index), $currentPage, $totalPages, $pageName);
+ }
}
public function outputFailureLine($exception, $index): void
{
- $uri = $this->getRelativeUri($index);
+ $uri = $this->getRelativeUri($this->uris()->get($index));
if ($exception instanceof RequestException && $exception->hasResponse()) {
$response = $exception->getResponse();
@@ -150,9 +180,9 @@ public function outputFailureLine($exception, $index): void
$this->components->twoColumnDetail($uri, "$message");
}
- private function getRelativeUri(int $index): string
+ private function getRelativeUri(string $uri): string
{
- return Str::start(Str::after($this->uris()->get($index), config('app.url')), '/');
+ return Str::start(Str::after($uri, config('app.url')), '/');
}
private function requests()
diff --git a/src/Console/Commands/StaticWarmJob.php b/src/Console/Commands/StaticWarmJob.php
index 4ae92b1b42..09de9b93aa 100644
--- a/src/Console/Commands/StaticWarmJob.php
+++ b/src/Console/Commands/StaticWarmJob.php
@@ -24,6 +24,18 @@ public function __construct(public Request $request, public array $clientConfig)
public function handle()
{
- (new Client($this->clientConfig))->send($this->request);
+ $response = (new Client($this->clientConfig))->send($this->request);
+
+ if ($response->hasHeader('X-Statamic-Pagination')) {
+ [$currentPage, $totalPages, $pageName] = $response->getHeader('X-Statamic-Pagination');
+
+ collect(range($currentPage, $totalPages))
+ ->map(function (int $page) use ($pageName) {
+ return "{$this->request->getUri()}?{$pageName}={$page}";
+ })
+ ->each(function (string $uri) {
+ StaticWarmJob::dispatch(new Request('GET', $uri), $this->clientConfig);
+ });
+ }
}
}
diff --git a/src/StaticCaching/Cachers/FileCacher.php b/src/StaticCaching/Cachers/FileCacher.php
index 7be32839a5..8e653d300d 100644
--- a/src/StaticCaching/Cachers/FileCacher.php
+++ b/src/StaticCaching/Cachers/FileCacher.php
@@ -167,7 +167,17 @@ public function getFilePath($url, $site = null)
$urlParts = parse_url($url);
$pathParts = pathinfo($urlParts['path']);
$slug = $pathParts['basename'];
- $query = $this->config('ignore_query_strings') ? '' : Arr::get($urlParts, 'query', '');
+ $query = Arr::get($urlParts, 'query', '');
+
+ if ($this->config('ignore_query_strings')) {
+ $allowedQueryParams = collect($this->config('allowed_query_strings', []))
+ ->map(fn ($param) => Str::ensureRight($param, '='))
+ ->all();
+
+ $query = collect(explode('&', $query))
+ ->filter(fn ($param) => Str::startsWith($param, $allowedQueryParams))
+ ->implode('&');
+ }
if ($this->isBasenameTooLong($basename = $slug.'_'.$query.'.html')) {
$basename = $slug.'_lqs_'.md5($query).'.html';
diff --git a/src/StaticCaching/Middleware/Cache.php b/src/StaticCaching/Middleware/Cache.php
index 3312ddab49..0777e876e1 100644
--- a/src/StaticCaching/Middleware/Cache.php
+++ b/src/StaticCaching/Middleware/Cache.php
@@ -10,6 +10,7 @@
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Cache as AppCache;
use Illuminate\Support\Facades\Log;
+use Statamic\Facades\Blink;
use Statamic\Facades\StaticCache;
use Statamic\Statamic;
use Statamic\StaticCaching\Cacher;
@@ -75,6 +76,16 @@ private function handleRequest($request, Closure $next)
$this->makeReplacementsAndCacheResponse($request, $response);
$this->nocache->write();
+
+ if ($paginator = Blink::get('tag-paginator')) {
+ if ($paginator->hasMorePages()) {
+ $response->headers->set('X-Statamic-Pagination', [
+ 'current' => $paginator->currentPage(),
+ 'total' => $paginator->lastPage(),
+ 'name' => $paginator->getPageName(),
+ ]);
+ }
+ }
} elseif (! $response->isRedirect()) {
$this->makeReplacements($response);
}
diff --git a/tests/Console/Commands/StaticWarmJobTest.php b/tests/Console/Commands/StaticWarmJobTest.php
index b92c0e2941..8baa3247fd 100644
--- a/tests/Console/Commands/StaticWarmJobTest.php
+++ b/tests/Console/Commands/StaticWarmJobTest.php
@@ -6,6 +6,7 @@
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Response;
+use Illuminate\Support\Facades\Queue;
use PHPUnit\Framework\Attributes\Test;
use Statamic\Console\Commands\StaticWarmJob;
use Tests\TestCase;
@@ -27,4 +28,41 @@ public function it_sends_a_get_request()
$this->assertEquals('/about', $mock->getLastRequest()->getUri()->getPath());
}
+
+ #[Test]
+ public function it_sends_a_get_request_and_dispatches_static_warm_job_for_page_with_pagination()
+ {
+ Queue::fake();
+
+ $mock = new MockHandler([
+ (new Response(200))->withHeader('X-Statamic-Pagination', [
+ 'current' => 1,
+ 'total' => 3,
+ 'name' => 'page',
+ ]),
+ ]);
+
+ $handlerStack = HandlerStack::create($mock);
+
+ $job = new StaticWarmJob(new Request('GET', '/blog'), ['handler' => $handlerStack]);
+
+ $job->handle();
+
+ $this->assertEquals('/blog', $mock->getLastRequest()->getUri()->getPath());
+
+ Queue::assertPushed(StaticWarmJob::class, function (StaticWarmJob $job) {
+ return $job->request->getUri()->getPath() === '/blog'
+ && $job->request->getUri()->getQuery() === 'page=1';
+ });
+
+ Queue::assertPushed(StaticWarmJob::class, function (StaticWarmJob $job) {
+ return $job->request->getUri()->getPath() === '/blog'
+ && $job->request->getUri()->getQuery() === 'page=2';
+ });
+
+ Queue::assertPushed(StaticWarmJob::class, function (StaticWarmJob $job) {
+ return $job->request->getUri()->getPath() === '/blog'
+ && $job->request->getUri()->getQuery() === 'page=3';
+ });
+ }
}