PluginProbe
xSpeed Cache: AI-Powered Performance Hub with MCP, Caching & CDN / 1.4.0
xSpeed Cache: AI-Powered Performance Hub with MCP, Caching & CDN v1.4.0
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 1.1.2 All 35 releases
← All changes | includes/class-rest-api.php +81 -3 1.3.2 → 1.4.0 View file →
@@ -90,10 +90,29 @@
90 90 'permission_callback' => array( $this, 'permissions' ),
91 91 )
92 92 );
93 93
94 + // The server-side mirror of "I pasted the block". Only meaningful on a
95 + // host where the probe cannot read the rules back — see
96 + // nginx_copied_hash().
94 97 register_rest_route(
95 98 self::NAMESPACE_V1,
99 + '/cache/nginx-copied-hash',
100 + array(
101 + 'methods' => 'POST',
102 + 'callback' => array( $this, 'nginx_copied_hash' ),
103 + 'permission_callback' => array( $this, 'permissions' ),
104 + 'args' => array(
105 + 'hash' => array(
106 + 'type' => 'string',
107 + 'required' => true,
108 + ),
109 + ),
110 + )
111 + );
112 +
113 + register_rest_route(
114 + self::NAMESPACE_V1,
96 115 '/cache/benchmark',
97 116 array(
98 117 'methods' => 'GET',
99 118 'callback' => array( $this, 'benchmark' ),
@@ -180,8 +199,17 @@
180 199 array(
181 200 'methods' => 'GET',
182 201 'callback' => array( $this, 'recommendations' ),
183 202 'permission_callback' => array( $this, 'permissions' ),
203 + 'args' => array(
204 + // `contributed` adds the entries other plugins hand in
205 + // through `xspeed_recommendations`. Only the Overview
206 + // card asks for them; see all_with_contributed().
207 + 'include' => array(
208 + 'type' => 'string',
209 + 'enum' => array( '', 'contributed' ),
210 + ),
211 + ),
184 212 )
185 213 );
186 214
187 215 register_rest_route(
@@ -340,10 +368,12 @@
340 368 }
341 369
342 370 /** Ranked "next best action" recommendations (issue #48). */
343 371 public function recommendations( $request ) {
344 - unset( $request );
345 - return rest_ensure_response( array( 'recommendations' => Recommendations::all() ) );
372 + $recs = 'contributed' === (string) $request->get_param( 'include' )
373 + ? Recommendations::all_with_contributed()
374 + : Recommendations::all();
375 + return rest_ensure_response( array( 'recommendations' => $recs ) );
346 376 }
347 377
348 378 /** One-click apply of a recommendation's settings fix. */
349 379 public function recommendations_apply( $request ) {
@@ -410,8 +440,14 @@
410 440 'server_type' => $server_type,
411 441 'snippet' => Cache::nginx_snippet(),
412 442 'topology' => Server::rewrite_topology(),
413 443 'behind_proxy' => Server::is_behind_proxy(),
444 + // Whether the rules the web server is running are the rules
445 + // these settings generate — `current`, `stale`, `absent` or
446 + // `unknown`, with the hashes both sides compared. Nothing
447 + // else can answer that: the nginx block lives in a server
448 + // config WordPress cannot read. See Cache::rules_state().
449 + 'rules' => Cache::rules_state( $probe ),
414 450 );
415 451 }
416 452
417 453 return rest_ensure_response(
@@ -438,9 +474,16 @@
438 474 // the user hasn't confirmed they actually need it. The dashboard
439 475 // renders a callout (+ "Check now" equality probe) from these.
440 476 'mobile_separate' => array(
441 477 'enabled' => ! empty( Settings::get()['cache_enabled'] ) ? (bool) ( Settings_Manager::get( 'cache' )['mobile_separate'] ?? false ) : false,
442 - 'blocking' => $rewrite_capable && 'mobile_separate' === Cache::static_rewrite_block_reason(),
478 + // Gated to servers that HAVE a static fast path — see the
479 + // matching comment in Admin::bootstrap_payload(): on IIS /
480 + // unknown, block_reason still falls through to
481 + // mobile_separate and reporting it as "blocking" would nag
482 + // about a rewrite that does not exist there (#108).
483 + // LiteSpeed joined the capable set with the opt-in (#509).
484 + 'blocking' => ( $rewrite_capable || Server::LITESPEED === $server_type )
485 + && 'mobile_separate' === Cache::static_rewrite_block_reason(),
443 486 'needs_review' => Cache::mobile_separate_needs_review(),
444 487 ),
445 488 )
446 489 );
@@ -541,10 +584,45 @@
541 584 'server_type' => $server_type,
542 585 'snippet' => Cache::nginx_snippet(),
543 586 'topology' => Server::rewrite_topology(),
544 587 'behind_proxy' => Server::is_behind_proxy(),
588 + // The whole reason to re-run the probe is usually that the
589 + // user just pasted the block, so this is where they most need
590 + // to be told whether the installed rules are the current ones.
591 + // It was only ever on /status before, which the CLI and MCP
592 + // recheck paths never call. See Cache::rules_state().
593 + 'rules' => $probe['rules'],
545 594 )
546 595 );
596 + }
597 +
598 + /**
599 + * Remember that this admin copied the current rules block.
600 + *
601 + * The mirror of the panel's own localStorage note, for the one case that
602 + * note cannot cover: a host where the probe returns `unknown` — blocked
603 + * loopback, or a CDN answering it — and a second admin, or the same admin
604 + * on another machine, is otherwise told to paste a block that is already
605 + * installed. Stored per user because it is a claim a person made.
606 + *
607 + * The hash is the rules marker, and a value that is not one is refused
608 + * rather than stored: the mirror is only useful while it holds something
609 + * rules_marker_expected() could also produce.
610 + */
611 + public function nginx_copied_hash( \WP_REST_Request $request ) {
612 + $params = (array) $request->get_json_params();
613 + $hash = isset( $params['hash'] ) ? (string) $params['hash'] : (string) $request->get_param( 'hash' );
614 +
615 + $stored = Cache::remember_rules_copied( $hash );
616 + if ( null === $stored ) {
617 + return new \WP_Error(
618 + 'xspeed_invalid_rules_hash',
619 + __( 'That is not a rules marker this site could have generated.', 'xspeed' ),
620 + array( 'status' => 400 )
621 + );
622 + }
623 +
624 + return rest_ensure_response( array( 'copied' => $stored ) );
547 625 }
548 626
549 627 public function toggle_cache( \WP_REST_Request $request ) {
550 628 $params = $request->get_json_params();