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

PublishPress Series 3.1.3 升级实录:PHP 8.5 Issue 已修复,却又遇到 Gutenberg 系列编号回归

【图 1:8 月 6 日提交的 PublishPress Series PHP 8.5 兼容性 Issue #1163 已由上游关闭】

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 Post Views Counter 热门文章排行榜区块及浏览量设置界面,用于排查首页查询性能问题

(19) WordPress 动态首页从 19 秒降到 1 秒以内:Post Views Counter 热门文章查询性能问题排查与 MU Plugin 优化实战

WordPress 撰写设置中已开启可能影响网站性能的 Gutenberg 实时协作功能

(20) WordPress 7.0 + PHP 8.5 服务器配置全面审计:PHP-FPM、OPcache、Redis、RDS 与 WordPress 调优实战

【图 1:8 月 6 日提交的 PublishPress Series PHP 8.5 兼容性 Issue #1163 已由上游关闭】

(21) PublishPress Series 3.1.3 升级实录:PHP 8.5 Issue 已修复,却又遇到 Gutenberg 系列编号回归

此前升级到 PHP 8.5 以后,我曾经专门做过一轮 WordPress 插件兼容性检查。

当时的排查记录可以参考:

那一轮排查中,PublishPress Series Free 3.1.2 会在 PHP 8.5 下反复产生与 SplObjectStorage 有关的 Deprecated 警告。

典型内容包括:

Plaintext
SplObjectStorage::attach() is deprecated since 8.5
SplObjectStorage::contains() is deprecated since 8.5

进一步检查源码后可以确认,插件中的 AbstractCollection.php 多处直接调用了这两个已经在 PHP 8.5 中废弃的方法。

当时我没有直接修改安装目录中的插件源码,而是把问题提交给了 PublishPress Series 官方 GitHub:

https://github.com/publishpress/publishpress-series/issues/1163

对我来说,这种处理方式更加合适。

如果直接修改:

Plaintext
wp-content/plugins/organize-series/

下一次插件升级以后,本地修改很容易被直接覆盖。

因此当时的处理原则就是:

能够等待上游解决的问题,尽量交给上游解决;本地则尽可能保持插件原始状态。

没想到大约两周以后,这个问题终于迎来了后续。

Issue #1163 已经由上游关闭

重新打开当时提交的 Issue,可以看到:

Plaintext
PHP 8.5 deprecation warnings from
SplObjectStorage::attach() and contains()

#1163

Closed

页面右侧同时可以看到 3.13: Bug Fixes Milestone,以及相关开发记录和 v3.1.3 版本信息。

【图 1:8 月 6 日提交的 PublishPress Series PHP 8.5 兼容性 Issue #1163 已由上游关闭】
【图 1:8 月 6 日提交的 PublishPress Series PHP 8.5 兼容性 Issue #1163 已由上游关闭】

这意味着,从 GitHub Issue 状态来看,当时提交的问题已经进入官方修复版本。

不过,Issue 被关闭并不等于生产环境一定已经没有问题。

所以在升级以后,我还是继续检查了服务器上实际安装的版本和源码。

PublishPress Series 已升级至 3.1.3

当前生产环境使用的是:

Plaintext
PublishPress Series Free 3.1.3

插件状态正常:

Plaintext
version  3.1.3
status   active

随后重新检查:

Plaintext
wp-content/plugins/organize-series/src/domain/interfaces/AbstractCollection.php

原先涉及 PHP 8.5 Deprecated 的:

PHP
$this->attach(...)
$this->contains(...)

已经全部不存在。

实际检查结果为:

Plaintext
OK: no attach()/contains() calls found

对应的位置已经更换为:

PHP
$this->offsetSet(...)
$this->offsetExists(...)

其中包括此前 Issue 中涉及的 39、41、120、201、261、279、283 等位置。

【图 2:生产环境中的 PublishPress Series 3.1.3 已将旧的 attach()/contains() 调用全部替换】
【图 2:生产环境中的 PublishPress Series 3.1.3 已将旧的 attach()/contains() 调用全部替换】

