'Minify', 'icon' => 'Wand2', 'description' => 'Strip whitespace and rewrite enqueued CSS / JS.', ); } public function settings_schema(): array { return array( 'minify_html' => array( 'type' => 'bool', 'default' => false, 'label' => 'Minify HTML', 'description' => 'Strip whitespace and comments from HTML output. Safe on most themes.', ), 'minify_css' => array( 'type' => 'bool', 'default' => false, 'label' => 'Minify CSS', 'description' => 'Compress and rewrite enqueued local stylesheets. External CSS is left untouched.', ), 'minify_js' => array( 'type' => 'bool', 'default' => false, 'label' => 'Minify JavaScript', 'description' => 'Compress enqueued local scripts. Disable if you hit script-loading conflicts on the frontend.', ), 'defer_js' => array( 'type' => 'bool', 'default' => false, 'label' => 'Defer JavaScript', 'description' => 'Add defer="defer" to enqueued script tags so they execute after HTML parsing. jQuery + its hard dependencies are skipped automatically.', ), 'delay_js' => array( 'type' => 'bool', 'default' => false, 'label' => 'Delay JavaScript Until Interaction', 'description' => 'Postpone script loading until the visitor scrolls, moves the mouse, taps, or presses a key. Drastically improves first paint on script-heavy pages; can break above-the-fold scripted UI — test before leaving on.', ), 'async_css' => array( 'type' => 'bool', 'default' => false, 'label' => 'Load CSS Asynchronously', 'description' => 'Rewrite stylesheet link tags to load non-blocking via the print-then-all pattern. Pairs well with critical-CSS workflows; can cause a flash of unstyled content if the theme has no critical CSS.', ), 'remove_query_strings' => array( 'type' => 'bool', 'default' => false, 'label' => 'Remove Asset Query Strings', 'description' => 'Strip ?ver=X.Y from enqueued CSS / JS URLs. Some CDN caches and proxies cache better when query strings are absent.', ), 'defer_js_excluded' => array( 'type' => 'list', 'default' => array( 'jquery-core', 'jquery-migrate' ), 'item_type' => 'string', 'label' => 'Defer / Delay Exclusions', 'description' => 'Script handles OR URL substrings that skip defer + delay. Defaults exclude jQuery (most themes depend on it being available synchronously). One per line.', ), 'combine_css' => array( 'type' => 'bool', 'default' => false, 'label' => 'Combine CSS Files', 'description' => 'Concatenate enqueued local stylesheets into a single file (with @import and url(…) paths resolved). External CSS is left alone. Pairs poorly with HTTP/2 push — only enable on HTTP/1.1 hosts.', ), 'combine_js' => array( 'type' => 'bool', 'default' => false, 'label' => 'Combine JavaScript Files', 'description' => 'Concatenate enqueued local scripts into a single file. External scripts + scripts marked async / deferred are left alone. Disable if you hit dependency-order issues; the combiner respects WordPress enqueue order but inline scripts attached via wp_add_inline_script can shift behavior.', ), ); } /** * 1.1.0: drain minify_html / minify_css / minify_js from the legacy * `xspeed_options` blob into this module's per-module option, then * delete the keys from the legacy blob so duplicate sources can't * re-appear. Idempotent — re-running is a no-op once the keys are * gone from xspeed_options. */ public function migrations(): array { return array( '1.1.0' => static function ( array $opts ): array { $legacy = get_option( 'xspeed_options', array() ); if ( ! is_array( $legacy ) ) { return $opts; } $dirty = false; foreach ( array( 'minify_html', 'minify_css', 'minify_js' ) as $key ) { if ( array_key_exists( $key, $legacy ) ) { $opts[ $key ] = (bool) $legacy[ $key ]; unset( $legacy[ $key ] ); $dirty = true; } } if ( $dirty ) { update_option( 'xspeed_options', $legacy ); } return $opts; }, ); } /** * Conflict declarations. Detected automatically by Conflict_Registry, * but listing them here keeps the module self-documenting. */ public function conflicts(): array { return array( array( 'plugin' => 'autoptimize/autoptimize.php', 'feature' => 'minify.html', 'strategy' => \XSpeed\Conflict_Registry::STRATEGY_REFUSE, 'reason' => 'Autoptimize is active and handles minification.', ), array( 'plugin' => 'wp-rocket/wp-rocket.php', 'feature' => 'minify.html', 'strategy' => \XSpeed\Conflict_Registry::STRATEGY_REFUSE, 'reason' => 'WP Rocket already handles minification.', ), ); } public function cli_commands(): array { return array( array( 'name' => 'xspeed minify', 'callback' => array( $this, 'cli_handler' ), 'shortdesc' => 'Inspect or purge xSpeed minify cache.', 'synopsis' => array( array( 'type' => 'positional', 'name' => 'action', 'options' => array( 'status', 'purge' ), 'optional' => false, ), ), ), ); } /** * On boot: * 1. Seed our per-module option from the legacy blob if neither * our option nor the migration has run yet (covers the * already-installed-before-this-module-shipped path). * 2. Instantiate the v1 Minifier engine; it now reads from * Settings_Manager::get('minify') via its updated read path. */ public function boot(): void { $this->seed_from_legacy_if_needed(); new LegacyMinifier(); } public function activate(): void { // Plugin activation hits all modules. Same seed logic — safe to // run more than once. $this->seed_from_legacy_if_needed(); } private function seed_from_legacy_if_needed(): void { $existing = get_option( 'xspeed_module_minify', null ); if ( null !== $existing ) { return; } $legacy = get_option( 'xspeed_options', array() ); if ( ! is_array( $legacy ) ) { return; } $seed = array( '_version' => self::VERSION ); $dirty = false; foreach ( array( 'minify_html', 'minify_css', 'minify_js' ) as $key ) { if ( array_key_exists( $key, $legacy ) ) { $seed[ $key ] = (bool) $legacy[ $key ]; unset( $legacy[ $key ] ); $dirty = true; } } if ( $dirty ) { update_option( 'xspeed_module_minify', $seed ); update_option( 'xspeed_options', $legacy ); } } public function cli_handler( array $args, array $assoc ): void { $action = $args[0] ?? 'status'; if ( 'status' === $action ) { $opts = Settings_Manager::get( self::SLUG ); \WP_CLI::log( sprintf( 'minify_html: %s', $opts['minify_html'] ? 'on' : 'off' ) ); \WP_CLI::log( sprintf( 'minify_css : %s', $opts['minify_css'] ? 'on' : 'off' ) ); \WP_CLI::log( sprintf( 'minify_js : %s', $opts['minify_js'] ? 'on' : 'off' ) ); return; } if ( 'purge' === $action ) { LegacyMinifier::purge_minified(); \WP_CLI::success( 'Minify cache purged.' ); return; } \WP_CLI::error( "Unknown action: $action" ); } }