没有不值得去解决的问题,也没有不值得去学习的技术!

WordPress 升级 PHP 8.5 后的插件兼容性排查:该修的修,该停的停,该等上游的等

GitHub 上为 PublishPress Series 提交 PHP 8.5 SplObjectStorage 弃用警告 Issue 的页面

作者:

WordPress 性能优化手记

如 如图1 所示,站点健康直接提示这是一个可能对性能或安全性产生重大影响的问题,需要优先解决。

(1) 从站点健康警告到全绿通关

PHP Fatal error: Uncaught RedisException: OOM command not allowed when used memory > 'maxmemory'. in /data/wwwroot/.../wp-content/plugins/w3-total-cache/Cache_Redis.php:150

(2) 解决 WordPress + Polylang 批量处理标签时遇到的 Redis OOM 错误

采用 ondemand 模式,适合 1 核小内存机器,空闲时释放进程。最终配置如下:如图4

(3) 一次WordPress站点504错误的排查与优化实录

优化前最终基准数据:历史累计504错误129条(6月3日峰值126条,为爬虫批量爬标签导致)。

(4) 从单日126次504超时到彻底稳定:WordPress 1核2G服务器极限优化全记录(附全部实操命令)

WebPageTest 核心指标

(5) WordPress性能基准测试与CDN选型实录:从国内拨测到海外WebPageTest,1核2G服务器如何面向全球

页面底部提示“此响应不是合法的 JSON 响应”。

(6) WordPress 标签保存失败?Nginx 限流规则惹的祸 —— 一次完整的 429 问题排查与解决

表示页面仍然是动态生成,没有缓存命中。

(7) WordPress + Nginx + W3 Total Cache 缓存未生效排查全过程(OneinStack 实战)

图7:带 Query String 后,W3TC 显示 Requested URI contains query

(8) WordPress CPU 再次满载:动态参数如何穿透 CDN 与 W3TC 页面缓存

图1:阿里云 ECS 在 14:33~14:42 期间 CPU 使用率持续接近 100%,而内存使用率整体较为稳定

(9) WordPress 服务器 CPU 再次满载:从 Nginx 499、PHP-FPM、Redis 到 W3TC 冷缓存的完整排查

图4:W3TC 最终使用 300 秒 × 7 页,并切换到中英文联合 Sitemap

(10) 从 CPU 告警到双域名预缓存:W3 Total Cache、EdgeOne 与 Cloudflare 96 小时缓存优化实战

WordPress 所有归档模板中使用 Language Visibility 和 WPCode Shortcode 添加中英文 Adsterra 广告

(11) WordPress 三域名架构再次踩坑:Adsterra 归档广告不生效,最终定位到 W3TC Object Cache

WordPress 多语言多域名缓存排查:修复 Polylang + W3 Total Cache 跨 Host 缓存失效问题

(12) WordPress 多语言多域名缓存排查:修复 Polylang + W3 Total Cache 跨 Host 缓存失效问题

WordPress 多域名环境下中文文章详情页未显示 Polylang 语言切换器

(13) WordPress 多域名下 Polylang 语言切换器延迟:W3TC Redis 跨 Host 缓存排查记录

图8:选择 2 核 4 GiB 后显示的实际补差价、2 Mbps 带宽和重启选项

(14) 从 CPU 再次告警到 ECS 升配:WordPress 服务器从 1 核 2G 升级到 2 核 4G 实录

**Alt:** WordPress 生产环境完成 PHP 8.5.9 升级,终端显示 OPcache、Imagick、Redis、Nginx、WordPress 版本及中英文站和后台域名均正常返回 HTTP 200

(15) OneinStack 生产环境将 PHP 8.1.19 升级到 PHP 8.5.9:Imagick 编译失败与 WordPress 多域名缓存验收

阿里云 OneinStack 服务器升级完成,终端显示 Nginx 1.30.4、OpenSSL 3.5.7、PCRE 8.45 和 PHP 8.5.9,Nginx 配置检查成功

(16) 阿里云 OneinStack 实战:将 Nginx 1.24.0 升级到 1.30.4,并同步升级 OpenSSL 3.5.7

阿里云 OneinStack 服务器 Redis 从 7.0.11 升级到 8.10.0 后的版本与运行状态对比截图

(17) 阿里云 OneinStack 实战:将 Redis 7.0.11 升级到 8.10.0,并完成内核优化与回滚保护

GitHub 上为 PublishPress Series 提交 PHP 8.5 SplObjectStorage 弃用警告 Issue 的页面

(18) WordPress 升级 PHP 8.5 后的插件兼容性排查:该修的修,该停的停,该等上游的等

