tag string, the * handle, and the src. We bail when: * - the user excluded this handle / src substring, * - the tag already has defer or async (don't double-set), * - the tag has no src (inline scripts can't be deferred — would * execute synchronously regardless). * * @param string $tag * @param string $handle * @param string $src */ public static function defer_script_tag( $tag, $handle, $src ): string { if ( ! is_string( $tag ) || '' === $tag ) { return (string) $tag; } if ( '' === (string) $src ) { return $tag; } if ( self::is_excluded_script( (string) $handle, (string) $src ) ) { return $tag; } if ( false !== stripos( $tag, ' defer' ) || false !== stripos( $tag, ' async' ) ) { return $tag; } return (string) preg_replace( '#]*)>#i', '', $tag, 1 ); } /** * Inline bootstrap that flips delayed scripts on the first user * interaction. Printed once on wp_footer priority 1000. */ public static function print_delay_bootstrap(): void { if ( self::$delay_bootstrap_printed ) { return; } self::$delay_bootstrap_printed = true; // Tiny vanilla bootstrap; keep it self-contained so the page // has no JS dependencies before the first interaction. ?> fallback so * users with JS disabled still get styles applied (via media="all"). * * @param string $tag * @param string $handle */ public static function async_style_tag( $tag, $handle ): string { if ( ! is_string( $tag ) || '' === $tag ) { return (string) $tag; } // Only operate on with a media attribute // we can swap. Skip anything custom (preload, etc.) — we don't // want to fight with explicit author intent. if ( false === stripos( $tag, 'rel=\'stylesheet\'' ) && false === stripos( $tag, 'rel="stylesheet"' ) ) { return $tag; } // Avoid double-wrapping. if ( false !== stripos( $tag, 'data-xs-async' ) ) { return $tag; } $async = (string) preg_replace_callback( '#\bmedia\s*=\s*(["\'])([^"\']*)\1#i', static function ( $m ) { $orig = $m[2]; return 'media="print" onload="this.media=\'' . esc_attr( $orig ) . '\'" data-xs-async="' . esc_attr( $orig ) . '"'; }, $tag, 1 ); // If no media= was present (rare), inject one. if ( $async === $tag ) { $async = (string) preg_replace( '#. return $async . ''; } /** * Filter: `style_loader_src` + `script_loader_src` — strip the * ?ver=X.Y query string that WP appends for cache busting. Some * CDNs / reverse proxies cache better when the URL has no query. * * Skip URLs whose query carries non-ver params — those might be * intentional (e.g. a CDN providing per-image transforms). * * @param string $src */ public static function strip_version_query( $src ): string { if ( ! is_string( $src ) || '' === $src ) { return (string) $src; } $parts = wp_parse_url( $src ); if ( ! is_array( $parts ) || empty( $parts['query'] ) ) { return $src; } parse_str( $parts['query'], $query ); if ( ! is_array( $query ) ) { return $src; } // Only strip 'ver' — keep anything else the asset URL needs. unset( $query['ver'] ); $new_query = http_build_query( $query ); $new_url = ( $parts['scheme'] ?? 'http' ) . '://' . ( $parts['host'] ?? '' ); if ( isset( $parts['port'] ) ) { $new_url .= ':' . $parts['port']; } $new_url .= $parts['path'] ?? ''; if ( '' !== $new_query ) { $new_url .= '?' . $new_query; } if ( ! empty( $parts['fragment'] ) ) { $new_url .= '#' . $parts['fragment']; } return $new_url; } private static function is_excluded_script( string $handle, string $src ): bool { $opts = self::opts(); $excluded = is_array( $opts['defer_js_excluded'] ?? null ) ? $opts['defer_js_excluded'] : array(); if ( empty( $excluded ) ) { return false; } foreach ( $excluded as $needle ) { $needle = (string) $needle; if ( '' === $needle ) { continue; } if ( $handle === $needle || false !== stripos( $src, $needle ) ) { return true; } } return false; } private static function opts(): array { if ( null === self::$opts ) { self::$opts = Settings_Manager::get( 'minify' ); } return self::$opts; } /** * Test-only — clear cached opts + bootstrap-printed flag. */ public static function reset_state(): void { self::$opts = null; self::$delay_bootstrap_printed = false; } }