__( 'xSpeed static-rewrite cache', 'xspeed' ), 'test' => array( $this, 'site_status_static_rewrite' ), ); return $tests; } /** * Site Health test row. Reports green when the .htaccess block is * present (Apache/LiteSpeed) or yellow with the nginx snippet * embedded when nginx is detected. Skipped entirely when cache is * disabled — no point telling the user to install a rewrite they * haven't opted into. */ public function site_status_static_rewrite(): array { $result = array( 'label' => __( 'xSpeed static-rewrite cache is active', 'xspeed' ), 'status' => 'good', 'badge' => array( 'label' => __( 'Performance', 'xspeed' ), 'color' => 'blue', ), 'description' => '

' . esc_html__( 'Cache hits bypass PHP for ~5-15ms TTFB.', 'xspeed' ) . '

', 'test' => 'xspeed_static_rewrite', ); $cache_enabled = (bool) ( \XSpeed\Settings::get()['cache_enabled'] ?? false ); if ( ! $cache_enabled ) { $result['label'] = __( 'xSpeed cache is disabled', 'xspeed' ); $result['status'] = 'recommended'; $result['description'] = '

' . esc_html__( 'Enable the page cache in the xSpeed dashboard to start serving cached HTML for non-logged-in visitors.', 'xspeed' ) . '

'; return $result; } $server_type = \XSpeed\Server::type(); if ( \XSpeed\Server::APACHE === $server_type || \XSpeed\Server::LITESPEED === $server_type ) { if ( ! \XSpeed\Cache::rewrite_installed() ) { $result['label'] = __( 'xSpeed .htaccess rewrite block is missing', 'xspeed' ); $result['status'] = 'recommended'; $result['description'] = '

' . esc_html__( 'Without the static-rewrite block, cache hits go through the PHP drop-in (~85ms TTFB) instead of the web server (~5-15ms). Toggle Enable Cache off and on in xSpeed to reinstall the block.', 'xspeed' ) . '

'; } return $result; } if ( \XSpeed\Server::NGINX === $server_type ) { $snippet = \XSpeed\Cache::nginx_snippet(); $result['label'] = __( 'xSpeed nginx server config required', 'xspeed' ); $result['status'] = 'recommended'; $result['description'] = '

' . esc_html__( 'xSpeed can\'t write nginx config from PHP. Paste this snippet into your site\'s server { } block, then reload nginx so cache hits serve without booting PHP:', 'xspeed' ) . '

' . '
'
				. esc_html( (string) $snippet )
				. '
'; return $result; } // Unknown / IIS — no server-level rewrite path available; PHP // drop-in is the best we can offer. Don't flag as broken. $result['label'] = __( 'xSpeed PHP drop-in cache active', 'xspeed' ); $result['status'] = 'recommended'; $result['description'] = '

' . esc_html__( 'Static-rewrite caching needs Apache, LiteSpeed, or nginx. The PHP drop-in is still serving cache hits at ~85ms TTFB on this server.', 'xspeed' ) . '

'; return $result; } public function ui_metadata(): array { return array( 'label' => 'Health', 'icon' => 'HeartPulse', 'description' => 'Diagnostics, hit ratio, and recent cache activity.', // Tells the React side to render HealthCard instead of // schema-driven settings (SETTINGS.md §6.2 allows custom // panels for non-settings surfaces). 'custom_panel' => 'HealthCard', ); } // No settings — explicit empty so Module::rest_routes() doesn't // auto-wire the schema-driven GET+POST. public function settings_schema(): array { return array(); } public function rest_routes(): array { return array( array( 'path' => '/', 'methods' => 'GET', 'callback' => array( $this, 'rest_get_payload' ), ), ); } public function cli_commands(): array { return array( array( 'name' => 'xspeed health', 'callback' => array( $this, 'cli_handler' ), 'shortdesc' => 'Print diagnostic checks + cache stats + recent activity.', 'synopsis' => array(), ), ); } /** * Single endpoint that backs the dashboard panel. Refreshed lazily by * the React side; cheap enough that aggregating into one response is * the right call (the buckets array is at most 24 entries; activity * is capped at 50). */ public function rest_get_payload( \WP_REST_Request $request ) { return rest_ensure_response( $this->payload() ); } public function payload(): array { return array( 'checks' => Health::checks(), 'stats' => Cache::get_stats(), 'buckets' => Hit_Counter::buckets(), 'activity' => Activity_Log::entries(), ); } public function cli_handler( array $args, array $assoc ): void { $payload = $this->payload(); \WP_CLI::log( '== Checks ==' ); foreach ( $payload['checks'] as $c ) { \WP_CLI::log( sprintf( '[%s] %s — %s', strtoupper( $c['tone'] ), $c['label'], $c['detail'] ) ); } \WP_CLI::log( '' ); \WP_CLI::log( '== Stats (24h) ==' ); \WP_CLI::log( sprintf( 'Hits %d · Misses %d · Hit ratio %.2f%%', $payload['stats']['hits_24h'], $payload['stats']['misses_24h'], $payload['stats']['hit_ratio'] * 100 ) ); \WP_CLI::log( '' ); \WP_CLI::log( '== Recent activity ==' ); foreach ( array_slice( $payload['activity'], 0, 10 ) as $e ) { \WP_CLI::log( sprintf( '%s [%s] %s', gmdate( 'Y-m-d H:i:s', $e['ts'] ), $e['severity'], $e['message'] ) ); } } }