最近,我将 WordPress 站点运行环境升级到了 PHP 8.5。网站前台可以正常访问,但 PHP-FPM 日志中开始不断出现 DeprecatedNotice

这类问题最容易让人陷入一个误区:看到一条日志,就想立即把它消灭。

但对于生产环境来说,更重要的问题其实是:

这条日志是否会在正常访问中稳定触发?对应插件是否仍然需要?本地修改会不会带来更大的风险?

这一次,我没有追求“让所有测试路径都绝对安静”,而是把目标限定为:

保证当前正常生产环境稳定运行,只处理能够确认的真实问题。

最终涉及的主要插件包括:

  • TMS Extensions for Polylang
  • Nimble Page Builder
  • SyntaxHighlighter
  • Yoast SEO
  • PublishPress Series

不同插件采用了完全不同的处理方式。


一、先确定处理原则:不要为了特殊测试路径扩大修改范围

排查开始时,我曾测试过一种特殊情况:在请求参数中临时停用 Polylang,然后观察依赖 Polylang 的扩展插件是否会报错。

TMS Extensions for Polylang 随后触发了多个与 pll_languages_list()pll_the_languages() 有关的错误。

最初的直觉是继续给插件补充 function_exists() 判断。但很快我意识到,这个方向本身就偏离了实际目标:

  • TMS Extensions for Polylang 本来就是 Polylang 的扩展;
  • 正常生产环境中 Polylang 始终处于启用状态;
  • 没有必要强行保证它在 Polylang 被人为停用时仍然完整运行。

因此,我回滚了当天新增的临时补丁,只保留以前针对真实生产问题留下的一处历史修复。

随后重新验证正常环境:

  • 中文站正常;
  • 英文站正常;
  • 后台正常;
  • Polylang 函数正常可用;
  • 没有新的 TMS 致命错误。

这一步让我重新明确了整个排查的边界:

特殊测试路径出现错误,不等于生产环境必须修改。


二、Nimble Page Builder:先查清用途,再决定是否停用

PHP 日志中反复出现一条 WordPress Notice:

Plaintext
Translation loading for the nimble-builder domain was triggered too early.

这不是 PHP 8.5 特有问题,也不会直接导致页面崩溃。但我已经完全不记得,自己为什么安装过 Nimble Page Builder。

与其直接修改插件源码,不如先确认它到底有没有被使用。

1. 查到的安装与使用记录

数据库信息显示:

Plaintext
nimble_start_date = 2019-07-17 03:04:37
nimble_started_with_version = 1.8.3
nimble_version = 3.3.8

插件至少创建过两份布局:

Plaintext
nimble___skp__home => 3865
nimble___skp__post_post_4891 => 4941

也就是说,Nimble Page Builder 并不是安装后从未使用,而是过去确实配置过:

  • 网站首页;
  • 文章 ID 4891

相关自定义文章和配置记录仍然保存在数据库中。

2. 首页布局其实是空的

进一步查看首页布局 3865 后发现,它只保存了 Nimble 的位置结构:

  • loop_start
  • before_content
  • after_content
  • nimble_local_header
  • nimble_local_footer

但这些位置中的 collection 全部为空。

正常首页 HTML 中虽然还带有:

Plaintext
nimble-has-local-data-skp__home

却没有真正的 sek-sectionsek-columnsek-module,也没有加载 Nimble 的前台资源。

因此,首页只留下了一份历史空配置,并没有真正使用 Nimble 构建页面。

3. 文章 4891 中仍有一个真实模块

文章 4891 的情况不同。

前台 HTML 中明确存在:

Plaintext
data-sek-level
sek-section
sek-column
sek-module
sek-shortcode-content

同时还加载了 Nimble Page Builder 的 CSS 和 JavaScript。

数据库中的布局内容显示,它在文章正文结束后的 after_content 位置插入了一段 AdSense 代码,广告位为:

Plaintext
5677981633

也就是说,Nimble 当前唯一实际用途,基本就是:

在一篇 2021 年发布的旧文章后面输出一个手动 AdSense 广告。

而我的网站现在已经全面使用 AdSense 自动广告,这个旧手动广告位没有继续保留的必要。

4. 停用后,缓存造成了一次误判

我在 WordPress 后台手动停用了 Nimble Page Builder。

第一次验证时,却仍然看到:

  • 旧广告位还在;
  • Nimble 页面结构还在;
  • PHP 日志中仍有 nimble-builder Notice。

但插件状态明明已经是:

Plaintext
status = inactive

后来清理了对象缓存和 W3 Total Cache,并平滑重载 PHP-FPM,再次验证时,结果变成:

Plaintext
active_option=no
included_files=0

中文站、英文站和管理域名都没有再加载 Nimble PHP 文件。

