我维护一套 50+ 插件的社区站点插件集,覆盖内容管道、主题导航、互动积分、后台管理、通知私信、榜单统计等类型。按 v11 beta 的代码逐项核对后,给几条 beta 窗口内改成本最低、上线后再改成本很高的建议。
一、links 是否必要:建议保留,但不要按“性能优化”定位
同意 @bbs1org 结论:它的核心价值是入口数据化、统一校验、故障隔离,性能只是顺带。我们的场景里,确实存在两类入口:
- 插件在前台只负责一条链接(迁 links 收益高);
- 插件本来就会因其它 Hook 加载,入口回调只是一行 append(收益几乎为零,只剩校验价值);
- 带未读角标、动态文案、
plugin_asset_require()的入口(必须继续 Hook)。
因此建议明确写入规范:links 是“纯静态入口”的声明方式,不做全量迁移;动态入口永远留 Hook。否则第三方插件容易为了“数据化”把动态逻辑塞进 links,最后既丢功能又难排查。
二、若保留 links,beta 前建议补齐 6 个契约(按优先级)
admin_tabs的“导航 + 内容”同源
现在
links.admin_tabs只生成导航,内容仍由admin_tabs回调渲染。插件作者按“声明 links 后回调会被跳过”的字面理解删掉内容回调,就会出现“入口在、点开空白/404”。建议二选一:admin_tabs支持对象形式:'admin_tabs' => ['key' => ['label'=>'...','callback'=>'...','order'=>...]];- 或允许
links.admin_tabs条目带content回调,由核心自动配对; - 至少要在 PLUGIN.md 明确:links.admin_tabs 与 admin_tabs 内容回调必须同时保留。
- 入口校验 fail-closed
when.config/when.ctx中非法规则目前被静默跳过;如果所有条件都非法,when变空,链接变成无条件显示。params的非法键/值也是逐个跳过但整条链接仍渲染。对“仅本人/仅管理员/依赖 id”的入口,这是实际风险。建议:- 任一
when或params非法 → 丢弃整条 link; - 同步/更新接口返回被丢弃的条目与原因,后台插件列表给出提示;20 条上限超限也一样。
- 每个入口的 ctx 契约要写清并校验
现在
{forum_id}、{self}等占位符在不同入口上下文并不都存在;写了不存在的键,整条链接会静默不渲染,作者很难定位。建议:- PLUGIN.md 按入口列出可用 ctx 键;
- 同步期把“该入口不存在的占位符”判为非法并给出原因。
- Tab key 命名空间与稳定顺序
当前 Tab 链接直接覆盖同名 key,可能顶掉核心或其它插件的 Tab;
before/after锚点不存在时追加,多个插件追加的顺序也未定义。建议:- 保留字清单(settings/forums/groups/plugins/profile/topics/replies/notifications/admin 等);
- Tab key 强制插件前缀,或核心自动命名空间;
- 明确排序规则(插件 ID + 声明顺序),避免同一页 Tab 顺序漂移。
- URL / route 校验
url目前允许协议相对地址//host,与“只允许相对或 http/https”的口径不一致,建议显式拒绝;route不校验是否存在,写错只在点击时 404,建议同步期校验路由或在文档标注。
icon_html白名单
当前只允许
svg/path/circle/rect/line/polyline/polygon/g,会误杀<ellipse>/<defs>/<linearGradient>等常用图标元素;同时又未拦fill="url(...)"这类外部引用。建议给一份官方安全 SVG 白名单,或明确“数据入口只用核心 icon 名”。三、按需资源:建议补 4 个能力
- 路由级资源声明
页面型插件路由(榜单、签到、推广页、日志页等)在
routes里只有 callback;改为按需模式后,每个路由都要手动plugin_asset_require(),漏一个就是裸页面。建议routes支持对象形式并声明资源(assets => 'all'|['css','js']),核心在路由分发前自动登记,旧字符串格式兼容。assets_mode支持按类型
assets_mode现在是插件级,CSS/JS 只能一起公共或一起按需;实际大量插件是“CSS 内容页常驻、JS 只在编辑/弹层页用”。建议支持assets_mode => ['css'=>'common','js'=>'ondemand'](或css_mode/js_mode),这样规则里的“列表页只用样式、不输出脚本”才能真正落地。- AJAX 片段的资源句柄
现在 AJAX 局部 HTML 明确不输出资源。弹卡、投票局部刷新、编辑器预览这类 AJAX UI,只能靠“首次整页提前登记”,页面组合一多就会漏。建议:
json_response可附带本次plugin_asset_require()收集到的 handles;- 核心 JS 提供去重加载(如
bbs1.loadAssets(handles)); - 或让
plugin_asset_require()返回 handles,由插件自行回传。
- 页面级 Hook 的 ctx 标准化
资源按需与页面注入都要求“按路由/页面类型判断”,但当前插件只能用
$_GET['a']自己解析,美化 URL、后台、AJAX 等路径容易误判。建议page.before_render/page.head/page.footer/page.template的 ctx 统一带route、page_type、is_ajax、plugin_route。四、兼容与迁移成本
- 同意“双份维护是 links 最大的代价”。建议明确:旧内核兼容期内不删旧回调,并在同步诊断里标出“该入口已由 links 接管、回调在新内核为死代码”,方便后续清理。
- v11 移除了 v10 的全局
plugin_registry_row()/plugin_update_row()(已内化到Plugin);建议升级说明列出这类全局函数清单,避免第三方插件 fatal。 - PLUGIN.md 中“老内核的
plugin_asset_require()不认识第二个参数”的表述不准确:老内核根本没有该函数,裸调会直接 fatal,必须function_exists()兜底。建议修正,避免作者照抄出错。
五、建议的 beta 验收用例
- 仅声明
links.admin_tabs、不保留内容回调 → 应明确报错/文档阻止,而不是空白页。 when.config写错键名 → 整条入口不出现,同步返回“条件非法”。params缺id→ 整条入口不出现,而不是链到无参页面。- 插件 Tab key 与核心
settings同名 → 不覆盖核心 Tab。 feature_links使用{forum_id}→ 同步期提示该入口不支持。- 按需插件在 AJAX 弹层返回 HTML → 资源能按 handles 加载,或文档明确要求首次整页登记。
- CSS 公共 + JS 按需 → 列表页只输出 CSS,编辑页才输出 JS。
- 老内核加载带
links/assets_mode的插件 → 仍走旧回调/公共合集,不报错。
结论:links 建议保留,但按“纯静态入口的数据化 + 统一校验 + 故障隔离”定位,不做全量迁移;若 beta 期能先补齐
admin_tabs内容契约、fail-closed 校验、Tab 命名空间这三项,后续第三方插件迁移的成本和事故率会低很多。按需资源则建议优先补“路由级声明 + 按类型模式 + AJAX handles”,否则这套机制对大多数页面型插件只能停留在“整包搬走”的半成品状态。主楼