PluginProbe
xSpeed Cache: AI-Powered Performance Hub with MCP, Caching & CDN / 1.4.2
xSpeed Cache: AI-Powered Performance Hub with MCP, Caching & CDN v1.4.2
1.4.2 1.4.1 1.4.0 1.3.7 1.3.6 1.3.5 1.3.4 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 All 36 releases
← All changes | includes/class-page-cache-detector.php +48 -4 1.3.7 → 1.4.2 View file →
@@ -78,8 +78,14 @@
78 78 /** advanced-cache.php is there and cannot be read. */
79 79 public const BLOCKER_UNREADABLE_DROPIN = 'unreadable_dropin';
80 80 /** A page-cache-capable plugin is active with no drop-in evidence. */
81 81 public const BLOCKER_ACTIVE_PAGE_CACHE = 'active_page_cache';
82 + /**
83 + * An active plugin's own settings say its page cache is on. Unlike
84 + * `active_page_cache`, which only says it CAN cache pages, this is
85 + * proof that it does, so xSpeed's would be stacked on top of it. (#653)
86 + */
87 + public const BLOCKER_PAGE_CACHE_SWITCHED_ON = 'page_cache_switched_on';
82 88 /** More than one plugin owns, or could own, the page cache. */
83 89 public const BLOCKER_MULTIPLE_PAGE_CACHES = 'multiple_page_caches';
84 90 /** WP_CACHE is true with no drop-in to explain it. */
85 91 public const BLOCKER_WP_CACHE_ORPHANED = 'wp_cache_orphaned';
@@ -182,8 +188,10 @@
182 188 if ( ! $active && empty( $signals ) ) {
183 189 continue;
184 190 }
185 191
192 + $page_cache = in_array( Cache_Plugin_Catalog::CAP_PAGE_CACHE, $entry['capabilities'], true );
193 +
186 194 $out[] = array(
187 195 'plugin' => $file,
188 196 'label' => $entry['label'],
189 197 'active' => $active,
@@ -191,9 +199,12 @@
191 199 'site_active' => $site_active,
192 200 'network_active' => $network_active,
193 201 'activation_scope' => $site_active && $network_active ? 'site-and-network' : ( $network_active ? 'network' : ( $site_active ? 'site' : 'inactive' ) ),
194 202 'capabilities' => $entry['capabilities'],
195 - 'page_cache' => in_array( Cache_Plugin_Catalog::CAP_PAGE_CACHE, $entry['capabilities'], true ),
203 + 'page_cache' => $page_cache,
204 + // The plugin's own page-cache switch: true on, false off,
205 + // null unknown. Only asked of an active page cache.
206 + 'page_cache_on' => ( $page_cache && $active ) ? Cache_Plugin_Catalog::page_cache_state( $file ) : null,
196 207 'signals' => $signals,
197 208 );
198 209 }
199 210 return $out;
@@ -446,9 +457,9 @@
446 457 foreach ( self::inspect()['plugins'] as $plugin ) {
447 458 if ( self::SELF_PLUGIN_FILE === (string) $plugin['plugin'] ) {
448 459 continue;
449 460 }
450 - if ( ! empty( $plugin['page_cache'] ) && ! empty( $plugin['active'] ) ) {
461 + if ( self::may_be_caching_pages( $plugin ) ) {
451 462 return true;
452 463 }
453 464 }
454 465 return false;
@@ -453,8 +464,26 @@
453 464 }
454 465 return false;
455 466 }
456 467
468 + /**
469 + * An active page-cache plugin, unless its own settings prove its page
470 + * cache is off.
471 + *
472 + * A plugin kept active for its other features, with its page cache
473 + * switched off, owns nothing here. Counting it anyway is what made
474 + * Health report LiteSpeed Cache as a conflict on GridPane's
475 + * OpenLiteSpeed servers with its page cache off. When the setting
476 + * cannot be read we still assume it may be caching. (#653)
477 + *
478 + * @param array $plugin One row from inspect_plugins().
479 + */
480 + private static function may_be_caching_pages( array $plugin ): bool {
481 + return ! empty( $plugin['page_cache'] )
482 + && ! empty( $plugin['active'] )
483 + && false !== ( $plugin['page_cache_on'] ?? null );
484 + }
485 +
457 486 public static function is_field_clear(): bool {
458 487 $verdict = self::classify();
459 488
460 489 if ( ! empty( $verdict['blockers'] ) ) {
@@ -478,9 +507,9 @@
478 507 */
479 508 public static function active_page_caches(): array {
480 509 $out = array();
481 510 foreach ( self::inspect()['plugins'] as $plugin ) {
482 - if ( $plugin['page_cache'] && $plugin['active'] ) {
511 + if ( self::may_be_caching_pages( $plugin ) ) {
483 512 $out[] = (string) $plugin['label'];
484 513 }
485 514 }
486 515 return $out;
@@ -589,11 +618,26 @@
589 618 */
590 619 $owners = array();
591 620 $active = array();
592 621 foreach ( $report['plugins'] as $plugin ) {
593 - if ( $plugin['page_cache'] && $plugin['active'] ) {
622 + if ( self::may_be_caching_pages( $plugin ) ) {
594 623 $active[ (string) $plugin['plugin'] ] = $plugin;
595 624 $owners[ (string) $plugin['plugin'] ] = (string) $plugin['label'];
625 + }
626 + }
627 +
628 + /*
629 + * Proven live, not just possible. Raised before the state ladder so
630 + * it rides along with whichever state wins: two page caches serving
631 + * the same pages is the problem whoever holds the drop-in. (#653)
632 + */
633 + foreach ( $active as $file => $plugin ) {
634 + if ( self::SELF_PLUGIN_FILE !== $file && true === ( $plugin['page_cache_on'] ?? null ) ) {
635 + $blockers[] = array(
636 + 'code' => self::BLOCKER_PAGE_CACHE_SWITCHED_ON,
637 + 'plugin' => $plugin['plugin'],
638 + 'label' => $plugin['label'],
639 + );
596 640 }
597 641 }
598 642 if ( self::OWNER_FOREIGN === $dropin['owner'] ) {
599 643 $key = (string) ( $dropin['plugin'] ?? $dropin['label'] );