从源码层面来说,Issue #1163 中报告的问题已经得到了完整处理。

关闭 WordPress Debug 后,不能只看日志判断问题是否消失

这里还有一个容易产生误判的地方。

前一天我刚刚清理 WordPress 站点健康问题,并关闭了 WordPress Debug。

因此,如果只是简单观察 PHP 日志中“不再出现 Deprecated”,其实并不能充分证明 PublishPress Series 的问题已经修复。

还有一种可能:

只是因为 Debug 被关闭以后,这些信息不再显示或者不再按照之前的方式记录。

所以这一次没有单纯依赖错误日志,而是主动做了一次 PHP 8.5 运行时测试。

测试中重新启用了 E_ALL,并专门捕获:

Plaintext
E_DEPRECATED
E_USER_DEPRECATED

然后实际创建 PublishPress Series 使用的 AbstractCollection,调用:

Plaintext
add()
hasObject()

最终结果为:

Plaintext
add(): OK
hasObject(): OK
DEPRECATIONS: 0
RESULT: Issue #1163 not reproduced
【图 3:主动捕获 E_DEPRECATED 后实际运行相关代码,Issue #1163 已无法复现】
【图 3:主动捕获 E_DEPRECATED 后实际运行相关代码,Issue #1163 已无法复现】

这一轮测试之后,才可以比较明确地确认:

我在 8 月 6 日提交的 PublishPress Series PHP 8.5 兼容性 Issue #1163,已经在当前使用的 3.1.3 中得到修复。

从提交 Issue,到等待上游,再到正式版本升级以后重新验证,这个问题算是终于闭环了。

但这次插件升级并没有就此结束。

升级以后,Gutenberg 中的系列选择方式发生了变化

PublishPress Series 升级以后,一个非常直观的变化是:

过去文章编辑器中的系列只能单选。

而现在 Gutenberg 右侧的“系列”面板变成了类似标签的选择方式,一篇文章看起来可以同时加入多个系列。

一开始我还怀疑是不是插件自动开启了 Multiple Series 功能。

但是进一步检查以后发现,当前使用的是 PublishPress Series Free 3.1.3,而后台“多个系列”本身仍然属于 Pro 功能,免费版并不能通过设置关闭或者开启这一项。

也就是说,现在 Gutenberg 中看到的多选式界面,并不等同于免费版主动启用了 Pro 的 Multiple Series。

继续对比 3.1.2 和 3.1.3 的实现以后可以发现,升级以后 Gutenberg 对 Series taxonomy 的处理方式发生了变化。

这也成为后面另一个问题的重要线索。

中文文章突然全部变成“无部分编号”

升级以后继续发布文章时,我很快发现一个更实际的问题。

中文文章依然能够正常选择系列,但是文章列表中的“系列”一栏开始出现:

Plaintext
无部分编号

更有意思的是,同一批文章对应的 English 版本却完全正常。

例如中文文章显示:

Plaintext
A Tour of Go 多语言翻译项目(无部分编号)

而对应 English 文章仍然正常显示:

Plaintext
A Tour of Go Multilingual Translation Project
(38 的第 36 部分)
(38 的第 37 部分)
(38 的第 38 部分)

今天发布的两篇 BeWild 文章同样如此。

中文:

Plaintext
BeWild 服务实测系列(无部分编号)

English:

Plaintext
BeWild Real-World Testing Series
(6 的第 5 部分)
(6 的第 6 部分)
【图 4:升级后新发布的中文文章仍属于正确系列,但 Series Part 显示为“无部分编号”】
【图 4:升级后新发布的中文文章仍属于正确系列,但 Series Part 显示为“无部分编号”】
【图 5:同一批 English 文章仍然正常生成 Series Part 编号】
【图 5:同一批 English 文章仍然正常生成 Series Part 编号】

这个对照非常重要。

它说明:

不是整个 PublishPress Series 的编号功能都失效了。

至少 English 流程依然可以正常写入编号。

