PluginProbe
xSpeed Cache: AI-Powered Performance Hub with MCP, Caching & CDN / 1.3.6
xSpeed Cache: AI-Powered Performance Hub with MCP, Caching & CDN v1.3.6
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 1.1.2 1.1.3 1.1.4 1.1.5 All 32 releases
← All changes | includes/class-admin.php +55 -2 1.1.4 → 1.3.6 View file →
@@ -551,9 +551,18 @@
551 551 // /status block so the dashboard callout renders on first paint
552 552 // without waiting for a status re-fetch.
553 553 'mobile_separate' => array(
554 554 'enabled' => (bool) ( $opts['cache_enabled'] ? ( Settings_Manager::get( 'cache' )['mobile_separate'] ?? false ) : false ),
555 - 'blocking' => $rewrite_capable && 'mobile_separate' === Cache::static_rewrite_block_reason(),
555 + // Gated to servers that HAVE a static fast path — on IIS or
556 + // an undetected server block_reason still falls through to
557 + // mobile_separate, and reporting that as "blocking" would
558 + // nag about a rewrite that does not exist there (#108).
559 + // LiteSpeed joined the capable set with the Static Fast
560 + // Path opt-in (#509); its own refusal (litespeed_dropin)
561 + // outranks mobile_separate, so this stays false there
562 + // until the opt-in is on.
563 + 'blocking' => ( $rewrite_capable || Server::LITESPEED === $server_type )
564 + && 'mobile_separate' === Cache::static_rewrite_block_reason(),
556 565 'needs_review' => Cache::mobile_separate_needs_review(),
557 566 ),
558 567 // One consolidated nginx server-block snippet aggregating
559 568 // every enabled module's directives (Cache static-rewrite,
@@ -560,8 +569,14 @@
560 569 // BrowserCache headers, GZIP, …). Null on non-nginx hosts
561 570 // or when no module contributes directives. Replaces the
562 571 // per-module "paste this snippet" notices.
563 572 'nginx_server_block' => Cache::full_nginx_server_block(),
573 + // Mirrors the /status block so the enable-time disclosure is
574 + // correct on FIRST PAINT. Without it the top-bar switch can be
575 + // clicked before a status fetch lands, and the one moment the
576 + // warning exists for — a leftover drop-in about to be
577 + // replaced — is exactly when it would be missing.
578 + 'dropin' => Page_Cache_Detector::dropin_disclosure(),
564 579 ),
565 580 // Registered Modules (Free + Pro). The React app discovers them
566 581 // here and renders one sidebar item + one panel per module that
567 582 // declares a settings schema. Hidden modules are filtered.
@@ -612,12 +627,43 @@
612 627 // panel — i.e., truly nothing to render in the dashboard.
613 628 if ( empty( $schema ) && empty( $custom_panel ) ) {
614 629 continue;
615 630 }
631 + $settings = Settings_Manager::get_public( $slug );
632 +
616 633 $entry = array(
617 634 'slug' => $slug,
618 635 'tier' => $module->tier(),
619 636 'version' => $module->version(),
637 + // Promoted from inside `settings` so the payload is
638 + // self-describing. Consumers kept tripping on this — the Hub
639 + // rendered every module "Inactive" until it learned to look
640 + // inside the settings bag. `settings.enabled` is kept below
641 + // for back-compat; this is the same value, not a second
642 + // source of truth. Modules with no `enabled` key (status
643 + // panels like Health) report null rather than a misleading
644 + // false. (#146)
645 + 'enabled' => array_key_exists( 'enabled', $settings )
646 + ? (bool) $settings['enabled']
647 + : null,
648 + // Whether the module is actually DOING something, which is not
649 + // the same question as `enabled` above. "On" has several shapes
650 + // -- page caching lives in the global option, Minify and Lazy
651 + // are on when any flag is set, MCP when it is connected -- so
652 + // each module answers for itself via is_active(). Consumers
653 + // that want "what is switched on?" (the sidebar's "N on" badge)
654 + // must read THIS, not `enabled`, which only ever described the
655 + // modules that happen to store that one key. null means the
656 + // module has no meaningful on/off and should be excluded from
657 + // any count rather than treated as off. (#363)
658 + 'active' => $module->is_active(),
659 + // One sentence explaining the line above, computed next to it
660 + // so the two cannot disagree. The UI shows it behind an (i)
661 + // beside the status pill: "On" is a bare assertion otherwise,
662 + // and least obvious exactly where it matters -- Media
663 + // Optimization reads On while its two most prominent switches
664 + // are off, because three other flags are on. (#363)
665 + 'active_reason' => $module->active_reason(),
620 666 'label' => $meta['label'] ?? ucfirst( $slug ),
621 667 'icon' => $meta['icon'] ?? 'Square',
622 668 'description' => $meta['description'] ?? '',
623 669 // Short label for the module's own tab when it hosts a tabbed
@@ -625,9 +671,16 @@
625 671 'tab_label' => $meta['tab_label'] ?? null,
626 672 // Public view: real values except secret fields, which are masked.
627 673 // The dashboard bundle localizes this into page HTML, so a raw
628 674 // credential here would be readable from view-source. (#115)
629 - 'settings' => Settings_Manager::get_public( $slug ),
675 + 'settings' => $settings,
676 + // Where each value actually came from: a wp-config.php constant,
677 + // the option row, or the schema default. The panel renders a
678 + // constant-sourced field read-only and names the constant, so it
679 + // can never present an editable box over a value the site is not
680 + // using. Every module gets this, not just the ones that declare
681 + // constants today. (#398)
682 + 'setting_origins' => Settings_Manager::origins( $slug ),
630 683 'schema' => $schema,
631 684 'notices' => $module->ui_notices(),
632 685 'custom_panel' => $meta['custom_panel'] ?? null,
633 686 );