插件上线前夜,我把这七项"灯下黑"问题钉在便签纸上逐项敲掉
每次发版前都觉得自己测得够细了,结果上线后总有人在群里@我说"菜单找不到了"或者"配置保存完刷新又回去了"。后来干脆列了张私人的"灯下黑"清单,专门抓那些"代码没问题但体验翻车"的死角。下面这几条是我最近两次发版实打实踩过的,分享出来当个对照。
一、权限:别只测管理员账号
我最常犯的错是全程用超管账号测后台,上线后编辑角色点进来直接白屏。现在我的习惯是开三个浏览器无痕窗口,分别登超管、编辑、订阅者,把每个菜单项都点一遍。
有个隐蔽坑:add_menu_page 的 capability 参数如果填了自定义的字符串(比如 'my_plugin_view'),但忘了在 user_has_cap 或角色初始化时分配,WordPress 不会报错,只会直接把菜单吞掉。建议用 current_user_can('my_plugin_view') 在页面顶部再拦一道,比依赖菜单自身的权限判断更稳。
二、路由:REST 端点的"命名空间幽灵"
注册路由时 namespace 带斜杠和不带斜杠,在 register_rest_route 里表现不一样。我之前写成:
register_rest_route('my-plugin/v1', '/items', ...);
本地用 Postman 测 /wp-json/my-plugin/v1/items 完全正常,但某台服务器的伪静态规则把带连字符的 namespace 拦了,返回 404。后来改成全小写无连字符的 myplugin/v1 才过。上线前现在我会用 rest_url() 拼接完整 URL 再 curl 一遍,而不是直接手写路径。
三、菜单:子菜单的"父菜单 slug 陷阱"
add_submenu_page 第一个参数是父菜单 slug,不是标题。我有一次重构把父菜单的 slug 从 my-plugin 改成 my_plugin_dashboard,结果三个子菜单全飘到设置页下面去了——因为它们还指着旧的 slug,WordPress 找不到匹配就默认挂到设置底下。
现在的做法是把所有 slug 定义成类常量,子菜单注册时引用常量,改一处全局生效。
四、配置:选项名的"隐性缓存"比你想的顽固
用 update_option 保存配置后,如果同一请求里后面又读了这条配置,WordPress 的对象缓存可能返回旧值。我踩过的场景:保存按钮触发 update_option('my_plugin_settings', $new),然后立即用 get_option('my_plugin_settings') 做响应回显,结果前端收到的是上一次的值。
解决是在 update_option 后手动 wp_cache_delete('my_plugin_settings', 'options'),或者干脆把响应数据用提交上来的 $new 直接组装,不再回读数据库。
五、多站点:激活钩子在子站点"装死"
单站点测得好好的,多站点网络激活时发现数据表只在主站建了。原因是 register_activation_hook 只在当前站点上下文跑。如果插件支持多站点,得在 wp_initialize_site 钩子里补一张"新站点自动补建表"的逻辑,否则网络管理员开新站点后插件直接报错。
六、卸载清理:用户数据留不留要写在明处
register_uninstall_hook 里删表很简单,但选项值、上传目录里的缓存文件、用户元数据这些要不要清?我之前默认全清,结果有用户卸载重装后配置全丢,在论坛骂了一页。现在我在设置页加个复选框:"卸载时保留配置数据",把选择权交出去,卸载钩子里根据这个选项的值走不同分支。
七、最后一步:用"脏数据"跑一遍
正式上线前,我会故意往配置框里塞特殊字符、超长字符串、emoji、SQL 片段,看看会不会把页面搞崩或者存进数据库后读出来乱码。这个习惯帮我抓到过两次 esc_attr 和 wp_kses_post 混用导致的输出截断问题。
你们发版前有没有专属的"灯下黑"检查项?比如某种特定环境才触发的怪毛病,或者某个 WordPress 版本的兼容暗坑。欢迎往楼里丢,我补进自己的清单里。