问题更集中在中文 Gutenberg 文章的保存流程。

Series 归属其实没有丢,真正缺少的是 _series_part_*

随后直接从 WordPress 数据库层面检查这些文章。

结果发现,中文文章的 Series taxonomy 关系完全正常。

也就是说,它们确实已经属于正确的系列。

真正缺少的是类似下面这样的 post meta:

Plaintext
_series_part_41899
_series_part_42451
_series_part_42197

PublishPress Series 使用 Series taxonomy 保存“文章属于哪个系列”,而 Series Part 则另外保存在 post meta 中。

因此就会出现这样一种状态:

Plaintext
文章属于系列:正常
Series Part:不存在

最终后台就显示成:

Plaintext
无部分编号

而 English 对应文章中,同一项数据正常存在。

例如:

Plaintext
中文 26935
Series term:正常
Series Part:EMPTY

English 26943
Series Part:29

今天的 BeWild 两篇文章也是相同情况:

Plaintext
中文 26987:EMPTY
English 26994:5

中文 26997:EMPTY
English 27002:6

全站扫描,只发现 6 篇异常文章

为了避免只修复眼前看到的几篇文章,我随后对所有已经发布并且属于 Series 的文章进行了一次只读扫描。

最终结果非常整齐。

全站只有 6 篇文章存在:

Plaintext
已经属于某个 Series
但对应 _series_part_* 不存在

分别是:

Plaintext
26935
26947
26958
26968
26987
26997

而且全部都是插件升级以后发布的中文文章。

对应 English 文章的编号分别为:

Plaintext
26935 → 29

26947 → 36
26958 → 37
26968 → 38

26987 → 5
26997 → 6

更重要的是,修复前还检查了这些目标编号有没有被其他中文文章占用。

6 条全部为:

Plaintext
OK

因此可以安全恢复。

根据 English 对应编号恢复 6 篇中文文章

这里没有简单地把这些异常文章全部追加到当前系列末尾。

因为 English 对应文章已经保存了正确编号。

所以最可靠的方式就是直接根据对应 English 文章恢复中文 Series Part。

最终恢复结果为:

Plaintext
26935 → 29

26947 → 36
26958 → 37
26968 → 38

26987 → 5
26997 → 6

修复完成以后再次进行全站扫描:

Plaintext
TOTAL EMPTY SERIES PART: 0
【图 6:6 篇受影响中文文章全部恢复正确编号,全站已不存在缺失 Series Part 的已发布文章】
【图 6:6 篇受影响中文文章全部恢复正确编号,全站已不存在缺失 Series Part 的已发布文章】

至此,历史异常数据已经全部修复。

但如果只是修复这 6 篇,下一篇中文文章发布以后仍然有可能继续出现相同问题。

所以还需要处理未来的发布流程。

不降级插件,也不修改 PublishPress Series 源码

这里有几种可能的方案。

第一种是降级回 3.1.2。

但 3.1.3 已经解决了 PHP 8.5 的兼容性问题,如果为了恢复旧的 Gutenberg 行为重新降级,就意味着刚刚解决的 Deprecated 问题又可能重新回来。

第二种是直接修改 PublishPress Series 3.1.3 源码。

这同样不是我希望采用的方案。

因为插件后续升级以后,本地修改很容易被覆盖。

第三种是恢复 3.1.2 原来的单选 Series 编辑界面。

这个方案可以做,但经过进一步考虑以后,我发现其实没有必要。

虽然现在 Gutenberg 中看起来可以同时选择多个 Series,但我自己的使用规则一直是:

一篇文章只加入一个系列。

分类和标签本来就支持多选,而“系列只表达一条连续内容线”反而是我自己希望长期保持的内容组织方式。

因此编辑器界面是不是强制单选,对我来说并没有那么重要。

真正重要的是:

发布文章以后,应该自动成为所选系列的最后一部分。

最终只增加一个很小的 MU Plugin

PublishPress Series 自己其实仍然保留了自动排序函数:

PHP
set_series_order()

