此前升级到 PHP 8.5 以后,我曾经专门做过一轮 WordPress 插件兼容性检查。
当时的排查记录可以参考:
那一轮排查中,PublishPress Series Free 3.1.2 会在 PHP 8.5 下反复产生与 SplObjectStorage 有关的 Deprecated 警告。
典型内容包括:
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
对我来说,这种处理方式更加合适。
如果直接修改:
wp-content/plugins/organize-series/下一次插件升级以后,本地修改很容易被直接覆盖。
因此当时的处理原则就是:
能够等待上游解决的问题,尽量交给上游解决;本地则尽可能保持插件原始状态。
没想到大约两周以后,这个问题终于迎来了后续。
Issue #1163 已经由上游关闭
重新打开当时提交的 Issue,可以看到:
PHP 8.5 deprecation warnings from
SplObjectStorage::attach() and contains()
#1163
Closed页面右侧同时可以看到 3.13: Bug Fixes Milestone,以及相关开发记录和 v3.1.3 版本信息。

这意味着,从 GitHub Issue 状态来看,当时提交的问题已经进入官方修复版本。
不过,Issue 被关闭并不等于生产环境一定已经没有问题。
所以在升级以后,我还是继续检查了服务器上实际安装的版本和源码。
PublishPress Series 已升级至 3.1.3
当前生产环境使用的是:
PublishPress Series Free 3.1.3插件状态正常:
version 3.1.3
status active随后重新检查:
wp-content/plugins/organize-series/src/domain/interfaces/AbstractCollection.php原先涉及 PHP 8.5 Deprecated 的:
$this->attach(...)
$this->contains(...)已经全部不存在。
实际检查结果为:
OK: no attach()/contains() calls found对应的位置已经更换为:
$this->offsetSet(...)
$this->offsetExists(...)其中包括此前 Issue 中涉及的 39、41、120、201、261、279、283 等位置。

从源码层面来说,Issue #1163 中报告的问题已经得到了完整处理。
关闭 WordPress Debug 后,不能只看日志判断问题是否消失
这里还有一个容易产生误判的地方。
前一天我刚刚清理 WordPress 站点健康问题,并关闭了 WordPress Debug。
因此,如果只是简单观察 PHP 日志中“不再出现 Deprecated”,其实并不能充分证明 PublishPress Series 的问题已经修复。
还有一种可能:
只是因为 Debug 被关闭以后,这些信息不再显示或者不再按照之前的方式记录。
所以这一次没有单纯依赖错误日志,而是主动做了一次 PHP 8.5 运行时测试。
测试中重新启用了 E_ALL,并专门捕获:
E_DEPRECATED
E_USER_DEPRECATED然后实际创建 PublishPress Series 使用的 AbstractCollection,调用:
add()
hasObject()最终结果为:
add(): OK
hasObject(): OK
DEPRECATIONS: 0
RESULT: Issue #1163 not reproduced
这一轮测试之后,才可以比较明确地确认:
我在 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 的处理方式发生了变化。
这也成为后面另一个问题的重要线索。
中文文章突然全部变成“无部分编号”
升级以后继续发布文章时,我很快发现一个更实际的问题。
中文文章依然能够正常选择系列,但是文章列表中的“系列”一栏开始出现:
无部分编号更有意思的是,同一批文章对应的 English 版本却完全正常。
例如中文文章显示:
A Tour of Go 多语言翻译项目(无部分编号)而对应 English 文章仍然正常显示:
A Tour of Go Multilingual Translation Project
(38 的第 36 部分)
(38 的第 37 部分)
(38 的第 38 部分)今天发布的两篇 BeWild 文章同样如此。
中文:
BeWild 服务实测系列(无部分编号)English:
BeWild Real-World Testing Series
(6 的第 5 部分)
(6 的第 6 部分)

