WordPress 的 wptexturize 过滤器正在悄无声息地破坏内联 JavaScript,将逻辑 && 运算符转换为 HTML 实体 &&,从而导致在短代码中运行的脚本失效。
这个问题出现在一位维护一系列计算器短代码的开发人员身上。在经过数周的完美运行后,提交按钮突然停止响应。没有 PHP 警告,没有控制台错误,检查 HTML 时看起来也很正常——直到渲染后的源代码显示出 if (!isNaN(bf) && bf > 0)。这一个语法错误导致整个脚本块无法执行。
为什么该过滤器会产生影响
WordPress 在将文章内容发送到浏览器之前,会通过一系列过滤器进行处理。wptexturize 是这些过滤器中的第一个;它将直引号转换为排版用的弯引号,将多个连字符替换为破折号,并处理和符号(&)。该过滤器假设处理的是正文内容,而非代码。当短代码注入一个内联 <script> 标签时,过滤器仍然会运行,并将 JavaScript 视为普通文本。因此,&& 中的和符号被转义为 &,浏览器会将其解释为字面字符串,而不是逻辑“与”运算符。
任何直接在文章内容中嵌入 JavaScript 的开发人员(如计算器、表单验证器、交互式小部件)都容易受到影响。问题不仅限于计算器;任何使用 &&、& 或类似字符的内联脚本都可能被损坏。由于这种转换是在服务器端发生的,浏览器永远看不到原始代码,且错误不会以典型的 JavaScript 异常形式出现。
谁会受到影响以及他们会失去什么
- 网站所有者:损坏的计算器或表单会令访客感到沮丧,增加跳出率并削弱信任。
- 开发人员:花费数小时寻找在日志或控制台输出中不留痕迹的“幽灵”Bug。
- 内容编辑:在编辑包含短代码的页面时,可能会在不知情的情况下破坏功能。
代价不仅仅是时间;它还会转化为转化率的损失,特别是对于那些依赖自定义计算器进行定价、贷款估算或健康评估的网站。
通俗地说,该过滤器做了什么
- 检测直引号 – 将
'和"替换为“智能”排版版本的弯引号。 - 清理和符号 – 将
&转换为&,除非它已经构成了一个有效的 HTML 实体。 - 应用于整个内容字符串 – 包括由短代码生成的
<script>标签内的任何内容。
当过滤器遇到 && 时,它会看到两个不属于现有 HTML 实体的和符号,因此会分别对它们进行转义,结果变为 &&。
如何阻止这种损坏
1. 为包含代码的页面关闭该过滤器
add_action( 'template_redirect', function () {
if ( is_page() ) {
remove_filter( 'the_content', 'wptexturize' );
remove_filter( 'widget_text_content', 'wptexturize' );
}
} );
此代码片段仅在页面模板上禁用 wptexturize,同时为文章和其他内容类型保留排版改进。它还从小部件文本中移除了该过滤器,因为小部件也可能是内联脚本的次要来源。
2. 重写逻辑以避免使用 &&
如果不想移除过滤器,可以重构 JavaScript,使其不需要逻辑“与”运算符:
// Original
if (a && b) { … }
// Refactored
var ok = a;
if (ok) { ok = b; }
if (ok) { … }
虽然这会增加几行代码,但它消除了触发过滤器的和符号。这种方法适用于简单的条件,但对于复杂的表达式可能会变得难以处理。
3. 将所有脚本外部化
最稳妥的解决方案是使用 enqueue 加载 JavaScript 文件,而不是嵌入内联代码:
wp_enqueue_script( 'my-calculator', get_template_directory_uri() . '/js/calculator.js', [], null, true );
通过 enqueue 加载的脚本会完全绕过 the_content 过滤器。它们还能受益于浏览器缓存,并可以进行压缩或与其他资源打包。
如何在实际环境中检测此问题
当脚本在没有明显错误的情况下停止运行时,请查看页面源代码(而不是 DOM 检查器)并搜索 &。如果你在 <script> 块中发现了它,那么过滤器就是罪魁祸首。这个问题不会出现在控制台中,因为浏览器从未接收到可供解析的语法正确的脚本。
反方观点:为什么要保留 wptexturize?
wptexturize 提高了前端的可读性。弯引号和正确的破折号字符能让正文看起来更精致,许多网站所有者认为这是一种不可妥协的美学特性。全局移除该过滤器会导致文本退回到原始、排版平淡的状态。
折衷方案是选择性禁用:仅在代码所在处关闭过滤器,或者使用自定义短代码,明确将其输出标记为不受文本美化(texturizing)影响。WordPress 已经提供了 wp_kses_post 和其他清理助手;开发者可以将这些与 remove_filter 调用结合使用,以兼顾两者的优点。
后续关注点
WordPress 核心尚未宣布对 wptexturize 进行任何会自动豁免 <script> 标签的更改。在此类更改落地之前,开发者必须手动保护其内联代码。请密切关注核心开发追踪器,留意任何关于使该过滤器具备上下文感知能力的提案。与此同时,请审计任何注入 JavaScript 的短代码或页面构建器元素,并应用上述三种修复方法之一。
底线: 如果您的 WordPress 网站运行内联 JavaScript,请务必确认 wptexturize 没有在后台悄悄重写它。一个被转义的 & 符号就可能导致整个功能失效,而修复方法通常只需几行 PHP 代码,或者将其迁移到外部脚本。
