| @@ -132,9 +132,9 @@ | ||
| 132 | 132 | |
| 133 | 133 | // Resolve the global TTL once — Settings_Manager::get() is cheap but |
| 134 | 134 | // this runs per candidate otherwise. |
| 135 | 135 | $opts = Settings_Manager::get( 'cache' ); |
| 136 | - $default_ttl = max( 1, (int) ( $opts['cache_expiry'] ?? 24 ) ) * HOUR_IN_SECONDS; | |
| 136 | + $default_ttl = max( 1, (int) ( $opts['cache_expiry'] ?? \XSpeed\Modules\Cache\CacheModule::DEFAULT_EXPIRY_HOURS ) ) * HOUR_IN_SECONDS; | |
| 137 | 137 | $asset_ttl = self::asset_max_age(); |
| 138 | 138 | $now = time(); |
| 139 | 139 | |
| 140 | 140 | // Start at the phase we paused in and carry on round the list. Each |
| @@ -333,8 +333,28 @@ | ||
| 333 | 333 | * The static tree never has a .meta: store_static() only runs for plain |
| 334 | 334 | * 200 text/html, so the global TTL is always correct there. |
| 335 | 335 | */ |
| 336 | 336 | private static function page_max_age( string $phase, string $path, int $default_ttl ): int { |
| 337 | + if ( 'static' === $phase ) { | |
| 338 | + // A nonce-bearing page records its own deadline when written: the | |
| 339 | + // nonce dies on WordPress's schedule, not the site's cache | |
| 340 | + // lifetime, and this tree is served without PHP so nothing else | |
| 341 | + // can enforce it. A site caching for a week would otherwise hand | |
| 342 | + // out a dead nonce for six and a half days of it, breaking every | |
| 343 | + // anonymous form on the page. | |
| 344 | + $expires_file = dirname( $path ) . '/.xspeed-expires'; | |
| 345 | + // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- sidecar read on a cron sweep; WP_Filesystem is not loaded here. | |
| 346 | + $expires = is_readable( $expires_file ) ? (int) @file_get_contents( $expires_file ) : 0; // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged -- file may vanish between the check and the read. | |
| 347 | + if ( $expires > 0 ) { | |
| 348 | + $mtime = @filemtime( $path ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged -- false is handled below. | |
| 349 | + // Express the deadline as an age, since the caller compares | |
| 350 | + // against the file's own mtime. A file already past its | |
| 351 | + // deadline gets 0, which expires it on this sweep. | |
| 352 | + return ( false !== $mtime ) ? max( 0, $expires - $mtime ) : 0; | |
| 353 | + } | |
| 354 | + | |
| 355 | + return $default_ttl; | |
| 356 | + } | |
| 337 | 357 | if ( 'flat' !== $phase ) { |
| 338 | 358 | return $default_ttl; |
| 339 | 359 | } |
| 340 | 360 | // Read the sidecar NEXT TO THE FILE. Cache::read_meta() rebuilds the |