这个对照非常重要。
它说明:
不是整个 PublishPress Series 的编号功能都失效了。
至少 English 流程依然可以正常写入编号。
问题更集中在中文 Gutenberg 文章的保存流程。
Series 归属其实没有丢,真正缺少的是 _series_part_*
随后直接从 WordPress 数据库层面检查这些文章。
结果发现,中文文章的 Series taxonomy 关系完全正常。
也就是说,它们确实已经属于正确的系列。
真正缺少的是类似下面这样的 post meta:
_series_part_41899
_series_part_42451
_series_part_42197PublishPress Series 使用 Series taxonomy 保存“文章属于哪个系列”,而 Series Part 则另外保存在 post meta 中。
因此就会出现这样一种状态:
文章属于系列:正常
Series Part:不存在最终后台就显示成:
无部分编号而 English 对应文章中,同一项数据正常存在。
例如:
中文 26935
Series term:正常
Series Part:EMPTY
English 26943
Series Part:29今天的 BeWild 两篇文章也是相同情况:
中文 26987:EMPTY
English 26994:5
中文 26997:EMPTY
English 27002:6全站扫描,只发现 6 篇异常文章
为了避免只修复眼前看到的几篇文章,我随后对所有已经发布并且属于 Series 的文章进行了一次只读扫描。
最终结果非常整齐。
全站只有 6 篇文章存在:
已经属于某个 Series
但对应 _series_part_* 不存在分别是:
26935
26947
26958
26968
26987
26997而且全部都是插件升级以后发布的中文文章。
对应 English 文章的编号分别为:
26935 → 29
26947 → 36
26958 → 37
26968 → 38
26987 → 5
26997 → 6更重要的是,修复前还检查了这些目标编号有没有被其他中文文章占用。
6 条全部为:
OK因此可以安全恢复。
根据 English 对应编号恢复 6 篇中文文章
这里没有简单地把这些异常文章全部追加到当前系列末尾。
因为 English 对应文章已经保存了正确编号。
所以最可靠的方式就是直接根据对应 English 文章恢复中文 Series Part。
最终恢复结果为:
26935 → 29
26947 → 36
26958 → 37
26968 → 38
26987 → 5
26997 → 6修复完成以后再次进行全站扫描:
TOTAL EMPTY SERIES PART: 0
至此,历史异常数据已经全部修复。
但如果只是修复这 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 自己其实仍然保留了自动排序函数:
set_series_order()当传入的 Part 为 0,并且文章已经发布时,它本身就可以读取当前系列最后一篇文章的编号,然后自动执行:
最后一个 Part + 1因此最终没有重新实现一套 Series 排序算法。
只是增加了一个很小的 MU Plugin:
swq-publishpress-series-auto-part.php它挂在:
rest_after_insert_post也就是 Gutenberg REST 保存完全结束以后。
逻辑很简单:
文章已经发布
↓
文章恰好属于一个 Series
↓
当前 Series Part 不存在
↓
调用 PublishPress Series 自己的 set_series_order()
↓
自动追加到当前系列最后一位同时保留几个安全条件。
如果文章已经存在 Series Part:
直接退出不会覆盖原有编号。
如果文章没有选择 Series:
直接退出如果误选了两个或者更多 Series:
直接退出不会自行猜测应该给哪个系列编号。
MU Plugin 创建以后进行 PHP 语法检查:
No syntax errors detectedWordPress 也已经正常识别:
swq-publishpress-series-auto-part must-use运行时需要的 PublishPress Series 函数和 Hook 同样全部正常:
set_series_order: OK
SERIES_PART_KEY: _series_part
rest_after_insert_post priority 20: REGISTERED整个处理过程中没有修改 PublishPress Series 插件源码,也没有降级版本。
同时也没有因为这次调整进行 W3 Total Cache 全量缓存清理。
这篇文章本身,就是最后一次真实生产验收
到这里,历史数据已经恢复:
TOTAL EMPTY SERIES PART: 0MU Plugin 也已经进入生产环境。
不过,还差最后一步:
验证下一篇真正通过 Gutenberg 发布的中文文章,是否能够重新自动获得 Series Part。
我没有另外创建一篇专门的测试文章。
这篇文章本身,就是修复后的第一篇真实生产验收文章。
发布本文时,我会继续按照平时的方式,只选择一个 Series,不手工填写 Series Part。
如果兼容修复正常工作,那么本文发布以后应该自动成为所属系列的最后一部分。
这一轮结果将在文章首次发布以后进行最后确认。
【图 7:本文发布以后自动获得所属系列最后一个 Series Part 编号——首次发布后补充】
结语
这次 PublishPress Series 3.1.3 升级经历比较特别。
8 月 6 日发现的 PHP 8.5 Deprecated 问题,当时没有修改插件源码,而是选择提交上游 Issue。
两周以后重新检查,可以确认:
Issue #1163 已关闭
源码中的旧调用已经完成替换
运行时 DEPRECATIONS: 0这证明当时等待上游修复的选择是有效的。
但与此同时,升级到解决旧问题的新版本以后,又出现了新的 Gutenberg Series Part 保存异常。
最终通过数据库检查确认:
Series taxonomy 正常
Series Part 缺失全站共有 6 篇受影响中文文章。
恢复以后:
TOTAL EMPTY SERIES PART: 0对于未来文章,则没有降级插件,也没有修改第三方插件源码,而是增加一个很小的 MU Plugin,继续调用 PublishPress Series 自己已有的自动排序函数。
这次经历也再次说明:
插件升级并不是点击“更新”以后就结束了。
旧问题得到修复以后,新版本仍然值得做一次实际生产验证。
尤其是像系列编号这种不会直接导致网站报错、但会悄悄改变内容结构的数据问题,如果没有观察中英文后台的差异,很可能会在继续发布很多文章以后才被发现。
而这一次,从上游 Issue 修复,到新版本回归排查,再到历史数据恢复和未来发布兼容,最终都可以在不修改插件源码的情况下完成。
剩下的最后一步,就是让本文自己完成这次修复的真实生产验收。
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

