options = get_option( 'aio_options', array() ); $this->site_host = strtolower( (string) wp_parse_url( home_url(), PHP_URL_HOST ) ); $this->home_path_prefix = rtrim( (string) wp_parse_url( home_url( '/' ), PHP_URL_PATH ), '/' ); if ( ! empty( $this->options['optEnableSmartLcp'] ) ) { add_action( 'wp_head', array( $this, 'output_lcp_featured_preload' ), 1 ); } if ( ! empty( $this->options['optCriticalCss'] ) ) { add_action( 'wp_head', array( $this, 'output_critical_css' ), 2 ); } if ( ! empty( $this->options['optEnableInstantPage'] ) ) { add_action( 'wp_footer', array( $this, 'output_instant_page_prefetch' ), 99 ); } if ( $this->needs_html_buffer() ) { add_action( 'template_redirect', array( $this, 'start_html_buffer' ), 1 ); } } private function needs_html_buffer() { $keys = array( 'optEnableSmartLcp', 'opt-perf-lazyload', 'optLazyLoadBg', 'optEnableAutoImageDims', 'optEnableWebpRewrite', 'optEnableFontSwap', 'optAsyncGoogleFonts', 'optSelfHostGoogleFonts', 'optEnableAsyncCss', 'optEnableYoutubeFacade', 'optEnableDelayJS', 'optEnableCdn', 'optEnableMinify', ); foreach ( $keys as $key ) { if ( ! empty( $this->options[ $key ] ) ) { return true; } } return false; } private function is_optimizable_request() { if ( is_admin() || aio_is_speed_safe_mode() ) { return false; } if ( ( function_exists( 'wp_doing_ajax' ) && wp_doing_ajax() ) || ( function_exists( 'wp_doing_cron' ) && wp_doing_cron() ) ) { return false; } if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) { return false; } if ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) { return false; } if ( is_feed() || is_preview() || is_customize_preview() || is_robots() || is_trackback() ) { return false; } if ( get_query_var( 'aio_sitemap' ) ) { return false; } if ( is_user_logged_in() ) { return false; } return true; } public function output_lcp_featured_preload() { if ( is_admin() || aio_is_speed_safe_mode() || ! is_singular() ) { return; } $post_id = get_queried_object_id(); if ( ! $post_id ) { return; } $thumb_id = 0; $size = 'large'; $sizes = ''; $is_section_bg = false; if ( is_page() ) { $post_obj = get_post( $post_id ); $content = $post_obj ? (string) $post_obj->post_content : ''; if ( preg_match( '/\[section\b([^\]]*)\bbg=["\']?(\d+)["\']?([^\]]*)\]/i', substr( $content, 0, 1500 ), $m ) ) { $thumb_id = (int) $m[2]; $sec_attrs = $m[1] . ' ' . $m[3]; $size = 'full'; if ( preg_match( '/\bbg_size=["\']?([a-z0-9_-]+)["\']?/i', $sec_attrs, $sm ) && strtolower( $sm[1] ) !== 'original' ) { $size = strtolower( $sm[1] ); } $is_section_bg = true; } else { return; } } else { if ( ! has_post_thumbnail( $post_id ) ) { return; } $thumb_id = (int) get_post_thumbnail_id( $post_id ); } if ( ! $thumb_id ) { return; } $src = wp_get_attachment_image_url( $thumb_id, $size ); if ( empty( $src ) ) { return; } $srcset = $is_section_bg ? '' : wp_get_attachment_image_srcset( $thumb_id, $size ); if ( ! $is_section_bg && '' === $sizes ) { $sizes = (string) wp_get_attachment_image_sizes( $thumb_id, $size ); } if ( ! empty( $this->options['optEnableWebpRewrite'] ) || ! empty( $this->options['opt-perf-webp'] ) ) { $src = $this->maybe_rewrite_url_to_webp( $src ); if ( ! empty( $srcset ) ) { $srcset = $this->maybe_rewrite_srcset_to_webp( $srcset ); } } echo '' . "\n"; } /** * Output user-configured Above-the-Fold Critical CSS early in . */ public function output_critical_css() { if ( ! $this->is_optimizable_request() ) { return; } $css = trim( (string) $this->options['optCriticalCss'] ); if ( $css === '' ) { return; } // Prevent any accidental breakout inside user CSS $safe_css = preg_replace( '#' . $safe_css . '' . "\n"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } public function output_instant_page_prefetch() { if ( ! $this->is_optimizable_request() ) { return; } $rules = array( 'prefetch' => array( array( 'source' => 'document', 'where' => array( 'and' => array( array( 'href_matches' => '/*' ), array( 'not' => array( 'href_matches' => array( '/wp-admin/*', '/wp-login.php*', '/*add-to-cart=*', '/*remove_item=*', '/*logout*', '/cart/*', '/checkout/*', '/my-account/*', '/gio-hang/*', '/thanh-toan/*', '/tai-khoan/*', '/*\\?*', ), ), ), array( 'not' => array( 'selector_matches' => '.no-prefetch, [download], [rel~=nofollow], .add_to_cart_button, .ajax_add_to_cart', ), ), ), ), 'eagerness' => 'moderate', ), ), ); echo '' . "\n"; ?> is_optimizable_request() ) { ob_start( array( $this, 'transform_html' ) ); } } /** * Main single-pass HTML transformation callback. */ public function transform_html( $html ) { if ( empty( $html ) || strlen( $html ) < 200 || stripos( $html, 'options['optEnableFontSwap'] ); $async_font_on = ! empty( $this->options['optAsyncGoogleFonts'] ); $self_host_font_on = ! empty( $this->options['optSelfHostGoogleFonts'] ) && class_exists( 'AIO_Font_Optimizer' ); $async_css_on = ! empty( $this->options['optEnableAsyncCss'] ); $yt_facade_on = ! empty( $this->options['optEnableYoutubeFacade'] ); $smart_lcp_on = ! empty( $this->options['optEnableSmartLcp'] ); $lazyload_on = ! empty( $this->options['opt-perf-lazyload'] ); $lazy_bg_on = ! empty( $this->options['optLazyLoadBg'] ); $auto_dims_on = ! empty( $this->options['optEnableAutoImageDims'] ); $webp_rewrite_on = ! empty( $this->options['optEnableWebpRewrite'] ) || ! empty( $this->options['opt-perf-webp'] ); $delay_js_on = ! empty( $this->options['optEnableDelayJS'] ); $cdn_on = ! empty( $this->options['optEnableCdn'] ) && ! empty( $this->options['txtCdnUrl'] ); $minify_on = ! empty( $this->options['optEnableMinify'] ); $yt_count = 0; $bg_lazy_count = 0; $font_detected = false; $font_preloads = array(); // 1. Protect '; if ( stripos( $working, '' ) !== false ) { $working = str_ireplace( '', $yt_css . "\n", $working ); } else { $working = $yt_css . "\n" . $working; } if ( stripos( $working, '' ) !== false ) { $working = str_ireplace( '', $yt_js . "\n", $working ); } else { $working .= "\n" . $yt_js; } } // 9. Inject CSS Background LazyObserver when needed if ( $bg_lazy_count > 0 ) { $bg_js = ''; if ( stripos( $working, '' ) !== false ) { $working = str_ireplace( '', $bg_js . "\n", $working ); } else { $working .= "\n" . $bg_js; } } // 10. Delay JavaScript Execution until First User Interaction or 5s Timeout if ( $delay_js_on ) { $working = $this->apply_delay_js( $working ); } // 11. Safe HTML Minifier if ( $minify_on ) { $working = self::minify_html( $working ); } return $working; } private function inject_img_attrs( $tag, $attrs ) { if ( substr( rtrim( $tag ), -2 ) === '/>' ) { return preg_replace( '/\s*\/>$/', $attrs . ' />', $tag, 1 ); } return preg_replace( '/>$/', $attrs . '>', $tag, 1 ); } private function is_local_host( $host ) { $h = strtolower( preg_replace( '/^www\./i', '', trim( (string) $host ) ) ); $s = strtolower( preg_replace( '/^www\./i', '', trim( (string) $this->site_host ) ) ); if ( $h === '' ) { return false; } if ( $h === $s || in_array( $h, array( 'winlab.vn', 'winlab.asia', 'winlab.local', 'winlab.test' ), true ) ) { return true; } return false; } /** * Safely rewrite a local .jpg/.jpeg/.png URL to its .webp counterpart ONLY if the .webp file exists on disk. * Works even when original .jpg/.png was deleted after WebP conversion! */ private function maybe_rewrite_url_to_webp( $url ) { $raw_url = trim( (string) $url ); if ( $raw_url === '' || stripos( $raw_url, 'data:' ) === 0 ) { return $url; } $clean_url = strtok( $raw_url, '?#' ); if ( ! preg_match( '/\.(?:jpe?g|png)$/i', (string) $clean_url ) ) { return $url; } if ( isset( $this->webp_url_cache[ $clean_url ] ) ) { return $this->webp_url_cache[ $clean_url ]; } $norm_url = $clean_url; if ( strpos( $norm_url, '//' ) === 0 ) { $norm_url = ( is_ssl() ? 'https:' : 'http:' ) . $norm_url; } elseif ( strpos( $norm_url, '/' ) === 0 ) { $norm_url = home_url( $norm_url ); } $host = strtolower( (string) wp_parse_url( $norm_url, PHP_URL_HOST ) ); if ( ! $this->is_local_host( $host ) ) { $this->webp_url_cache[ $clean_url ] = $url; return $url; } $url_path = rawurldecode( (string) wp_parse_url( $norm_url, PHP_URL_PATH ) ); if ( $this->home_path_prefix !== '' && strpos( $url_path, $this->home_path_prefix . '/' ) === 0 ) { $url_path = substr( $url_path, strlen( $this->home_path_prefix ) ); } if ( strpos( $url_path, '..' ) !== false || strpos( $url_path, "\0" ) !== false ) { $this->webp_url_cache[ $clean_url ] = $url; return $url; } $abs_root = trailingslashit( wp_normalize_path( ABSPATH ) ); $orig_path = wp_normalize_path( $abs_root . ltrim( $url_path, '/' ) ); if ( strpos( $orig_path, $abs_root ) !== 0 ) { $this->webp_url_cache[ $clean_url ] = $url; return $url; } // Candidate 1: standard AIO Tools replacement naming (photo.jpg -> photo.webp) $webp_path_1 = preg_replace( '/\.(?:jpe?g|png)$/i', '.webp', $orig_path ); if ( $webp_path_1 && is_file( $webp_path_1 ) && filesize( $webp_path_1 ) > 100 ) { $rewritten = preg_replace( '/\.(?:jpe?g|png)$/i', '.webp', $clean_url ); $this->webp_url_cache[ $clean_url ] = $rewritten; return $rewritten; } // Candidate 2: appended extension naming (photo.jpg -> photo.jpg.webp) $webp_path_2 = $orig_path . '.webp'; if ( is_file( $webp_path_2 ) && filesize( $webp_path_2 ) > 100 ) { $rewritten = $clean_url . '.webp'; $this->webp_url_cache[ $clean_url ] = $rewritten; return $rewritten; } $this->webp_url_cache[ $clean_url ] = $url; return $url; } /** * Rewrite all local .jpg/.jpeg/.png candidates inside an HTML srcset attribute to .webp if present on disk. */ private function maybe_rewrite_srcset_to_webp( $srcset ) { $parts = explode( ',', (string) $srcset ); $out = array(); foreach ( $parts as $part ) { $trimmed = trim( $part ); if ( $trimmed === '' ) { continue; } $tokens = preg_split( '/\s+/', $trimmed, 2 ); $tokens[0] = $this->maybe_rewrite_url_to_webp( $tokens[0] ); $out[] = implode( ' ', $tokens ); } return ! empty( $out ) ? implode( ', ', $out ) : $srcset; } /** * Resolve width & height of ANY local site image (uploads, themes, plugins, wp-includes) including SVG! */ private function resolve_local_image_dims( $url ) { $clean_url = strtok( $url, '?#' ); if ( empty( $clean_url ) ) { return false; } // Fast path 1: WordPress intermediate thumbnail suffix -WIDTHxHEIGHT.ext if ( preg_match( '/-(\d{2,5})x(\d{2,5})\.(?:jpe?g|png|webp|gif|avif)$/i', $clean_url, $m ) ) { return array( (int) $m[1], (int) $m[2] ); } if ( $this->dims_cache === null ) { $cached = get_transient( 'aio_img_dims_cache' ); $this->dims_cache = is_array( $cached ) ? $cached : array(); } if ( isset( $this->dims_cache[ $clean_url ] ) ) { return $this->dims_cache[ $clean_url ]; } $norm_url = $clean_url; if ( strpos( $norm_url, '//' ) === 0 ) { $norm_url = ( is_ssl() ? 'https:' : 'http:' ) . $norm_url; } elseif ( strpos( $norm_url, '/' ) === 0 ) { $norm_url = home_url( $norm_url ); } $host = strtolower( (string) wp_parse_url( $norm_url, PHP_URL_HOST ) ); if ( ! $this->is_local_host( $host ) ) { return false; } $url_path = rawurldecode( (string) wp_parse_url( $norm_url, PHP_URL_PATH ) ); if ( $this->home_path_prefix !== '' && strpos( $url_path, $this->home_path_prefix . '/' ) === 0 ) { $url_path = substr( $url_path, strlen( $this->home_path_prefix ) ); } if ( strpos( $url_path, '..' ) !== false || strpos( $url_path, "\0" ) !== false ) { return false; } $abs_root = trailingslashit( wp_normalize_path( ABSPATH ) ); $local_file = wp_normalize_path( $abs_root . ltrim( $url_path, '/' ) ); if ( strpos( $local_file, $abs_root ) !== 0 || ! is_file( $local_file ) || ! is_readable( $local_file ) ) { return false; } $dims = false; // SVG Dimension Parser (reads ) if ( preg_match( '/\.svg$/i', $local_file ) ) { $svg_head = (string) @file_get_contents( $local_file, false, null, 0, 2048 ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged if ( preg_match( '/]*>/is', $svg_head, $sm ) ) { $svg_tag = $sm[0]; $sw = 0; $sh = 0; if ( preg_match( '/\bwidth\s*=\s*["\']\s*([0-9]+(?:\.[0-9]+)?)\s*(?:px)?\s*["\']/i', $svg_tag, $wm ) ) { $sw = (int) round( (float) $wm[1] ); } if ( preg_match( '/\bheight\s*=\s*["\']\s*([0-9]+(?:\.[0-9]+)?)\s*(?:px)?\s*["\']/i', $svg_tag, $hm ) ) { $sh = (int) round( (float) $hm[1] ); } if ( ( $sw <= 0 || $sh <= 0 ) && preg_match( '/\bviewBox\s*=\s*["\']\s*[-0-9.]+\s+[-0-9.]+\s+([0-9.]+)\s+([0-9.]+)\s*["\']/i', $svg_tag, $vm ) ) { $sw = (int) round( (float) $vm[1] ); $sh = (int) round( (float) $vm[2] ); } if ( $sw > 0 && $sh > 0 ) { $dims = array( $sw, $sh ); } } } else { $size = function_exists( 'wp_getimagesize' ) ? @wp_getimagesize( $local_file ) : @getimagesize( $local_file ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged if ( is_array( $size ) && ! empty( $size[0] ) && ! empty( $size[1] ) ) { $dims = array( (int) $size[0], (int) $size[1] ); } } if ( is_array( $dims ) ) { $this->dims_cache[ $clean_url ] = $dims; $this->dims_cache_dirty = true; return $dims; } return false; } /** * Rewrite static /wp-content/ and /wp-includes/ URLs to user-configured CDN hostname. */ private function apply_cdn_rewrite( $html ) { $raw_cdn = trim( (string) $this->options['txtCdnUrl'] ); if ( $raw_cdn === '' ) { return $html; } if ( strpos( $raw_cdn, '//' ) === 0 ) { $raw_cdn = 'https:' . $raw_cdn; } elseif ( ! preg_match( '#^https?://#i', $raw_cdn ) ) { $raw_cdn = 'https://' . ltrim( $raw_cdn, '/' ); } $cdn_base = rtrim( $raw_cdn, '/' ); $home_base = rtrim( home_url(), '/' ); if ( strtolower( $cdn_base ) === strtolower( $home_base ) ) { return $html; } $escaped_home = preg_quote( preg_replace( '#^https?:#i', '', $home_base ), '#' ); $pattern = '#(?:https?:)?' . $escaped_home . '(/(?:wp-content|wp-includes)/[^"\'\s\)<>]+?\.(?:css|js|jpe?g|png|gif|webp|avif|svg|ico|woff2?|ttf|otf|eot|mp4|webm))(?=["\'\s\)?\#>])#i'; return preg_replace( $pattern, $cdn_base . '$1', $html ) ?? $html; } private function apply_delay_js( $html ) { $mode = isset( $this->options['optDelayJsMode'] ) && $this->options['optDelayJsMode'] === 'all' ? 'all' : 'targeted'; $raw_excludes = isset( $this->options['optDelayJsExcludes'] ) ? (string) $this->options['optDelayJsExcludes'] : ''; $safe_excludes = array( 'jquery.min.js', 'jquery.js', 'jquery-core', 'jquery-migrate', '/wp-includes/js/dist/hooks', '/wp-includes/js/dist/i18n', 'flatsome-js', 'flatsome.js', 'chunk.slider', 'chunk.popups', 'chunk.tooltips', 'slick-js', 'slick.min.js', 'shostvn-js', 'shostvn-', 'hoverIntent', 'wc-checkout', 'wc-cart', 'wc-add-to-cart', 'woocommerce', 'challenges.cloudflare.com', 'google.com/recaptcha', 'gstatic.com/recaptcha', 'aio-yt-facade', 'aio-lazy-bg', 'aio-instant-page', 'aio-delay-js', 'data-aio-no-delay', 'data-no-optimize', 'data-cfasync="false"', ); foreach ( preg_split( '/[\r\n]+/', $raw_excludes ) as $line ) { $line = trim( $line ); if ( $line !== '' ) { $safe_excludes[] = $line; } } $targeted_patterns = array( 'googletagmanager.com', 'google-analytics.com', 'gtag/js', 'analytics.js', 'googlesyndication.com', 'adsbygoogle', 'connect.facebook.net', 'fbevents.js', 'embed.tawk.to', 'Tawk_API', 'chative.io', 'chat.zalo.me', 'sp.zalo.me', 'analytics.tiktok.com', 'ttq.load(', 'static.hotjar.com', '_hjSettings', 'clarity.ms', 'snap.licdn.com', 'bat.bing.com', 'crisp.chat', 'intercom.io', 'livechatinc.com', 'tidio.co', 'mc.yandex.ru', 'fbq(', 'gtag(', 'gt_widget_script', ); $ns_blocks = array(); $ns_idx = 0; $masked = preg_replace_callback( '#<(noscript|textarea)\b[^>]*>.*?#is', function ( $m ) use ( &$ns_blocks, &$ns_idx ) { $tok = '%%AIO_NS_BLOCK_' . ( $ns_idx++ ) . '%%'; $ns_blocks[ $tok ] = $m[0]; return $tok; }, $html ); if ( $masked === null ) { return $html; } $delayed_count = 0; $rewritten = preg_replace_callback( '#]*)>(.*?)#is', function ( $m ) use ( $mode, $safe_excludes, $targeted_patterns, &$delayed_count ) { $full_tag = $m[0]; $attrs = $m[1]; $body = $m[2]; $orig_type = ''; if ( preg_match( '/\btype\s*=\s*(["\'])([^"\']*)\1/i', $attrs, $tm ) ) { $orig_type = strtolower( trim( $tm[2] ) ); } elseif ( preg_match( '/\btype\s*=\s*([^\s>]+)/i', $attrs, $tm ) ) { $orig_type = strtolower( trim( $tm[1], '"\'' ) ); } if ( $orig_type !== '' && ! in_array( $orig_type, array( 'text/javascript', 'application/javascript', 'javascript', 'module' ), true ) ) { return $full_tag; } $is_gt_widget = ( stripos( $full_tag, 'gt_widget_script' ) !== false ); foreach ( $safe_excludes as $ex ) { if ( $ex !== '' && stripos( $full_tag, $ex ) !== false ) { if ( $is_gt_widget && 'data-no-optimize' === $ex ) { continue; } return $full_tag; } } $has_src = (bool) preg_match( '/\bsrc\s*=\s*(["\'])([^"\']+)\1/i', $attrs, $sm ); if ( ! $has_src ) { if ( preg_match( '/\bid\s*=\s*["\'][^"\']*-(?:js-extra|js-before)["\']/i', $attrs ) ) { return $full_tag; } if ( stripos( $body, 'document.documentElement' ) !== false || trim( $body ) === '' ) { return $full_tag; } } if ( $mode === 'targeted' ) { $matched = false; foreach ( $targeted_patterns as $pat ) { if ( stripos( $full_tag, $pat ) !== false ) { $matched = true; break; } } if ( ! $matched ) { return $full_tag; } } $new_attrs = preg_replace( '/\s*\btype\s*=\s*(?:(["\'])[^"\']*\1|[^\s>]+)/i', '', $attrs ); if ( $orig_type === 'module' ) { $new_attrs .= ' data-aio-type="module"'; } if ( $has_src ) { $src_quote = $sm[1]; $src_val = $sm[2]; $new_attrs = str_replace( $sm[0], 'data-aio-src=' . $src_quote . $src_val . $src_quote, $new_attrs ); } $delayed_count++; return ''; }, $masked ); if ( $rewritten === null ) { return $html; } if ( ! empty( $ns_blocks ) ) { $rewritten = strtr( $rewritten, $ns_blocks ); } if ( $delayed_count > 0 ) { $loader = ''; if ( stripos( $rewritten, '' ) !== false ) { $rewritten = str_ireplace( '', $loader . "\n", $rewritten ); } else { $rewritten .= "\n" . $loader; } } return $rewritten; } public static function minify_html( $buffer ) { if ( empty( $buffer ) || stripos( $buffer, ']*>.*?#is', function ( $matches ) use ( &$placeholders, &$index ) { $token = '%%AIO_MINIFY_BLOCK_' . ( $index++ ) . '%%'; $placeholders[ $token ] = $matches[0]; return $token; }, $buffer ); if ( $protected === null ) { return $buffer; } $minified = preg_replace( '/).)*-->/s', '', $protected ); if ( $minified !== null ) { $minified = preg_replace( array( '/>[^\S ]+/s', '/[^\S ]+', '<', '$1' ), $minified ); } if ( $minified === null ) { return $buffer; } if ( ! empty( $placeholders ) ) { $minified = strtr( $minified, $placeholders ); } return $minified; } }