重新请求文章 4891 后:

  • HTTP 状态为 200
  • 旧 AdSense 广告位已经消失;
  • Nimble 页面结构已经消失;
  • 正文仍然正常显示。

所以,第一次看到的内容只是旧页面缓存,并不是插件停用失败。

最终处理方式是:

保持 Nimble Page Builder 停用,暂时不清理数据库中的历史布局数据。


三、SyntaxHighlighter:三个明确问题,做最小本地修复

SyntaxHighlighter 仍然承担着大量历史文章的代码高亮功能,目前不能直接停用。

当前版本为:

Plaintext
3.7.2

PHP 8.5 下出现了三处明确的 Deprecated。

1. null 被用作数组键

原代码:

PHP
$language = null;

if ( isset( $attributes['language'] ) ) {
    $language = $attributes['language'];
}

if ( isset( $this->brushes[ $language ] ) ) {
    // ...
}

当代码块没有提供 language 属性时,$language 保持为 null,随后被用作数组键。

PHP 8.5 开始对此发出警告:

Plaintext
Using null as an array offset is deprecated

原有 PHP 行为实际上会把这个键近似当作空字符串使用,所以最小修改是:

Diff
-$language = null;
+$language = '';

2. casedefault 后错误使用分号

原代码中还有:

PHP
case 'false';
default;

虽然旧版本 PHP 仍然接受这种写法,但 PHP 8.5 已经将它标记为废弃语法。

修复为:

Diff
-case 'false';
+case 'false':

-default;
+default:

正常请求中确实出现了第 56411151118 行相关日志,因此这不是仅存在于静态扫描中的理论问题。

3. 修改前完整备份

修改前,我将原文件保存到了插件目录之外:

Plaintext
/root/plugin-file-backups/syntaxhighlighter/

同时生成了一份标准补丁文件:

Plaintext
syntaxhighlighter-3.7.2-php85-20260806-200729.patch

修改后完成了以下验证:

  • 三处原代码均只匹配一次;
  • PHP 语法检查通过;
  • PHP-FPM 平滑重载成功;
  • 文章 4891 返回 HTTP 200
  • SyntaxHighlighter 前台标记仍然存在;
  • 三处 PHP 8.5 Deprecated 全部消失。

这类修复适合采用本地补丁,因为:

  • 修改范围只有三行;
  • 原因明确;
  • 行为变化可控;
  • 正常生产请求可以直接验证。

不过,插件将来升级时会覆盖本地修改。升级后需要先检查新版是否已经包含修复,而不是直接重新套用旧补丁。


四、Yoast SEO:发现根因,但没有贸然修改

Yoast SEO 28.2 曾在 PHP-FPM 日志中出现:

Plaintext
Using null as an array offset is deprecated

涉及两个文件:

Plaintext
src/memoizers/meta-tags-context-memoizer.php
src/memoizers/presentation-memoizer.php

检查源码后发现,这几条日志实际上来自同一个根因:

PHP
$this->cache[ $indexable->id ]

$indexable->idnull 时,同一个值会在多个位置被用作缓存键。

Presentation Memoizer 中也是相同逻辑。

这里不能简单把 null 转成空字符串,因为多个没有 ID 的临时 Indexable 可能共用同一个缓存键。这样虽然能让日志安静,却可能导致:

  • SEO 标题串用;
  • Canonical 串用;
  • Schema 上下文串用;
  • 不同页面之间缓存错误。

为了确认触发来源,我临时创建了一个 MU 插件,只在带专用测试参数的请求中捕获 Yoast 的 PHP 8.5 调用栈。

测试了:

  • 中文首页;
  • 英文首页;
  • 普通文章;
  • 搜索页面;
  • 404 页面。

结果分别为:

Plaintext
www-home: HTTP 200
en-home: HTTP 200
post-4891: HTTP 200
search: HTTP 200
not-found: HTTP 404

整个受控测试过程中,没有再次触发 Yoast 的 null array offset Deprecated。

测试结束后,临时 MU 插件也已经删除。

因此,最终决定是:

Yoast SEO 保持原样,不修改源码,也不为了无法稳定复现的日志重建索引。

此前日志可能来自后台请求、并发访问或某个短暂的特殊上下文。只有将来能够通过明确 URL 或明确后台操作稳定复现,才值得继续处理。


五、PublishPress Series:问题明确,但交给上游修复

PublishPress Series 在 PHP 8.5 中持续出现:

Plaintext
Method SplObjectStorage::attach() is deprecated
Method SplObjectStorage::contains() is deprecated

PHP 8.5 推荐分别改用:

Plaintext
offsetSet()
offsetExists()

这两处问题不会影响当前页面正常输出,但会持续污染日志。