当传入的 Part 为 0,并且文章已经发布时,它本身就可以读取当前系列最后一篇文章的编号,然后自动执行:

Plaintext
最后一个 Part + 1

因此最终没有重新实现一套 Series 排序算法。

只是增加了一个很小的 MU Plugin:

Plaintext
swq-publishpress-series-auto-part.php

它挂在:

Plaintext
rest_after_insert_post

也就是 Gutenberg REST 保存完全结束以后。

逻辑很简单:

Plaintext
文章已经发布

文章恰好属于一个 Series

当前 Series Part 不存在

调用 PublishPress Series 自己的 set_series_order()

自动追加到当前系列最后一位

同时保留几个安全条件。

如果文章已经存在 Series Part:

Plaintext
直接退出

不会覆盖原有编号。

如果文章没有选择 Series:

Plaintext
直接退出

如果误选了两个或者更多 Series:

Plaintext
直接退出

不会自行猜测应该给哪个系列编号。

MU Plugin 创建以后进行 PHP 语法检查:

Plaintext
No syntax errors detected

WordPress 也已经正常识别:

Plaintext
swq-publishpress-series-auto-part    must-use

运行时需要的 PublishPress Series 函数和 Hook 同样全部正常:

Plaintext
set_series_order: OK
SERIES_PART_KEY: _series_part
rest_after_insert_post priority 20: REGISTERED

整个处理过程中没有修改 PublishPress Series 插件源码,也没有降级版本。

同时也没有因为这次调整进行 W3 Total Cache 全量缓存清理。

这篇文章本身,就是最后一次真实生产验收

到这里,历史数据已经恢复:

Plaintext
TOTAL EMPTY SERIES PART: 0

MU Plugin 也已经进入生产环境。

不过,还差最后一步:

验证下一篇真正通过 Gutenberg 发布的中文文章,是否能够重新自动获得 Series Part。

我没有另外创建一篇专门的测试文章。

这篇文章本身,就是修复后的第一篇真实生产验收文章。

发布本文时,我会继续按照平时的方式,只选择一个 Series,不手工填写 Series Part。

如果兼容修复正常工作,那么本文发布以后应该自动成为所属系列的最后一部分。

这一轮结果将在文章首次发布以后进行最后确认。

【图 7:本文发布以后自动获得所属系列最后一个 Series Part 编号——首次发布后补充】

结语

这次 PublishPress Series 3.1.3 升级经历比较特别。

8 月 6 日发现的 PHP 8.5 Deprecated 问题,当时没有修改插件源码,而是选择提交上游 Issue。

两周以后重新检查,可以确认:

Plaintext
Issue #1163 已关闭
源码中的旧调用已经完成替换
运行时 DEPRECATIONS: 0

这证明当时等待上游修复的选择是有效的。

但与此同时,升级到解决旧问题的新版本以后,又出现了新的 Gutenberg Series Part 保存异常。

最终通过数据库检查确认:

Plaintext
Series taxonomy 正常
Series Part 缺失

全站共有 6 篇受影响中文文章。

恢复以后:

Plaintext
TOTAL EMPTY SERIES PART: 0

对于未来文章,则没有降级插件,也没有修改第三方插件源码,而是增加一个很小的 MU Plugin,继续调用 PublishPress Series 自己已有的自动排序函数。

这次经历也再次说明:

插件升级并不是点击“更新”以后就结束了。

旧问题得到修复以后,新版本仍然值得做一次实际生产验证。

尤其是像系列编号这种不会直接导致网站报错、但会悄悄改变内容结构的数据问题,如果没有观察中英文后台的差异,很可能会在继续发布很多文章以后才被发现。

而这一次,从上游 Issue 修复,到新版本回归排查,再到历史数据恢复和未来发布兼容,最终都可以在不修改插件源码的情况下完成。

剩下的最后一步,就是让本文自己完成这次修复的真实生产验收。

WordPress 7.0 + PHP 8.5 服务器配置全面审计:PHP-FPM、OPcache、Redis、RDS 与 WordPress 调优实战

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