Add filemtime-based cache busting for styles.css and main.js

Safari caches static assets far more aggressively than Chrome/Firefox
and largely ignores heuristic revalidation, so a new deploy could keep
showing the old CSS/JS indefinitely even on a hard refresh — no
Cache-Control headers were set anywhere to guide it otherwise.

inc/assets.php adds asset_version($path), which appends a ?v=<mtime>
query string derived from the file's last-modified time. Every page
that links styles.css or main.js (index.php, menu.php, and all five
admin pages) now uses it, so the URL changes whenever the file's
contents change and browsers always fetch the new version.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
David DyerandClaude Sonnet 5 committed 2026-09-02 10:23:40 -04:00
1 parent 375407245c
commit bbe84e8614
8 files changed
+41 -9

No files matched your search

+25
View File
@@ -0,0 +1,25 @@
<?php
declare(strict_types=1);
/**
* Cache-busting query string for a static asset (styles.css, main.js),
* derived from the file's last-modified time.
*
* Without this, browsers — Safari especially, which caches static
* assets far more aggressively than Chrome/Firefox and largely ignores
* heuristic revalidation — can keep serving a stale styles.css/main.js
* indefinitely after a deploy, even on a hard refresh. Appending
* ?v=<mtime> changes the URL every time the file's contents change, so
* it's always treated as a brand new resource rather than a cached one.
*
* Usage: <link rel="stylesheet" href="styles.css<?= asset_version('styles.css') ?>">
* <link rel="stylesheet" href="../styles.css<?= asset_version('styles.css') ?>">
*/
function asset_version(string $relativePath): string
{
$path = dirname(__DIR__) . '/' . ltrim($relativePath, '/');
$mtime = @filemtime($path);
return $mtime !== false ? '?v=' . $mtime : '';
}