记录一下,美化 WordPress HTML 输出,无需任何插件
在WordPress中使用输出缓冲(Output Buffering)和Tidy库来美化HTML输出是一个很好的实践,尤其是在开发或调试阶段。
- 确保Tidy库可用:首先,确保你的服务器安装了Tidy库,并且PHP的Tidy扩展已经启用。这通常不是所有服务器都默认安装的。
- WordPress主题和插件的兼容性:
在WordPress中使用shutdown
钩子进行输出处理可能会影响某些插件或主题的功能,尤其是那些也使用输出缓冲的插件。 - 性能考虑:
使用tidy
来解析和清理HTML可能会对服务器性能产生影响,特别是当网站流量大或HTML内容复杂时。 - 输出时机:
虽然shutdown
钩子是在请求结束时执行,但通常用于日志记录或清理工作,而不是修改最终发送给客户端的响应。确保这是你想要的行为。
下面是一个代码示例,增加了错误处理和确保tidy
对象被正确使用:
function beautify_html_output() {
if (ob_get_level() > 0) {
$html = ob_get_clean();
if (class_exists('\tidy')) {
$tidy = new \tidy;
$tidy->parseString($html, [
'indent' => true,
'output-xhtml' => true,
'wrap' => 0
], 'utf8');
$tidy->cleanRepair();
if ($tidy->errorBuffer) {
// 处理tidy的错误
error_log('Tidy Error: ' . $tidy->errorBuffer);
} else {
echo $tidy;
}
} else {
// 如果tidy类不存在,则回退到原始HTML
echo $html;
}
}
}
add_action('shutdown', 'beautify_html_output', 0);
// 启动输出缓冲
ob_start();
换行符处理:这可能会影响HTML的可读性(在源代码中),但不会影响浏览器渲染的页面。如果您希望保留一些可读性,可以考虑只去除不必要的换行符或空格。这里$buffe只是合并css的时候去除多余空格,注意,如果文章中有pre代码,会被压缩处理
function format_html_output($buffer) {
// 早期返回:对于登录用户或XML内容
if (is_user_logged_in() || strpos(strtolower($buffer), '<?xml') === 0) {
return $buffer;
}
// 去除换行符
$buffer = str_replace(["\r\n", "\r", "\n"], '', $buffer);
// 尝试使用HTML Tidy进行格式化(如果可用)
if (function_exists('tidy_parse_string')) {
// 内联配置选项
$tidy = tidy_parse_string($buffer, [
'indent' => 2, // 启用缩进
'wrap' => 0, // 禁自动换行
'char-encoding' => 'UTF8' // 设置字符编码
], 'UTF8');
// 直接获取并返回Tidy的输出
if ($tidy) {
$buffer = tidy_get_output($tidy);
}
}
return $buffer;
}
// 添加输出缓冲
ob_start('format_html_output');
如果文章中有pre代码格式,需要做特殊处理,否则其中代码会被压缩
为了修改format_html_output
函数以在美化HTML时不删除<pre>
标签内的换行符,我们需要在去除全局换行符之前先处理<pre>
标签内的内容,以确保其内部的换行符得到保留。由于直接在字符串操作中区分<pre>
标签的内容较为复杂,我们可以采用正则表达式配合回调函数的方式来处理。
但是,由于HTML的复杂性(如嵌套<pre>
标签或包含<pre>
标签的JavaScript字符串等),直接通过正则表达式来完美处理所有情况可能会很复杂且容易出错。不过,对于简单的用途,我们可以尝试以下方案:
- 使用正则表达式找到所有的
<pre>
标签及其内容。 - 对这些内容进行特殊处理,比如暂时替换为占位符。
- 去除剩余的换行符。
- 格式化HTML(如果可能)。
- 将
<pre>
标签的内容恢复回原位置。
但是,考虑到性能和实现的复杂性,这里给出一个简化的方案,它依赖于HTML结构相对简单且<pre>
标签不包含嵌套的HTML元素(如<div>
、<span>
等)的假设。
下面是一个简化的示例,它使用preg_replace_callback
来保留<pre>
标签内的换行符:
function format_html_output($buffer) {
// 早期返回:对于登录用户或XML内容
if (is_user_logged_in() || strpos(strtolower($buffer), '<?xml') === 0) {
return $buffer;
}
// 使用正则表达式找到所有的<pre>标签并保留其内部换行符
$buffer = preg_replace_callback('/<pre[^>]*>(.*?)<\/pre>/is', function ($matches) {
// 替换换行符为特殊占位符(确保它不会出现在正常文本中)
$preservedContent = str_replace(["\r\n", "\r", "\n"], '__PRE_NEWLINE__', $matches[1]);
return "<pre>" . $preservedContent . "</pre>";
}, $buffer);
// 去除剩余的换行符
$buffer = str_replace(["\r\n", "\r", "\n"], '', $buffer);
// 尝试使用HTML Tidy进行格式化(如果可用)
if (function_exists('tidy_parse_string')) {
$tidy = tidy_parse_string($buffer, [
'indent' => 2,
'wrap' => 0,
'char-encoding' => 'UTF8'
], 'UTF8');
if ($tidy) {
$buffer = tidy_get_output($tidy);
// 将特殊占位符替换回换行符
$buffer = str_replace('__PRE_NEWLINE__', "\n", $buffer);
}
}
// 如果Tidy不可用,则直接替换回换行符
if (!function_exists('tidy_parse_string')) {
$buffer = str_replace('__PRE_NEWLINE__', "\n", $buffer);
}
return $buffer;
}
// 添加输出缓冲
ob_start('format_html_output');
注意:
- 这个解决方案假设
<pre>
标签不包含嵌套的HTML元素,或者即使包含,它们也不会干扰到换行符的替换。 - 如果HTML内容非常复杂,或者
<pre>
标签内的内容可能包含对换行符有特殊要求的元素(如<textarea>
),则可能需要更复杂的处理逻辑。 - 在实际应用中,考虑到性能和可维护性,通常建议只在必要时才进行此类处理,并且可能需要更健壮的HTML解析和修改库来确保准确性和可靠性。