# xspeed/1.0.4/includes/class-rest-api.php

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

- Page: https://pluginprobe.com/plugins/xspeed/1.0.4/code/includes/class-rest-api.php
- Raw: https://pluginprobe.com/plugins/xspeed/1.0.4/raw/includes/class-rest-api.php
- Modified: 2026-06-14T07:01:26+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.4/code/includes/class-rest-api.php#L10-L20`.

```php
<?php
/**
 * REST API endpoints.
 *
 * @package XSpeed
 */

namespace XSpeed;

defined( 'ABSPATH' ) || exit;

class Rest_Api {

	const NAMESPACE_V1 = 'xspeed/v1';

	public function __construct() {
		add_action( 'rest_api_init', array( $this, 'register' ) );
	}

	public function register() {
		register_rest_route(
			self::NAMESPACE_V1,
			'/status',
			array(
				'methods'             => 'GET',
				'callback'            => array( $this, 'get_status' ),
				'permission_callback' => array( $this, 'permissions' ),
			)
		);

		register_rest_route(
			self::NAMESPACE_V1,
			'/settings',
			array(
				array(
					'methods'             => 'GET',
					'callback'            => array( $this, 'get_settings' ),
					'permission_callback' => array( $this, 'permissions' ),
				),
				array(
					'methods'             => 'POST',
					'callback'            => array( $this, 'update_settings' ),
					'permission_callback' => array( $this, 'permissions' ),
				),
			)
		);

		register_rest_route(
			self::NAMESPACE_V1,
			'/cache/purge',
			array(
				'methods'             => 'POST',
				'callback'            => array( $this, 'purge' ),
				'permission_callback' => array( $this, 'permissions' ),
			)
		);

		register_rest_route(
			self::NAMESPACE_V1,
			'/cache/toggle',
			array(
				'methods'             => 'POST',
				'callback'            => array( $this, 'toggle_cache' ),
				'permission_callback' => array( $this, 'permissions' ),
			)
		);

		register_rest_route(
			self::NAMESPACE_V1,
			'/cache/benchmark',
			array(
				'methods'             => 'GET',
				'callback'            => array( $this, 'benchmark' ),
				'permission_callback' => array( $this, 'permissions' ),
			)
		);

		register_rest_route(
			self::NAMESPACE_V1,
			'/audit/pro',
			array(
				'methods'             => 'GET',
				'callback'            => array( $this, 'pro_audit' ),
				'permission_callback' => array( $this, 'permissions' ),
			)
		);

		register_rest_route(
			self::NAMESPACE_V1,
			'/modules',
			array(
				'methods'             => 'GET',
				'callback'            => array( $this, 'get_modules' ),
				'permission_callback' => array( $this, 'permissions' ),
			)
		);
	}

	/**
	 * The registered-module descriptors — same payload baked into the
	 * admin bootstrap (Admin::modules_payload), re-evaluated live. The
	 * dashboard re-fetches this after a license activate/deactivate so a
	 * Pro module's custom_panel flips between its real surface and
	 * LicenseLockedPanel (decided server-side via the
	 * xspeed_module_descriptor filter) WITHOUT a full page reload.
	 */
	public function get_modules() {
		return rest_ensure_response( Admin::modules_payload() );
	}

	/**
	 * Run the Pro audit — scans current settings + cache stats,
	 * returns a personalized list of Pro features that would help
	 * THIS site. See Pro_Audit::run() for the rule set.
	 */
	public function pro_audit( $request ) {
		unset( $request );
		return rest_ensure_response( array( 'suggestions' => Pro_Audit::run() ) );
	}

	/**
	 * Cache before/after benchmark — fetches home_url() twice (with +
	 * without the bypass header) and returns side-by-side timings for
	 * the dashboard widget.
	 */
	public function benchmark( $request ) {
		unset( $request );
		return rest_ensure_response( Cache_Benchmark::run() );
	}

	public function permissions() {
		return current_user_can( 'manage_options' );
	}

	public function get_status() {
		$opts  = Settings::get();
		$stats = Cache::get_stats();

		// rewrite_probe + nginx_server_block mirror the admin bootstrap
		// payload (Admin::bootstrap_data). The dashboard re-fetches /status
		// after every module save to refresh the consolidated nginx
		// server-block snippet without a full page reload — if these were
		// omitted here, the snippet would only ever update on reload (the
		// QA bug: "Server config snippet requires full page reload to
		// reflect toggle changes"). Keep this in sync with Admin.
		$server_type     = Server::type();
		$rewrite_capable = ( $server_type === Server::NGINX || $server_type === Server::APACHE || $server_type === Server::LITESPEED );
		$rewrite_probe   = null;
		if ( $opts['cache_enabled'] && $rewrite_capable ) {
			$probe         = Cache::probe_static_rewrite();
			$rewrite_probe = array(
				'active'       => (bool) ( $probe['active'] ?? false ),
				'server_type'  => $server_type,
				'snippet'      => Cache::nginx_snippet(),
				'topology'     => Server::rewrite_topology(),
				'behind_proxy' => Server::is_behind_proxy(),
			);
		}

		return rest_ensure_response(
			array(
				'enabled'            => (bool) $opts['cache_enabled'],
				'stats'              => $stats,
				'server'             => array(
					'type'           => $server_type,
					'gzip_mode'      => Server::gzip_mode(),
					'gzip_active'    => Gzip::probe_active(),
					'nginx_snippet'  => Gzip::nginx_snippet(),
				),
				'rewrite_probe'      => $rewrite_probe,
				'nginx_server_block' => Cache::full_nginx_server_block(),
			)
		);
	}

	public function get_settings() {
		return rest_ensure_response( Settings::get() );
	}

	public function update_settings( \WP_REST_Request $request ) {
		$params  = $request->get_json_params();
		if ( ! is_array( $params ) ) {
			$params = $request->get_params();
		}
		// `cache_enabled` is the trigger for drop-in install / wp-config.php
		// edit and must only flow through the dedicated /cache/toggle
		// endpoint. Strip it here so generic settings updates can never
		// implicitly write a drop-in or modify wp-config.php.
		unset( $params['cache_enabled'] );
		$updated = Settings::update( $params );
		return rest_ensure_response( $updated );
	}

	public function purge() {
		Cache::purge_all();
		return rest_ensure_response( array( 'stats' => Cache::get_stats() ) );
	}

	public function toggle_cache( \WP_REST_Request $request ) {
		$params  = $request->get_json_params();
		$enabled = isset( $params['enabled'] ) ? (bool) $params['enabled'] : false;

		// User-explicit drop-in install / wp-config.php edit happens here.
		// permission_callback above already enforced current_user_can(
		// 'manage_options' ); the REST nonce is verified by core via the
		// X-WP-Nonce header.
		$state   = Cache::toggle( $enabled );
		$updated = Settings::update( array( 'cache_enabled' => $state['enabled'] ) );

		return rest_ensure_response(
			array(
				'enabled'       => $updated['cache_enabled'],
				'stats'         => Cache::get_stats(),
				'install_state' => $state,
			)
		);
	}
}

```
