插件开发模型
插件用于扩展 ClayBBS 的业务能力,例如新增后台页面、监听 Hook、扩展通知、接入外部服务、增加内容处理逻辑等。插件启用后,系统会加载插件目录中的 bootstrap.php。
插件命名规范
- slug:只允许小写英文、数字、下划线、短横线,例如
hello_notice。 - 命名空间:建议使用
Plugin\你的Slug或避免声明命名空间,防止和主系统类冲突。 - 数据库表:建议使用
plugin_插件slug_业务名,例如plugin_hello_notice_logs。 - 配置键:建议使用
plugin_插件slug_配置名,避免污染全局设置。 - 版本号:使用语义化版本,修复补丁递增第三位,新增兼容能力递增第二位,破坏性变化递增第一位。
插件目录结构
hello_notice/ ├── market.json ├── plugin.json ├── bootstrap.php ├── migrations/ │ └── 202605070001_create_table.sql ├── views/ │ └── admin/index.php ├── assets/ │ ├── css/plugin.css │ └── js/plugin.js └── README.md
market.json:市场识别文件,提交官方市场时必须提供。plugin.json:论坛端插件识别文件。bootstrap.php:插件启用后的入口。migrations/:数据库迁移文件,建议可重复执行。
plugin.json / market.json
{
"type": "plugin",
"slug": "hello_notice",
"name": "Hello Notice",
"version": "1.0.0",
"api_version": "1.0.0",
"min_core_version": "1.0.0",
"description": "一个插件开发示例",
"author": "你的名字"
}slug 只能使用英文、数字、下划线和短横线。上线后不要频繁变更 slug,否则会影响升级、授权识别和用户迁移。
api_version 声明插件依赖的 Extension API 版本,论坛加载时会检查兼容性。不声明或版本不兼容时插件无法启用。
min_core_version 声明插件要求的最低论坛版本。
market.json 同样包含这些字段,但用于提交官方市场识别;plugin.json 用于论坛本地识别。
插件生命周期
- 安装:官方市场包下载到论坛端,校验类型和 slug 后解压到
plugins/slug。 - 启用:后台开启插件,slug 写入
plugins_enabled设置。 - 启动:每次请求启动时,系统加载已启用插件的
bootstrap.php。 - 运行:插件通过 Hook、服务类、模板或后台入口扩展能力。
- 停用:插件不再加载
bootstrap.php,但数据通常保留。 - 卸载:删除插件目录;如需删除数据,应由插件提供明确迁移/卸载说明,不建议默认清库。
PluginApi 方法速查
所有插件必须通过 App\Extension\PluginApi 与论坛核心交互。建议统一别名:use App\Extension\PluginApi as ClayPlugin;
| 分类 | 方法 | 说明 |
|---|---|---|
| 系统 | version() | 返回 API 版本号 |
| 系统 | siteUrl() | 获取站点根 URL,用于拼接回调/绝对路径 |
| 系统 | assetUrl(slug, path) | 获取插件静态资源 URL |
| 钩子 | listen(hook, callback, priority) | 监听系统钩子 |
| 钩子 | fire(hook, payload) | 主动触发事件 |
| 钩子 | filter(hook, value, context) | 过滤值(类似 apply_filters) |
| 路由 | get(path, handler) | 注册 GET 路由 |
| 路由 | post(path, handler) | 注册 POST 路由 |
| UI | adminMenu(html, group, priority) | 后台侧边栏菜单项 |
| UI | userQuickAction(html, priority) | 用户中心快捷操作 |
| UI | appendStyles(html, priority) | 注入 CSS/JS 到前台 head |
| 数据库 | db() | 获取 PDO 数据库连接 |
| 设置 | setting(key, default) | 读取站点全局设置 |
| 设置 | setSetting(key, value) | 写入站点全局设置 |
| 设置 | pluginSetting(slug, key, default) | 读取插件私有设置 |
| 设置 | setPluginSetting(slug, key, value) | 写入插件私有设置 |
| 安全 | csrfField() | 输出 CSRF 隐藏字段 |
| 安全 | csrfVerify() | 校验 CSRF token |
| 用户 | currentUser() | 获取当前登录用户信息 |
| 工具 | e(value) | HTML 转义输出 |
方法详情见源码 PHPDoc 或 app/Extension/PluginApi.php。
bootstrap.php 接入
<?php
use App\Core\Hook;
Hook::listen('app.booted', function () {
// 插件初始化逻辑
});bootstrap.php 会随请求加载,必须保持轻量。不要在这里执行耗时任务、远程请求或大量数据库扫描。
Hook 与过滤器
使用 PluginApi 监听事件和过滤数据:
use App\Extension\PluginApi as ClayPlugin;
ClayPlugin::listen('thread.created', function (array $payload) {
$thread = $payload['thread'];
// 新帖子发布后的处理逻辑
return $payload;
});
$filtered = ClayPlugin::filter('thread.title', $title, ['thread_id' => 1]);主动触发事件(广播给其他插件):
ClayPlugin::fire('my_plugin.event', ['data' => $someData]);插件应优先通过 Hook 接入,不要直接修改主系统文件。若当前 Hook 不够,应在插件文档中说明需要新增的 Hook 点,再由官方评估加入主系统。
后台页面开发
插件如果需要后台页面,建议遵守主系统后台风格:表格、表单、分区清晰,不要做大卡片堆叠。
// 示例思路:bootstrap.php 中注册你的菜单/入口,后台控制器中必须做权限校验
use App\Middleware\AdminAuth;
use App\Middleware\Permission;
AdminAuth::check();
Permission::require('admin.settings');- 所有 POST 操作必须调用
csrf_verify()。 - 删除、回滚、批量处理等高风险动作必须二次确认。
- 后台页面不要泄露密钥、token、授权码原文。
数据库与权限
- 建表 SQL 放在
migrations/,字段名和索引要清晰。 - 后台入口必须检查管理员权限,不要只靠前端隐藏。
- 涉及钱包、订单、授权、用户状态的操作必须服务端二次校验。
- 危险操作必须有 CSRF 和确认流程。
授权与付费入口保护
付费插件必须声明授权要求和受保护入口。官方站在已购买且绑定域名后,会在下载包根目录注入 license.json / market-license.json;论坛端会使用官方公钥校验签名和域名。
{
"type": "plugin",
"slug": "hello_notice",
"name": "Hello Notice",
"version": "1.0.0",
"license": {
"required": true,
"protected_routes": ["/admin/hello-notice"],
"protected_hooks": ["admin.menu.plugins"],
"protected_features": ["admin_page", "frontend_display"]
}
}插件代码中应在关键入口调用统一授权网关:
use App\Services\MarketLicenseService;
MarketLicenseService::guard('plugin', 'hello_notice', 'admin_page');
if (!MarketLicenseService::featureAllowed('plugin', 'hello_notice', 'frontend_display')) {
return $payload;
}- 未授权或域名不匹配时,论坛不会启用付费插件。
- 菜单、Hook 输出、后台控制器、前台路由都应按 feature 做保护。
- 破解包即使被手动复制,也无法通过官方更新接口下载新版本。
- PHP 源码无法绝对防破解,但入口网关 + 官方更新授权能提高破解成本。
插件安全清单
- 所有数据库写入使用预处理,不拼接用户输入。
- 上传文件必须限制 MIME、扩展名、大小和真实内容。
- 不要使用
eval、动态 include 用户路径、反序列化不可信数据。 - 远程请求设置超时,并处理失败。
- 不要在插件包内放置私钥、数据库密码、授权 token。
- 不要修改系统用户、钱包、订单、授权状态,除非有明确权限和日志。
插件打包发布
- 复制示例工程并修改 slug/name/version。
- 本地安装、启用、禁用、卸载测试。
- 测试管理员、普通用户、未登录用户三种状态。
- 确认不包含
.git、日志、上传文件、密钥、数据库配置。 - 压缩插件根目录,确保 zip 解压后第一层就是插件目录。
- 到开发者中心创建插件并提交审核。
插件示例工程
包含 market.json、plugin.json、api_version 声明、bootstrap.php(路由注册 + 后台菜单 + 样式注入)和 README。