# xspeed/1.0.3/includes/class-plugin.php

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

- Page: https://pluginprobe.com/plugins/xspeed/1.0.3/code/includes/class-plugin.php
- Raw: https://pluginprobe.com/plugins/xspeed/1.0.3/raw/includes/class-plugin.php
- Modified: 2026-06-02T05:31:36+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.3/code/includes/class-plugin.php#L10-L20`.

```php
<?php
/**
 * Main plugin bootstrap.
 *
 * @package XSpeed
 */

namespace XSpeed;

defined( 'ABSPATH' ) || exit;

class Plugin {

	private static $instance = null;

	public static function instance() {
		if ( null === self::$instance ) {
			self::$instance = new self();
		}
		return self::$instance;
	}

	public function init() {
		// v1 services that are NOT yet wrapped as Modules (Admin, Rest_Api,
		// Cache, Onboarding) are instantiated directly. Minifier is now
		// instantiated by MinifyModule::boot(); Gzip is purely static.
		new Admin();
		new Rest_Api();
		new Cache();
		new Onboarding();

		// Auto-heal the cache drop-in + WP_CACHE constant when state
		// drifts. Scoped to admin_init only: filesystem writes belong in
		// an authenticated admin context, never on anonymous front-end
		// requests. The user already opted in (cache_enabled=true) —
		// this is a consistency check, not a new install path. First
		// admin page load after a plugin upgrade restores the state;
		// front-end then serves from cache on the next request.
		add_action( 'admin_init', array( Cache::class, 'auto_heal' ) );

		// Per-post cache rules (Phase 3.4) — registers postmeta with
		// REST + meta box on edit screens.
		Cache_Meta_Box::boot();

		// Phase 0 architecture — managers + Free modules. v1 services
		// (Cache/Minifier/Gzip) are NOT yet Modules; they'll be refactored
		// in a follow-up PR with parity tests.
		Conflict_Registry::boot();

		// Register Free modules via the same action xspeed-pro uses, so
		// the bootstrap path is symmetric across tiers.
		add_action( 'xspeed_register_modules', array( $this, 'register_free_modules' ) );

		// Fire the registration action + boot the registry at a LATER
		// plugins_loaded priority so add-on plugins (xspeed-pro, in
		// alphabetical order so it runs at default priority 10 AFTER
		// us, but any add-on loaded at plugins_loaded(< 20)) have a
		// chance to register their `xspeed_register_modules` callback
		// before we fire the action.
		//
		// Bug history: previously this fired inline from init() at
		// priority 10. xspeed-pro's plugins_loaded(15) hook then added
		// its register_pro_modules callback AFTER the action had
		// already fired — Pro modules never appeared in the registry.
		// Caught by the ProStatus sentinel module's integration test.
		add_action( 'plugins_loaded', array( $this, 'fire_module_lifecycle' ), 20 );
	}

	/**
	 * Phase 2 of plugin init: fire the registration action (collecting
	 * Free + Pro + any third-party modules hooked into
	 * `xspeed_register_modules`) and boot the registry.
	 *
	 * Runs at plugins_loaded(20) so every add-on that hooks at any
	 * priority < 20 has time to register first.
	 */
	public function fire_module_lifecycle(): void {
		/**
		 * Action: xspeed_register_modules
		 *
		 * Free modules register at priority 10; xspeed-pro at priority
		 * 20; site code can hook in between to inject custom modules.
		 * Fires exactly once per request.
		 */
		do_action( 'xspeed_register_modules' );

		Module_Registry::boot_all();
	}

	/**
	 * Register the Free Modules shipped in this plugin. Add new module
	 * registrations here. Pro plugin hooks the same action separately.
	 */
	public function register_free_modules(): void {
		Module_Registry::register( new \XSpeed\Modules\Cache\CacheModule() );
		Module_Registry::register( new \XSpeed\Modules\Health\HealthModule() );
		Module_Registry::register( new \XSpeed\Modules\Preloader\PreloaderModule() );
		Module_Registry::register( new \XSpeed\Modules\Heartbeat\HeartbeatModule() );
		Module_Registry::register( new \XSpeed\Modules\Minify\MinifyModule() );
		Module_Registry::register( new \XSpeed\Modules\Gzip\GzipModule() );
		Module_Registry::register( new \XSpeed\Modules\Lazy\LazyModule() );
		Module_Registry::register( new \XSpeed\Modules\Bloat\BloatModule() );
		Module_Registry::register( new \XSpeed\Modules\Database\DatabaseModule() );
		Module_Registry::register( new \XSpeed\Modules\Cdn\CdnModule() );
		Module_Registry::register( new \XSpeed\Modules\Cloudflare\CloudflareModule() );
		Module_Registry::register( new \XSpeed\Modules\ObjectCache\ObjectCacheModule() );
		Module_Registry::register( new \XSpeed\Modules\BrowserCache\BrowserCacheModule() );
		Module_Registry::register( new \XSpeed\Modules\Fonts\FontsModule() );
	}

	public static function activate() {
		Settings::set_defaults();

		if ( ! file_exists( XSPEED_CACHE_DIR ) ) {
			wp_mkdir_p( XSPEED_CACHE_DIR );
		}
		Cache::write_silence( XSPEED_CACHE_DIR );

		// Drop-in installation (advanced-cache.php) and the WP_CACHE constant
		// edit happen only when the user explicitly enables caching from the
		// admin UI — never on activation. See Cache::toggle() and
		// Rest_Api::toggle_cache(). This is a WordPress.org review requirement.

		// First-run wizard: flag a one-time redirect for the activating user.
		// Suppressed for bulk activations / already-completed sites in
		// Onboarding::maybe_redirect().
		Onboarding::flag_redirect();

		// Propagate activation to every registered Module. Activation
		// happens after plugins_loaded → modules are already registered.
		Module_Registry::activate_all();
	}

	public static function deactivate() {
		// Drop-in + WP_CACHE constant are NOT touched here. WordPress
		// upgrades run as deactivate → wipe files → install → activate,
		// so removing those artifacts on every deactivate would silently
		// disable caching after each plugin update. uninstall.php
		// handles full teardown when the user actually removes the
		// plugin; auto_heal() restores state on the next admin_init if
		// the drop-in or WP_CACHE went missing for any other reason.
		Cache::purge_all();
		Minifier::purge_minified();
		Gzip::apply( false );

		Module_Registry::deactivate_all();
	}
}

```