由于 PublishPress Series 是仍在使用的重要插件,而且修复应当由插件作者统一完成,我没有直接修改本地源码,而是向官方仓库提交了问题:

PublishPress Series GitHub Issue #1163

当前处理方式是:

继续正常使用插件,等待官方版本修复。


六、最终处理结果

这轮排查结束后,各插件状态如下:

插件处理方式当前结果
TMS Extensions for Polylang回滚不必要的扩展补丁正常生产环境无致命错误
Nimble Page Builder停用页面正常,旧广告布局已消失
SyntaxHighlighter三行最小本地补丁高亮功能正常,三处 Deprecated 消失
Yoast SEO不修改常见生产页面无法复现
PublishPress Series提交上游 Issue功能正常,等待官方修复

七、这次排查中最重要的几个经验

1. 先判断插件是否还需要,再决定要不要修

Nimble Page Builder 就是最典型的例子。

一开始看到 Notice,很容易直接修改它的翻译加载逻辑。但查清用途后才发现,它只是在一篇旧文章后面插入了一个已经不需要的手动广告。

这种情况下,停用插件比维护补丁更合理。

2. 停用插件后仍看到旧内容,先怀疑缓存

WordPress 站点可能同时存在:

  • 页面缓存;
  • 对象缓存;
  • CDN 缓存;
  • PHP-FPM 进程中的已加载状态。

停用插件后立即请求页面,不一定看到的就是最新结果。

本次 Nimble 排查中,旧缓存一度让我误以为插件仍然在运行。

3. 日志时间相近,不代表来自同一个请求

PHP-FPM 日志可能同时混入:

  • 自己的测试请求;
  • 搜索引擎访问;
  • 后台 Ajax;
  • WP-Cron;
  • 普通访客请求;
  • CDN 回源请求。

Yoast 的 Deprecated 就是在混合日志中出现,但没有在五类受控页面中复现。

因此,不能只按时间窗口看到一条日志,就断定它来自刚才执行的命令。

4. WP-CLI 的 Deprecated 不等于前台问题

WP-CLI 自身打包的 php-cli-tools 在 PHP 8.5 下也会产生大量:

Plaintext
Colors.php on line 95

这属于命令行工具自身的兼容性问题,不影响 PHP-FPM 和网站前台。

同样,WP-CLI 启动时加载插件所产生的日志,也不能直接等同于真实用户访问。

5. 本地补丁必须满足三个条件

我认为只有同时满足以下条件,才适合修改插件源码:

  1. 问题可以稳定复现;
  2. 根因已经明确;
  3. 修改范围足够小,并且可以完整备份和回滚。

SyntaxHighlighter 符合这三个条件,所以做了三行修复。

Yoast SEO 不符合,所以没有修改。


结语

PHP 8.5 带来的许多兼容性日志,并不意味着网站已经不能运行。

真正需要做的,不是机械地消灭每一条 Warning 或 Deprecated,而是逐项判断:

  • 它是否发生在正常生产环境;
  • 是否真的影响功能;
  • 插件是否还有保留价值;
  • 应该本地修复、停用插件,还是等待上游更新。

这一次最终采用了四种不同策略:

不需要的插件直接停用,明确的小问题最小修复,无法复现的问题暂不处理,上游插件的问题交给上游。

相比追求“日志绝对清零”,这种做法更符合生产环境的实际需求,也更容易长期维护。

阿里云 OneinStack 实战:将 Redis 7.0.11 升级到 8.10.0,并完成内核优化与回滚保护

WordPress 网站维护、性能优化与博客运营咨询

本站已持续运营超过 10 年,累计发布 1000+ 篇原创技术文章,长期实践 WordPress 网站建设、CDN / Cloudflare 配置、缓存优化、Google SEO、广告变现和多语言网站运营。

如果你的 WordPress 网站遇到访问慢、缓存异常、插件冲突、广告不显示、SEO 基础结构混乱、CDN 配置不确定等问题,可以联系我做一次远程技术排查。

适合以下用户:
✅ 个人博客站长
✅ WordPress 网站运营者
✅ 独立开发者与内容创作者
✅ SaaS 产品官网运营团队
✅ 希望优化网站速度与稳定性的站点

服务内容:
✅ WordPress 速度优化
✅ Cloudflare / CDN / 缓存配置排查
✅ 插件冲突与页面异常排查
✅ AdSense 广告显示问题排查
✅ SEO 基础结构检查
✅ 博客运营与商业化咨询

如需了解方案或交流相关问题,请直接联系我,并注明:WordPress 维护咨询

联系方式:
Telegram:@shuijingwan
微信:13980074657
邮箱:shuijingwanwq@gmail.com

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理