# xspeed/1.0.7/includes/modules/Health/HealthModule.php

xSpeed Cache: AI-Powered Performance Hub with MCP, Caching &amp; CDN, version 1.0.7. 192 lines.

- Page: https://pluginprobe.com/plugins/xspeed/1.0.7/code/includes/modules/Health/HealthModule.php
- Raw: https://pluginprobe.com/plugins/xspeed/1.0.7/raw/includes/modules/Health/HealthModule.php
- Modified: 2026-06-18T10:03:30+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/xspeed/1.0.7/code/includes/modules/Health/HealthModule.php#L10-L20`.

```php
<?php
/**
 * Health module — read-only diagnostic surface for the dashboard.
 *
 * No settings_schema (this is a status panel, not a configuration
 * surface). The React side renders a custom panel (HealthCard, declared
 * via `ui_metadata.custom_panel`) instead of going through ModulePanel's
 * schema-driven path.
 *
 * Data sources are all existing services:
 *   - Health::checks()          — diagnostic rows
 *   - Cache::get_stats()        — cached_pages / size / last_purge /
 *                                  hits_24h / misses_24h / hit_ratio
 *   - Hit_Counter::buckets()    — 24 hourly buckets for the sparkline
 *   - Activity_Log::entries()   — newest-first event log
 *
 * Tier: Free (per FEATURES.md "Cache Insights" — Cache Performance +
 * Last 24h chart are Free; Recommendations + Frequently-missed-URLs
 * stay Pro).
 *
 * @package XSpeed
 */

declare(strict_types=1);

namespace XSpeed\Modules\Health;

defined( 'ABSPATH' ) || exit;

use XSpeed\Activity_Log;
use XSpeed\Cache;
use XSpeed\Health;
use XSpeed\Hit_Counter;
use XSpeed\Module;

final class HealthModule extends Module {

	public const SLUG    = 'health';
	public const TIER    = self::TIER_FREE;
	public const VERSION = '1.0.0';

	/**
	 * Surface the most important diagnostics in WordPress's built-in
	 * Site Health screen (Tools → Site Health → Status). Admins who
	 * never open the xSpeed dashboard still get a heads-up when
	 * static-rewrite is missing on Apache/LiteSpeed or when the nginx
	 * snippet hasn't been pasted yet — both lead to a 5-10× slowdown
	 * vs the optimal cache hit path.
	 */
	public function boot(): void {
		add_filter( 'site_status_tests', array( $this, 'register_site_status_tests' ) );
	}

	public function register_site_status_tests( array $tests ): array {
		$tests['direct']['xspeed_static_rewrite'] = array(
			'label' => __( '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' => '<p>' . esc_html__( 'Cache hits bypass PHP for ~5-15ms TTFB.', 'xspeed' ) . '</p>',
			'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'] = '<p>' . esc_html__( 'Enable the page cache in the xSpeed dashboard to start serving cached HTML for non-logged-in visitors.', 'xspeed' ) . '</p>';
			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'] = '<p>' . 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' ) . '</p>';
			}
			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'] = '<p>' . 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' ) . '</p>'
				. '<pre style="white-space:pre;overflow-x:auto;background:#f6f7f7;border:1px solid #c3c4c7;border-radius:4px;padding:12px;font-size:12px;line-height:1.4;">'
				. esc_html( (string) $snippet )
				. '</pre>';
			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'] = '<p>' . 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' ) . '</p>';
		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'] ) );
		}
	}
}

```
