niihost

免插件实现WordPress HTML 压缩

近日我在为客户网站定制开发 WordPress 优化与缓存插件时,处理 WordPress HTML 压缩是一项重要的任务。现有的开源库虽然方便易用,但可能存在过度压缩导致 HTML 或内联脚本错误的问题。所以自己写了一段代码,分享给大家。

启用 WordPress HTML 压缩的必要性

在现代网页设计中,即使启用了 GZIP 或 Brotli 压缩,仍然建议对 HTML 代码进行压缩。这是因为:

  • GZIP 和 Brotli 压缩算法主要针对重复数据空白进行压缩。而 HTML 代码中通常包含大量的语义化标签注释,这些内容对于浏览器解析页面结构至关重要,但并非重复数据,因此压缩效果可能并不理想。
  • 对 HTML 代码进行压缩可以进一步减少文件大小,从而提高页面加载速度降低服务器带宽消耗。尤其是对于体积较大的 HTML 文件,压缩效果更加明显。

需要注意的是,过度压缩 HTML 代码可能会导致代码的兼容性和维护性下降引发错误。因此,在压缩 HTML 代码时,应遵循以下原则:

  • 保留必要的代码结构语义化标签,不要为了压缩而牺牲代码的可读性与兼容性,避免过度压缩。
  • 在压缩后检查代码,确保没有语法错误或其他问题。

总而言之,在现代网页设计中,对 HTML 代码进行压缩仍然是一项必要的性能优化措施。即使启用了 GZIP 或 Brotli 压缩,也应该对 HTML 代码进行进一步压缩,以获得更好的性能表现。

WordPress HTML 压缩程序源码

function WenM_clean_javascript($js_code) {
    // 将多个空格替换为单个空格,但保留换行符
    $js_code = preg_replace('/[ \t]+/', ' ', $js_code);
    // 去掉每行开头和结尾的空格
    $js_code = preg_replace('/^\s+|\s+$/m', '', $js_code);
    return $js_code;
}

function WenM_compress_css($css_code) {
    // 精确匹配CSS注释,避免删除包含在字符串字面量中的注释
    $css_code = preg_replace_callback('!/\*[^*]*\*+([^/][^*]*\*+)*/!', function($matches) {
        return strpos($matches[0], '"') === false && strpos($matches[0], "'") === false ? '' : $matches[0];
    }, $css_code);
    // 去掉多余空格,但保留重要空格确保兼容性
    $css_code = preg_replace_callback('/(?<=\s|^)([{};:,]|}(?!\s*(?:\[.*?\]|[^\s}]))(?=\s|$))/', function($matches) { return $matches[1]; }, $css_code); $css_code = preg_replace('/\s*([>~+])\s*/', '$1', $css_code); // 保留选择器间的空格
    // 合并多余的空白符,保留必要的空格
    $css_code = preg_replace('/\s+/', ' ', $css_code);
    $css_code = preg_replace('/;\s*}/', '}', $css_code); // 删除行尾的分号

    return $css_code;
}

