登录 注册
Developer WikiPluginThemeAPI v1.0.0

面向生态开发者的工程文档

当前 Extension API 版本 1.0.0,核心最低要求 1.0.0。从插件、主题到授权、打包与安全规范,帮助开发者以官方兼容方式扩展 ClayBBS。文档公开阅读;示例工程仅开发者账号可下载。

📖 论坛端完整 API 参考:app/Extension/ExtensionContract.php · 打包规范:docs/extension-manifest-spec.md · API 文档:docs/extension-api.md

插件开发模型

插件用于扩展 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 用于论坛本地识别。

插件生命周期

  1. 安装:官方市场包下载到论坛端,校验类型和 slug 后解压到 plugins/slug
  2. 启用:后台开启插件,slug 写入 plugins_enabled 设置。
  3. 启动:每次请求启动时,系统加载已启用插件的 bootstrap.php
  4. 运行:插件通过 Hook、服务类、模板或后台入口扩展能力。
  5. 停用:插件不再加载 bootstrap.php,但数据通常保留。
  6. 卸载:删除插件目录;如需删除数据,应由插件提供明确迁移/卸载说明,不建议默认清库。

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 路由
UIadminMenu(html, group, priority)后台侧边栏菜单项
UIuserQuickAction(html, priority)用户中心快捷操作
UIappendStyles(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。
  • 不要修改系统用户、钱包、订单、授权状态,除非有明确权限和日志。

插件打包发布

  1. 复制示例工程并修改 slug/name/version。
  2. 本地安装、启用、禁用、卸载测试。
  3. 测试管理员、普通用户、未登录用户三种状态。
  4. 确认不包含 .git、日志、上传文件、密钥、数据库配置。
  5. 压缩插件根目录,确保 zip 解压后第一层就是插件目录。
  6. 到开发者中心创建插件并提交审核。
公益开发者只能发布免费插件;普通开发者可以发布免费或付费插件。

插件示例工程

Hello Notice 示例插件

包含 market.json、plugin.json、api_version 声明、bootstrap.php(路由注册 + 后台菜单 + 样式注入)和 README。

成为开发者后下载