# xspeed/1.0.5/includes/class-health.php

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

- Page: https://pluginprobe.com/plugins/xspeed/1.0.5/code/includes/class-health.php
- Raw: https://pluginprobe.com/plugins/xspeed/1.0.5/raw/includes/class-health.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.5/code/includes/class-health.php#L10-L20`.

```php
<?php
/**
 * Health — shared diagnostic checks consumed by both Onboarding's
 * environment surface and the Health module's dashboard panel.
 *
 * Each check returns:
 *   [
 *     'id'     => 'wp_version',
 *     'tone'   => 'ok' | 'warn' | 'fail' | 'info',
 *     'label'  => 'WordPress 6.6',
 *     'detail' => 'Meets the 6.0+ minimum.',
 *   ]
 *
 * Pure reads — never writes to disk, never makes outbound HTTP calls.
 * Safe to call from any request including the loading dashboard.
 *
 * @package XSpeed
 */

declare(strict_types=1);

namespace XSpeed;

defined( 'ABSPATH' ) || exit;

final class Health {

	public const OK   = 'ok';
	public const WARN = 'warn';
	public const FAIL = 'fail';
	public const INFO = 'info';

	private const SERVER_LABELS = array(
		'apache'    => 'Apache',
		'litespeed' => 'LiteSpeed',
		'nginx'     => 'nginx',
		'iis'       => 'IIS',
		'unknown'   => 'Unknown',
	);

	/**
	 * Full check list used by the Health module's dashboard panel.
	 *
	 * @return array<int,array{id:string,tone:string,label:string,detail:string}>
	 */
	public static function checks(): array {
		global $wp_version;

		$server_type = Server::type();
		$gzip_mode   = Server::gzip_mode();
		$conflicts   = Server::conflicts();
		$cache_dir   = defined( 'XSPEED_CACHE_DIR' ) ? XSPEED_CACHE_DIR : ( WP_CONTENT_DIR . '/cache/xspeed' );

		$out = array();

		// WordPress version
		$wp_ok  = version_compare( (string) $wp_version, '6.0', '>=' );
		$out[]  = array(
			'id'     => 'wp_version',
			'tone'   => $wp_ok ? self::OK : self::FAIL,
			'label'  => sprintf( 'WordPress %s', (string) $wp_version ),
			'detail' => $wp_ok ? 'Meets the 6.0+ minimum.' : 'Upgrade to WordPress 6.0 or higher.',
		);

		// PHP version
		$php_ok      = version_compare( PHP_VERSION, '7.4', '>=' );
		$php_modern  = version_compare( PHP_VERSION, '8.1', '>=' );
		$out[]       = array(
			'id'     => 'php_version',
			'tone'   => $php_modern ? self::OK : ( $php_ok ? self::WARN : self::FAIL ),
			'label'  => sprintf( 'PHP %s', PHP_VERSION ),
			'detail' => $php_modern
				? 'Modern PHP — full speed.'
				: ( $php_ok
					? 'Works, but 8.1+ is recommended for best performance.'
					: 'Upgrade to PHP 7.4 or higher.' ),
		);

		// Server
		$out[] = array(
			'id'     => 'server',
			'tone'   => self::INFO,
			'label'  => sprintf( 'Server: %s', self::SERVER_LABELS[ $server_type ] ?? 'Unknown' ),
			'detail' => 'auto' === $gzip_mode
				? 'GZIP can be auto-configured via .htaccess.'
				: 'GZIP requires a manual server-config snippet (shown in the GZIP module).',
		);

		// Cache directory writable
		$dir_writable = wp_mkdir_p( $cache_dir ) && wp_is_writable( $cache_dir );
		$out[]        = array(
			'id'     => 'cache_dir',
			'tone'   => $dir_writable ? self::OK : self::FAIL,
			'label'  => 'Cache directory writable',
			'detail' => $dir_writable
				? $cache_dir
				: sprintf( 'Cannot write to %s. Adjust file permissions before enabling cache.', $cache_dir ),
		);

		// Drop-in installed (only when cache is enabled — otherwise N/A)
		$cache_enabled = (bool) Settings::get()['cache_enabled'];
		if ( $cache_enabled ) {
			$dropin_path  = WP_CONTENT_DIR . '/advanced-cache.php';
			$dropin_match = file_exists( $dropin_path ) && false !== strpos( (string) file_get_contents( $dropin_path ), 'xspeed' );
			$out[]        = array(
				'id'     => 'dropin',
				'tone'   => $dropin_match ? self::OK : self::FAIL,
				'label'  => 'advanced-cache.php drop-in',
				'detail' => $dropin_match
					? 'Installed and owned by xSpeed.'
					: 'Drop-in missing or owned by another plugin. Toggle Enable Cache off and on to reinstall.',
			);
		}

		// WP_CACHE constant
		$wp_cache_const = defined( 'WP_CACHE' ) && WP_CACHE;
		if ( $cache_enabled ) {
			$out[] = array(
				'id'     => 'wp_cache_constant',
				'tone'   => $wp_cache_const ? self::OK : self::WARN,
				'label'  => 'WP_CACHE constant',
				'detail' => $wp_cache_const
					? 'Defined and truthy in wp-config.php.'
					: 'Not set. Cache is configured but WordPress will not load the drop-in until WP_CACHE = true is added to wp-config.php.',
			);
		}

		// Static-rewrite probe. Active end-to-end check: writes a probe
		// file under the static-cache dir, fetches it over HTTP, and
		// confirms the web server (nginx OR Apache/LiteSpeed) served
		// the raw file. Result is throttled to a 5-minute transient
		// inside Cache::probe_static_rewrite so we never hit the
		// network per-paint.
		if ( $cache_enabled ) {
			$server_type = Server::type();
			// The live loopback probe only matters where a server-level static
			// rewrite is actually used (nginx snippet / Apache .htaccess).
			// LiteSpeed serves hits via the drop-in (see below), so skip the
			// probe there entirely — no needless self-request. Health is the
			// right place to pay for the probe when we DO run it (the admin
			// bootstrap reads cache-only so it never blocks); the 5-minute
			// transient still throttles repeat runs. (FBS-82142)
			$probe     = ( Server::LITESPEED === $server_type )
				? array( 'active' => false )
				: Cache::probe_static_rewrite( true );
			$is_active = (bool) ( $probe['active'] ?? false );

			if ( Server::NGINX === $server_type ) {
				$out[] = array(
					'id'      => 'static_rewrite_nginx',
					'tone'    => $is_active ? self::OK : self::WARN,
					'label'   => 'Static-file rewrite (nginx server config)',
					'detail'  => $is_active
						? 'nginx is serving cache hits directly — PHP bypassed (~5-15ms TTFB).'
						: 'nginx detected but not yet routing to the cache. Paste the snippet below into your site\'s server { } block, then reload nginx.',
					// Always ship the snippet — even when active, so the
					// admin has it handy for re-pasting after a server
					// rebuild without having to find it elsewhere. Mirror
					// the SAME unified block the "Server config" panel
					// renders (cache + gzip + browser-cache directives),
					// not the cache-only snippet — otherwise Health and
					// the Cache panel disagree on what to paste.
					'snippet' => Cache::full_nginx_server_block(),
				);
			} elseif ( Server::LITESPEED === $server_type ) {
				// LiteSpeed intentionally does NOT use the .htaccess static
				// rewrite: OpenLiteSpeed's .htaccess engine ignores
				// mod_headers (so we can't stamp X-XSpeed-Cache: HIT) and has
				// no per-rule access_log (so a static hit can't be counted).
				// We route LiteSpeed hits through the PHP drop-in instead, so
				// every hit is both visible (X-XSpeed-Cache: HIT) and counted
				// in the hit-ratio — see Cache::static_rewrite_allowed(). This
				// is the healthy, expected state on LiteSpeed, not a fallback.
				$out[] = array(
					'id'     => 'static_rewrite_litespeed',
					'tone'   => self::OK,
					'label'  => 'Cache serving (LiteSpeed)',
					'detail' => 'Cache hits are served by xSpeed\'s drop-in and tagged X-XSpeed-Cache: HIT — so every hit is visible and counted in your hit-ratio. (LiteSpeed\'s .htaccess can\'t add that header or log static hits, so xSpeed serves them itself for accurate reporting.)',
				);
			} elseif ( Server::APACHE === $server_type ) {
				$installed = Cache::rewrite_installed();
				if ( $is_active ) {
					$tone   = self::OK;
					$detail = 'Block installed and serving cache hits directly — PHP bypassed.';
				} elseif ( ! $installed ) {
					$tone   = self::WARN;
					$detail = 'Block missing from .htaccess. Toggle Enable Cache off and on to reinstall it.';
				} else {
					$tone   = self::WARN;
					$detail = sprintf( 'Block installed but probe failed (%s). Confirm the .htaccess block is at the TOP of the file, and that AllowOverride is enabled for your site so mod_rewrite reads it.', (string) ( $probe['reason'] ?? 'unknown' ) );
				}
				$out[] = array(
					'id'     => 'static_rewrite',
					'tone'   => $tone,
					'label'  => 'Static-file rewrite (.htaccess)',
					'detail' => $detail,
				);
			}
		}

		// Permalinks
		$permalinks_ok = (bool) get_option( 'permalink_structure' );
		$out[]         = array(
			'id'     => 'permalinks',
			'tone'   => $permalinks_ok ? self::OK : self::WARN,
			'label'  => 'Permalinks',
			'detail' => $permalinks_ok
				? 'Pretty permalinks active.'
				: 'Set permalinks to anything other than "Plain" — page caching needs URL paths to key on.',
		);

		// Conflicting plugins
		$out[] = array(
			'id'     => 'conflicts',
			'tone'   => empty( $conflicts ) ? self::OK : self::WARN,
			'label'  => 'Caching plugin conflicts',
			'detail' => empty( $conflicts )
				? 'No other caching plugins detected.'
				: sprintf( 'Active: %s. Deactivate before enabling xSpeed cache to avoid double-caching.', implode( ', ', $conflicts ) ),
		);

		return $out;
	}

	/**
	 * Lightweight environment payload for the onboarding wizard. Keeps
	 * the legacy shape Onboarding::env_payload returned so the Welcome
	 * step's HealthRow rendering doesn't change.
	 */
	public static function env_payload(): array {
		global $wp_version;
		$cache_dir = defined( 'XSPEED_CACHE_DIR' ) ? XSPEED_CACHE_DIR : ( WP_CONTENT_DIR . '/cache/xspeed' );
		return array(
			'wp'            => array(
				'version' => (string) $wp_version,
				'ok'      => version_compare( (string) $wp_version, '6.0', '>=' ),
			),
			'php'           => array(
				'version' => PHP_VERSION,
				'ok'      => version_compare( PHP_VERSION, '7.4', '>=' ),
				'modern'  => version_compare( PHP_VERSION, '8.1', '>=' ),
			),
			'server'        => array(
				'type'      => Server::type(),
				'gzip_mode' => Server::gzip_mode(),
			),
			'cache_dir'     => array(
				'path'     => $cache_dir,
				'writable' => wp_mkdir_p( $cache_dir ) && wp_is_writable( $cache_dir ),
			),
			'wp_config'     => array(
				'writable' => self::wp_config_writable(),
			),
			'permalinks_ok' => (bool) get_option( 'permalink_structure' ),
			'conflicts'     => Server::conflicts(),
		);
	}

	private static function wp_config_writable(): bool {
		$path = ABSPATH . 'wp-config.php';
		if ( ! file_exists( $path ) ) {
			$path = dirname( ABSPATH ) . '/wp-config.php';
		}
		return file_exists( $path ) && wp_is_writable( $path );
	}
}

```
