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-rest-api.php +41 -11 1.1.31.3.3 View file →
@@ -425,8 +425,13 @@
425 425 'nginx_snippet' => Gzip::nginx_snippet(),
426 426 ),
427 427 'rewrite_probe' => $rewrite_probe,
428 428 'nginx_server_block' => Cache::full_nginx_server_block(),
429 + // What enabling the page cache would do to
430 + // wp-content/advanced-cache.php. The dashboard discloses the
431 + // replacement BEFORE the write when a leftover drop-in is
432 + // already there; see Page_Cache_Detector::dropin_disclosure().
433 + 'dropin' => Page_Cache_Detector::dropin_disclosure(),
429 434 // Separate Mobile Cache visibility (FBS-83145). `blocking` is
430 435 // true when mobile_separate is what's keeping the device-blind
431 436 // static fast path from installing on a rewrite-capable server;
432 437 // `needs_review` is true when a migration turned it on for us and
@@ -459,10 +464,19 @@
459 464 return rest_ensure_response( $updated );
460 465 }
461 466
462 467 public function purge() {
463 - Cache::purge_all( __( 'dashboard', 'xspeed' ) );
464 - return rest_ensure_response( array( 'stats' => Cache::get_stats() ) );
468 + // The same core function `wp xspeed purge` runs, so the dashboard
469 + // button and the CLI cannot clear different sets of stores — and the
470 + // per-store report is available here for the UI to surface a store
471 + // that was skipped or refused rather than flashing "cache cleared".
472 + $report = Purge_Runner::run( array( 'all' ), __( 'dashboard', 'xspeed' ) );
473 + return rest_ensure_response(
474 + array(
475 + 'stats' => Cache::get_stats(),
476 + 'report' => $report,
477 + )
478 + );
465 479 }
466 480
467 481 /**
468 482 * The "Cached Pages" drill-down: which pages are cached and how old they
@@ -504,17 +518,27 @@
504 518 * Returns the same shape the dashboard bootstrap uses, so the caller can
505 519 * swap it straight into state without a second round trip. (FBS-84012)
506 520 */
507 521 public function recheck_rewrite() {
508 - $probe = Cache::recheck_static_rewrite();
522 + $raw = Cache::recheck_static_rewrite();
509 523 $server_type = Server::detect();
510 524
525 + // Qualify the raw probe against known config refusals. The probe
526 + // fetches its own file from the static tree, which succeeds even when
527 + // no real page is served that way — so an unqualified `active` told
528 + // clients the static path was engaged on sites where it demonstrably
529 + // wasn't. `block_reason` is exposed so a client can act on the
530 + // specific cause rather than re-deriving it. See
531 + // Cache::qualify_rewrite_probe().
532 + $probe = Cache::qualify_rewrite_probe( $raw );
533 +
511 534 return rest_ensure_response(
512 535 array(
513 - 'active' => (bool) ( $probe['active'] ?? false ),
514 - 'pending' => (bool) ( $probe['pending'] ?? false ),
515 - 'inconclusive' => (bool) ( $probe['inconclusive'] ?? false ),
516 - 'reason' => (string) ( $probe['reason'] ?? '' ),
536 + 'active' => $probe['active'],
537 + 'pending' => (bool) ( $raw['pending'] ?? false ),
538 + 'inconclusive' => $probe['inconclusive'],
539 + 'reason' => $probe['reason'],
540 + 'block_reason' => $probe['block_reason'],
517 541 'server_type' => $server_type,
518 542 'snippet' => Cache::nginx_snippet(),
519 543 'topology' => Server::rewrite_topology(),
520 544 'behind_proxy' => Server::is_behind_proxy(),
@@ -530,9 +554,9 @@
530 554 // permission_callback above already enforced current_user_can(
531 555 // 'manage_options' ); the REST nonce is verified by core via the
532 556 // X-WP-Nonce header.
533 557 $state = Cache::toggle( $enabled );
534 - $updated = Settings::update( array( 'cache_enabled' => $state['enabled'] ) );
558 + $updated = Settings::get();
535 559
536 560 // Recompute the unified nginx block AFTER cache_enabled is persisted.
537 561 // Cache::toggle() computes it inline, but cache_enabled isn't written
538 562 // until the Settings::update() above — so the block inside $state
@@ -542,11 +566,17 @@
542 566 $state['nginx_server_block'] = Cache::full_nginx_server_block();
543 567
544 568 return rest_ensure_response(
545 569 array(
546 - 'enabled' => $updated['cache_enabled'],
547 - 'stats' => Cache::get_stats(),
548 - 'install_state' => $state,
570 + 'enabled' => $updated['cache_enabled'],
571 + // Surfaced at the top level so the dashboard can explain a
572 + // refusal rather than silently snapping the toggle back:
573 + // Cache::toggle() writes nothing when another plugin owns the
574 + // drop-in or WP_CACHE is in a shape we must not rewrite.
575 + 'blocked' => ! empty( $state['blocked'] ),
576 + 'blocked_reason' => $state['blocked_reason'] ?? null,
577 + 'stats' => Cache::get_stats(),
578 + 'install_state' => $state,
549 579 )
550 580 );
551 581 }
552 582 }