From db96c290003fbfefefec52b491023a94e2cd9098 Mon Sep 17 00:00:00 2001 From: Ryan Mitchell Date: Fri, 22 Aug 2025 07:20:12 +0100 Subject: [PATCH 01/18] Update composer.json --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index ee2baf5..8ebaf08 100644 --- a/composer.json +++ b/composer.json @@ -11,9 +11,9 @@ } }, "require": { - "php": "^8.1", + "php": "^8.2", "pixelfear/composer-dist-plugin": "^0.1.5", - "statamic/cms": "^4.55 || ^5.0" + "statamic/cms": "^5.0 || ^6.0" }, "require-dev": { "laravel/pint": "^1.13", From 3aa9e801eb1f86e41622eff7cbddab3e704648e1 Mon Sep 17 00:00:00 2001 From: Ryan Mitchell Date: Tue, 30 Sep 2025 07:10:11 +0100 Subject: [PATCH 02/18] Add clear cache action on routable entries --- src/Actions/ClearCache.php | 36 ++++++++++++++++++++++++++++ src/Http/Middleware/CacheTracker.php | 6 ++--- src/ServiceProvider.php | 4 ++++ 3 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 src/Actions/ClearCache.php diff --git a/src/Actions/ClearCache.php b/src/Actions/ClearCache.php new file mode 100644 index 0000000..27443a6 --- /dev/null +++ b/src/Actions/ClearCache.php @@ -0,0 +1,36 @@ +filter(fn ($item) => $item->absoluteUrl()) + ->each(fn ($item) => Tracker::remove($item->absoluteUrl())); + + return __('Cache cleared'); + } + + public static function title() + { + return __('Clear cache'); + } + + public function visibleTo($item) + { + if (! $item instanceof Entry) { + return false; + } + + return ! Blink::once( + 'cache-action::'.$item->collectionHandle.'::'.$item->locale(), + fn () => is_null($item->collection()->route($item->locale())) + ); + } +} diff --git a/src/Http/Middleware/CacheTracker.php b/src/Http/Middleware/CacheTracker.php index f0373d7..f29f847 100644 --- a/src/Http/Middleware/CacheTracker.php +++ b/src/Http/Middleware/CacheTracker.php @@ -123,13 +123,13 @@ private function setupAugmentationHooks(string $url) return $next($augmented); }); - app(Entry::class)::hook('augmented', function ($augmented, $next) use ($self, $url) { + app(Entry::class)::hook('augmented', function ($augmented, $next) use ($self) { $self->addContentTag($this->collection()->handle().':'.$this->id()); return $next($augmented); }); - Page::hook('augmented', function ($augmented, $next) use ($self, $url) { + Page::hook('augmented', function ($augmented, $next) use ($self) { if ($entry = $this->entry()) { $self->addContentTag($entry->collection()->handle().':'.$entry->id()); } @@ -137,7 +137,7 @@ private function setupAugmentationHooks(string $url) return $next($augmented); }); - LocalizedTerm::hook('augmented', function ($augmented, $next) use ($self, $url) { + LocalizedTerm::hook('augmented', function ($augmented, $next) use ($self) { $self->addContentTag('term:'.$this->id()); return $next($augmented); diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index 69d106d..19f4e40 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -6,6 +6,10 @@ class ServiceProvider extends AddonServiceProvider { + protected $actions = [ + Actions\ClearCache::class, + ]; + protected $middlewareGroups = [ 'web' => [ Http\Middleware\CacheTracker::class, From f7ea7092a6ef466a6c2bd591ee733d9f1ab85343 Mon Sep 17 00:00:00 2001 From: Ryan Mitchell Date: Fri, 3 Oct 2025 13:02:13 +0100 Subject: [PATCH 03/18] progress --- composer.json | 2 +- package.json | 15 +++ resources/js/components/CacheTrackerModal.vue | 95 +++++++++++++++++++ resources/js/cp.js | 5 + routes/cp.php | 9 ++ src/Actions/ViewCacheTags.php | 53 +++++++++++ src/Http/Controllers/GetTagsController.php | 18 ++++ src/Http/Controllers/GetUrlsController.php | 18 ++++ src/Http/Middleware/CacheTracker.php | 4 + src/ServiceProvider.php | 12 ++- tests/TestCase.php | 4 +- vite.config.js | 17 ++++ 12 files changed, 248 insertions(+), 4 deletions(-) create mode 100644 package.json create mode 100644 resources/js/components/CacheTrackerModal.vue create mode 100644 resources/js/cp.js create mode 100644 routes/cp.php create mode 100644 src/Actions/ViewCacheTags.php create mode 100644 src/Http/Controllers/GetTagsController.php create mode 100644 src/Http/Controllers/GetUrlsController.php create mode 100644 vite.config.js diff --git a/composer.json b/composer.json index 8ebaf08..a4bd635 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,7 @@ "require": { "php": "^8.2", "pixelfear/composer-dist-plugin": "^0.1.5", - "statamic/cms": "^5.0 || ^6.0" + "statamic/cms": "dev-master" }, "require-dev": { "laravel/pint": "^1.13", diff --git a/package.json b/package.json new file mode 100644 index 0000000..6bdac4c --- /dev/null +++ b/package.json @@ -0,0 +1,15 @@ +{ + "dependencies": { + "@statamic/cms": "file:./vendor/statamic/cms/resources/js/package", + "axios": "^1.12.2" + }, + "scripts": { + "dev": "vite", + "build": "vite build", + "production": "vite build" + }, + "devDependencies": { + "laravel-vite-plugin": "^1.2.0", + "vite": "^6.3.4" + } +} diff --git a/resources/js/components/CacheTrackerModal.vue b/resources/js/components/CacheTrackerModal.vue new file mode 100644 index 0000000..e19e7da --- /dev/null +++ b/resources/js/components/CacheTrackerModal.vue @@ -0,0 +1,95 @@ + + + diff --git a/resources/js/cp.js b/resources/js/cp.js new file mode 100644 index 0000000..cc7e04a --- /dev/null +++ b/resources/js/cp.js @@ -0,0 +1,5 @@ +import CacheTrackerModal from './components/CacheTrackerModal.vue'; + +Statamic.booting(() => { + Statamic.$components.register('cache-tracker-modal', CacheTrackerModal); +}); diff --git a/routes/cp.php b/routes/cp.php new file mode 100644 index 0000000..c48fc1b --- /dev/null +++ b/routes/cp.php @@ -0,0 +1,9 @@ +prefix('cache-tracker')->group(function () { + Route::post('tags', [Controllers\GetTagsController::class, '__invoke'])->name('tags'); + Route::post('urls', [Controllers\GetUrlsController::class, '__invoke'])->name('url'); +}); diff --git a/src/Actions/ViewCacheTags.php b/src/Actions/ViewCacheTags.php new file mode 100644 index 0000000..d89d0d0 --- /dev/null +++ b/src/Actions/ViewCacheTags.php @@ -0,0 +1,53 @@ +collectionHandle.'::'.$item->locale(), + fn () => is_null($item->collection()->route($item->locale())) + ); + } + + public function visibleToBulk($items) + { + return false; + } + + public function buttonText() + { + /** @translation */ + return __('Clear cache'); + } +} diff --git a/src/Http/Controllers/GetTagsController.php b/src/Http/Controllers/GetTagsController.php new file mode 100644 index 0000000..055cb0c --- /dev/null +++ b/src/Http/Controllers/GetTagsController.php @@ -0,0 +1,18 @@ +input('item')) { + return []; + } + + return Tracker::get($url) ?? []; // + } +} diff --git a/src/Http/Controllers/GetUrlsController.php b/src/Http/Controllers/GetUrlsController.php new file mode 100644 index 0000000..53db867 --- /dev/null +++ b/src/Http/Controllers/GetUrlsController.php @@ -0,0 +1,18 @@ +input('item'); + + return collect(Tracker::all()) + ->filter(fn ($tracked) => in_array($item, $tracked['tags'])) + ->all(); + } +} diff --git a/src/Http/Middleware/CacheTracker.php b/src/Http/Middleware/CacheTracker.php index f29f847..d60a6eb 100644 --- a/src/Http/Middleware/CacheTracker.php +++ b/src/Http/Middleware/CacheTracker.php @@ -49,6 +49,10 @@ public function handle($request, Closure $next) $url = $this->url(); + if (Str::endsWith($url, '/')) { + $url = substr($url, 0, -1); + } + if (Tracker::has($url)) { return $next($request); } diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index 19f4e40..f82d530 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -7,7 +7,7 @@ class ServiceProvider extends AddonServiceProvider { protected $actions = [ - Actions\ClearCache::class, + Actions\ViewCacheTags::class, ]; protected $middlewareGroups = [ @@ -20,6 +20,16 @@ class ServiceProvider extends AddonServiceProvider Listeners\Subscriber::class, ]; + protected $routes = [ + 'cp' => __DIR__.'/../routes/cp.php', + ]; + + protected $vite = [ + 'input' => ['resources/js/cp.js'], + 'publicDirectory' => 'dist', + 'hotFile' => __DIR__.'/../dist/hot', + ]; + public function boot() { parent::boot(); diff --git a/tests/TestCase.php b/tests/TestCase.php index 8419f79..e5915a9 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -20,7 +20,7 @@ protected function resolveApplicationConfiguration($app) { parent::resolveApplicationConfiguration($app); - $app['config']->set('app.key', 'base64:' . base64_encode(Encrypter::generateKey($app['config']['app.cipher']))); + $app['config']->set('app.key', 'base64:'.base64_encode(Encrypter::generateKey($app['config']['app.cipher']))); // Assume the pro edition within tests $app['config']->set('statamic.editions.pro', true); @@ -30,7 +30,7 @@ protected function resolveApplicationConfiguration($app) // views for front end routing tests $app['config']->set('view.paths', [ - __DIR__ . '/__fixtures__/resources/views', + __DIR__.'/__fixtures__/resources/views', ]); } diff --git a/vite.config.js b/vite.config.js new file mode 100644 index 0000000..c547d8f --- /dev/null +++ b/vite.config.js @@ -0,0 +1,17 @@ +import laravel from 'laravel-vite-plugin' +import { defineConfig } from 'vite' +import statamic from '@statamic/cms/vite-plugin'; + +export default defineConfig({ + plugins: [ + statamic(), + laravel({ + input: [ + 'resources/js/cp.js' + ], + refresh: true, + publicDirectory: 'dist', + hotFile: 'dist/hot', + }), + ], +}); From 2565b6a8d84d84cc8973acbfb1acb67482675a6d Mon Sep 17 00:00:00 2001 From: Ryan Mitchell Date: Fri, 3 Oct 2025 13:07:08 +0100 Subject: [PATCH 04/18] More --- resources/js/components/CacheTrackerModal.vue | 8 ++++---- src/Actions/ClearCache.php | 5 +++++ src/ServiceProvider.php | 1 + 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/resources/js/components/CacheTrackerModal.vue b/resources/js/components/CacheTrackerModal.vue index e19e7da..7aeaf4e 100644 --- a/resources/js/components/CacheTrackerModal.vue +++ b/resources/js/components/CacheTrackerModal.vue @@ -57,13 +57,13 @@ axios