function WenM_html_cleaner($buffer) {
    // 获取压缩前的HTML体积
    $original_size = strlen($buffer);

    // 提取所有  代码块并用占位符替换
    if (preg_match_all('/(<code\b[^>]*>)([\s\S]*?)(<\/code>)/i', $buffer, $code_matches)) {
        $code_placeholders = array_map(function($i) { return "###CODE_$i###"; }, array_keys($code_matches[0]));
        $buffer = str_replace($code_matches[0], $code_placeholders, $buffer);
    }

    // 提取所有 JavaScript 代码块并用占位符替换
    if (preg_match_all('/(<script\b[^>]*>)([\s\S]*?)(<\/script>)/i', $buffer, $js_matches)) {
        $js_placeholders = array_map(function($i) { return "###JAVASCRIPT_$i###"; }, array_keys($js_matches[0]));
        $buffer = str_replace($js_matches[0], $js_placeholders, $buffer);
    }

    // 压缩标签之前内联的CSS代码
    if (preg_match('/(<head\b[^>]*>)([\s\S]*?)(<\/head>)/i', $buffer, $head_matches)) {
        if (preg_match_all('/(<style\b[^>]*id=["\'][^"\']*["\'][^>]*>)([\s\S]*?)(<\/style>)/i', $head_matches[2], $css_matches)) {
            foreach ($css_matches[2] as &$css_code) {
                $css_code = WenM_compress_css($css_code);
            }
            $cleaned_head = $head_matches[2];
            foreach ($css_matches[0] as $i => $original_style_tag) {
                $compressed_style_tag = $css_matches[1][$i] . $css_matches[2][$i] . $css_matches[3][$i];
                $cleaned_head = str_replace($original_style_tag, $compressed_style_tag, $cleaned_head);
            }
            $buffer = str_replace($head_matches[0], $head_matches[1] . $cleaned_head . $head_matches[3], $buffer);
        }
    }

    // 去掉 HTML 注释
    $buffer = preg_replace('//', '', $buffer);
    
    // 去掉多余的空格和换行
    $buffer = preg_replace('/\s+/', ' ', $buffer);
    $buffer = preg_replace('/>\s+</', '><', $buffer);

    // 保留指定标签前的一个换行符
    $buffer = preg_replace('/(<(title|h1|h2|aside|main|html|head|body|code)[^>]*>)/i', "\n$1", $buffer);

    // 处理 JavaScript 代码块中的空格
    if (!empty($js_matches[2])) {
        foreach ($js_matches[2] as &$js_code) {
            $js_code = WenM_clean_javascript($js_code);
        }
        // 将占位符替换回处理后的 JavaScript 代码块
        $processed_js = array_map(function($i) use ($js_matches) {
            return $js_matches[1][$i] . $js_matches[2][$i] . $js_matches[3][$i];
        }, array_keys($js_matches[0]));
        $buffer = str_replace($js_placeholders, $processed_js, $buffer);
    }
    
    // 将占位符替换回  代码块
    if (!empty($code_matches[2])) {
        $processed_code = array_map(function($i) use ($code_matches) {
            return $code_matches[1][$i] . $code_matches[2][$i] . $code_matches[3][$i];
        }, array_keys($code_matches[0]));
        $buffer = str_replace($code_placeholders, $processed_code, $buffer);
    }

    // 获取压缩后的HTML体积
    $compressed_size = strlen($buffer);

    // 计算体积并转换为KB
    $original_size_kb = round($original_size / 1024, 2);
    $compressed_size_kb = round($compressed_size / 1024, 2);

    // 在HTML尾部添加压缩前后的体积信息
    $buffer .= "\n";

    return $buffer;
}

function WenM_start_buffering() {
    ob_start('WenM_html_cleaner');
}

function WenM_end_buffering() {
    // 确保在有缓冲区时调用 ob_end_flush
    if (ob_get_level() > 0) {
        ob_end_flush();
    }
}

add_action('wp_loaded', 'WenM_start_buffering');
add_action('shutdown', 'WenM_end_buffering');

这段代码的优势在于:

  • 有效压缩 HTML 代码,减小文件大小,提升页面加载速度、节约带宽与流量。
  • 识别并保留代码中的必要空格,避免过度压缩导致错误。
  • 针对性压缩内联脚本,确保其正常运行。
  • 代码简洁易懂,方便二次开发和维护。

技术宅使用的代码大家可以参考:《WordPress免插件压缩HTML和GZIP

给TA赏糖
共{{data.count}}人
人已赏糖
技术分享

WordPress Object Cache Pro 插件解疑与推荐配置

2024-11-30 1:12:37

技术分享

忘记路由器密码怎么办?重置技巧详解,快速恢复网络连接

2024-11-30 17:35:44

0 条回复 A文章作者 M管理员
技术宅评论
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索