近日我在为客户网站定制开发 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》