PluginProbe
xSpeed Cache: AI-Powered Performance Hub with MCP, Caching & CDN / 1.3.3
xSpeed Cache: AI-Powered Performance Hub with MCP, Caching & CDN v1.3.3
1.3.3 1.3.2 1.3.1 1.3.0 1.2.4 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.1.8 All 29 releases
← All changes | includes/class-cache-inventory.php +34 -4 1.1.31.3.3 View file →
@@ -214,9 +214,26 @@
214 214 $scanned = 0;
215 215 $capped = false;
216 216
217 217 // Flat tree — md5-keyed, URL recovered from the markup.
218 - $flat = defined( 'XSPEED_CACHE_DIR' ) ? (array) glob( XSPEED_CACHE_DIR . '/*.html' ) : array();
218 + // Flat entries live in per-site buckets since #6
219 + // (XSPEED_CACHE_DIR/<host>/<md5>.html); the legacy top-level layout
220 + // is still globbed so pre-#6 entries remain visible until they age out.
221 + $flat = defined( 'XSPEED_CACHE_DIR' )
222 + ? array_merge(
223 + (array) glob( XSPEED_CACHE_DIR . '/*.html' ),
224 + (array) glob( XSPEED_CACHE_DIR . '/*/*.html' )
225 + )
226 + : array();
227 + $flat = array_values(
228 + array_filter(
229 + $flat,
230 + static function ( $f ) {
231 + // min/ and rest/ are separate buckets, not page entries.
232 + return ! in_array( basename( dirname( (string) $f ) ), array( 'min', 'rest', 'combined' ), true );
233 + }
234 + )
235 + );
219 236 foreach ( $flat as $file ) {
220 237 if ( $scanned >= self::SCAN_CAP ) {
221 238 $capped = true;
222 239 break;
@@ -368,11 +385,15 @@
368 385 ),
369 386 );
370 387
371 388 if ( defined( 'XSPEED_CACHE_DIR' ) ) {
389 + // Both layouts: per-site buckets (#6) and pre-#6 top level.
372 390 self::add_glob( $buckets['pages_flat'], XSPEED_CACHE_DIR . '/*.html' );
373 391 self::add_glob( $buckets['metadata'], XSPEED_CACHE_DIR . '/*.meta' );
374 392 self::add_glob( $buckets['precompressed'], XSPEED_CACHE_DIR . '/*.br' );
393 + self::add_glob( $buckets['pages_flat'], XSPEED_CACHE_DIR . '/*/*.html' );
394 + self::add_glob( $buckets['metadata'], XSPEED_CACHE_DIR . '/*/*.meta' );
395 + self::add_glob( $buckets['precompressed'], XSPEED_CACHE_DIR . '/*/*.br' );
375 396 self::add_glob( $buckets['rest'], XSPEED_CACHE_DIR . '/rest/*.json' );
376 397 self::add_glob( $buckets['assets'], XSPEED_CACHE_DIR . '/min/*.css' );
377 398 self::add_glob( $buckets['assets'], XSPEED_CACHE_DIR . '/min/*.js' );
378 399 self::add_glob( $buckets['assets'], XSPEED_CACHE_DIR . '/min/combined/*.css' );
@@ -506,18 +527,27 @@
506 527
507 528 /**
508 529 * The last-purge drill-down.
509 530 *
510 - * @return array{events:array<int,array<string,mixed>>,last_purge:int}
531 + * `last_gc` / `gc_removed` / `gc_removed_total` come from the daily
532 + * `xspeed_gc` sweep (Cache_GC) so the collector is verifiable from the
533 + * dashboard instead of over SSH.
534 + *
535 + * @return array{events:array<int,array<string,mixed>>,last_purge:int,last_gc:int,gc_removed:int,gc_removed_total:int,gc_next_run:int}
511 536 */
512 537 public static function purge_log( int $limit = 25 ): array {
513 538 $limit = max( 1, min( 50, $limit ) );
514 539 $events = self::filter_purges( Activity_Log::entries(), $limit );
515 540 $stats = get_option( 'xspeed_stats', array() );
541 + $stats = is_array( $stats ) ? $stats : array();
516 542
517 543 return array(
518 - 'events' => $events,
519 - 'last_purge' => is_array( $stats ) && isset( $stats['last_purge'] ) ? (int) $stats['last_purge'] : 0,
544 + 'events' => $events,
545 + 'last_purge' => (int) ( $stats['last_purge'] ?? 0 ),
546 + 'last_gc' => (int) ( $stats['last_gc'] ?? 0 ),
547 + 'gc_removed' => (int) ( $stats['gc_removed'] ?? 0 ),
548 + 'gc_removed_total' => (int) ( $stats['gc_removed_total'] ?? 0 ),
549 + 'gc_next_run' => (int) wp_next_scheduled( Cache_GC::CRON_HOOK ),
520 550 );
521 551 }
522 552
523 553 /** Drop the memoized scan — called after a purge so the list can't lie. */