'GZIP', 'icon' => 'Layers', 'description' => 'Compress responses to reduce transfer size.', ); } public function settings_schema(): array { return array( 'gzip_enabled' => array( 'type' => 'bool', 'default' => false, 'label' => 'Enable GZIP Compression', 'description' => 'On Apache / LiteSpeed we write the .htaccess rules automatically. On nginx the snippet below must be added to your server config.', ), ); } /** * 1.1.0: drain gzip_enabled from the legacy xspeed_options blob into * this module's option. Idempotent — a re-run with the legacy key * already gone is a no-op. */ public function migrations(): array { return array( '1.1.0' => static function ( array $opts ): array { $legacy = get_option( 'xspeed_options', array() ); if ( ! is_array( $legacy ) || ! array_key_exists( 'gzip_enabled', $legacy ) ) { return $opts; } $opts['gzip_enabled'] = (bool) $legacy['gzip_enabled']; unset( $legacy['gzip_enabled'] ); update_option( 'xspeed_options', $legacy ); return $opts; }, ); } public function cli_commands(): array { return array( array( 'name' => 'xspeed gzip', 'callback' => array( $this, 'cli_handler' ), 'shortdesc' => 'Show GZIP status (server type, active, mode).', 'synopsis' => array(), ), ); } /** * Conditional notice published to the module's panel via * Module::ui_notices(). When gzip is enabled and the server can't * auto-configure (nginx / unknown / IIS), we surface a copy-able * snippet so the user can wire it up. */ public function ui_notices(): array { $opts = Settings_Manager::get( self::SLUG ); if ( empty( $opts['gzip_enabled'] ) ) { return array(); } // Probe the live response — works regardless of server type // (Apache, nginx, anything). If gzip is actually being served, // nothing else matters: hide the notice. Mirror's BrowserCache's // probe_headers_present() pattern. if ( LegacyGzip::probe_active() ) { return array(); } // Probe says NOT active and gzip is enabled — surface the right // notice per server topology. if ( 'auto' === Server::gzip_mode() ) { // Apache/LiteSpeed but probe failed — .htaccess write must // have been blocked, or another plugin is overriding. Tell // the user something is wrong, no snippet (we can't fix it // without their server access). return array( array( 'tone' => 'warn', 'title' => __( 'GZIP enabled but not active on the server', 'xspeed' ), 'body' => __( 'xSpeed wrote the .htaccess rules but the response still isn\'t gzipped. Your server may have AllowOverride disabled, another caching plugin overriding, or mod_deflate missing. Ask your host to enable GZIP on Apache.', 'xspeed' ), ), ); } // Manual server (nginx, IIS, unknown) — probe failed because // the user hasn't pasted the snippet (or hasn't reloaded nginx). $type = Server::type(); if ( 'nginx' === $type ) { return array( array( 'tone' => 'warn', 'title' => __( 'GZIP requires server config on nginx', 'xspeed' ), 'body' => __( 'xSpeed can only auto-configure GZIP on Apache and LiteSpeed (via .htaccess). The directives are included in the unified server-block snippet on the Cache panel — copy + paste it once into your nginx vhost (or container nginx config) and reload nginx.', 'xspeed' ), ), ); } // IIS / unknown server fallback — keep the legacy "paste this" // notice until a non-nginx unified-snippet surface ships. return array( array( 'tone' => 'warn', 'title' => __( 'GZIP requires server config on this server', 'xspeed' ), 'body' => __( 'xSpeed can only auto-configure GZIP on Apache and LiteSpeed (via .htaccess). Paste the snippet below into your server config and reload.', 'xspeed' ), 'snippet' => LegacyGzip::nginx_snippet(), ), ); } /** * Module booting: seed per-module option from legacy if needed, * then register the change hook that flips Apache / LiteSpeed * .htaccess rules whenever gzip_enabled is toggled. This handler * fires on writes to xspeed_module_gzip (not the legacy blob). */ public function boot(): void { $this->seed_from_legacy_if_needed(); add_action( 'update_option_xspeed_module_gzip', array( __CLASS__, 'on_settings_change' ), 10, 2 ); add_action( 'add_option_xspeed_module_gzip', array( __CLASS__, 'on_settings_added' ), 10, 2 ); } /** * Detect the gzip_enabled flip on write and apply / remove the * .htaccess rules. Idempotent — re-running with the same state is a * no-op inside LegacyGzip::apply(). */ public static function on_settings_change( $old, $new ): void { $old_gzip = is_array( $old ) ? ! empty( $old['gzip_enabled'] ) : false; $new_gzip = is_array( $new ) ? ! empty( $new['gzip_enabled'] ) : false; if ( $old_gzip !== $new_gzip ) { LegacyGzip::apply( $new_gzip ); // Settings just changed — current "probe says active" answer // is stale. Drop the transient so the next dashboard load // re-checks the live response. delete_transient( 'xspeed_gzip_active' ); } } /** * The very first write (option doesn't exist yet) hits add_option * instead of update_option. Treat it as old=false → new=current. */ public static function on_settings_added( $name, $value ): void { $enabled = is_array( $value ) ? ! empty( $value['gzip_enabled'] ) : false; if ( $enabled ) { LegacyGzip::apply( true ); } } public function activate(): void { $this->seed_from_legacy_if_needed(); } private function seed_from_legacy_if_needed(): void { if ( null !== get_option( 'xspeed_module_gzip', null ) ) { return; } $legacy = get_option( 'xspeed_options', array() ); if ( ! is_array( $legacy ) || ! array_key_exists( 'gzip_enabled', $legacy ) ) { return; } update_option( 'xspeed_module_gzip', array( '_version' => self::VERSION, 'gzip_enabled' => (bool) $legacy['gzip_enabled'], ) ); unset( $legacy['gzip_enabled'] ); update_option( 'xspeed_options', $legacy ); } public function cli_handler( array $args, array $assoc ): void { $opts = Settings_Manager::get( self::SLUG ); \WP_CLI::log( 'enabled ' . ( $opts['gzip_enabled'] ? 'true' : 'false' ) ); \WP_CLI::log( 'server ' . Server::type() ); \WP_CLI::log( 'mode ' . Server::gzip_mode() ); \WP_CLI::log( 'active ' . ( LegacyGzip::probe_active() ? 'true' : 'false' ) ); \WP_CLI::log( 'nginx_snippet ' . LegacyGzip::nginx_snippet() ); } /** * GZIP directives for the unified nginx server-block snippet. Null * when the module is disabled. */ public function nginx_directives(): ?string { $opts = Settings_Manager::get( self::SLUG ); if ( empty( $opts['gzip_enabled'] ) ) { return null; } $snippet = LegacyGzip::nginx_snippet(); return is_string( $snippet ) && '' !== $snippet ? $snippet : null; } }