插件开发 1
更新于 2026-10-13
插件开发 · 生命周期与钩子
一、生命周期回调
插件入口类可实现以下方法,程序在对应时机自动调用:
| 方法 | 触发时机 | 典型用途 |
|---|---|---|
install() | 安装后 | 建表、写初始配置 |
uninstall() | 卸载前 | 删表(如用户确认)、清理缓存 |
enable() | 启用时 | 注册路由、刷新缓存 |
disable() | 禁用时 | 清理临时数据 |
upgrade($from, $to) | 版本升级 | 字段变更、数据迁移 |
public function install()
{
// 建表
Db::execute("CREATE TABLE IF NOT EXISTS `ws_my_log` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`content` varchar(255) DEFAULT '',
`create_time` int unsigned DEFAULT 0,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
return true;
}
public function upgrade(string $from, string $to)
{
if (version_compare($from, '1.2.0', '<')) {
Db::execute("ALTER TABLE `ws_my_log` ADD COLUMN `ip` varchar(64) DEFAULT ''");
}
return true;
}
生命周期回调必须返回
true,返回false或抛异常会中断安装/卸载流程。
二、钩子(Hook)机制
文枢CMS 内置 Action(动作)与 Filter(过滤)两类钩子,支持优先级排序。
2.1 注册钩子
use think\facade\Hook;
// 在入口类的 enable() 或 initialize() 中注册
Hook::add('content_after_save', [$this, 'onContentSaved'], 10);
Hook::add('front_head', [$this, 'injectHead'], 5);
2.2 Action 钩子(无返回值,用于插入行为)
| 钩子名 | 触发点 | 参数 |
|---|---|---|
content_after_save | 内容保存后 | $content |
content_after_delete | 内容删除后 | $id |
user_after_register | 用户注册后 | $user |
order_paid | 订单支付成功 | $order |
front_head | 前台 </head> 前 | — |
front_footer | 前台 </body> 前 | — |
admin_dashboard | 后台控制台 | — |
public function injectHead()
{
echo '<meta name="my-plugin" content="1">' . "\n";
}
public function onContentSaved($content)
{
Db::name('my_log')->insert([
'content' => '内容已更新:' . ($content['title'] ?? ''),
'create_time' => time(),
]);
}
2.3 Filter 钩子(有返回值,用于修改数据)
| 钩子名 | 作用 | 参数 |
|---|---|---|
content_item | 修改单条内容输出 | $item |
content_list | 修改内容列表 | $list |
seo_meta | 修改页面 SEO 元信息 | $meta |
upload_save | 修改上传结果 | $result |
pay_amount | 修改订单金额 | $amount, $order |
Hook::add('content_item', function ($item) {
$item['title'] = '【置顶】' . $item['title'];
return $item;
}, 10);
Filter 钩子必须 return 处理后的数据,否则后续钩子拿到 null。
2.4 优先级
第三个参数为优先级,数值越小越先执行,默认 10。
Hook::add('seo_meta', [$this, 'a'], 5); // 先执行
Hook::add('seo_meta', [$this, 'b'], 20); // 后执行
三、路由注册
插件需要对外暴露地址时,在自己的路由文件中注册:
// addons/myplugin/route/route.php
use think\facade\Route;
Route::get('myplugin/callback', 'addons\myplugin\controller\Callback@index');
插件路由在启用时自动加载,禁用后失效。
四、调试建议
- 开启
APP_DEBUG = true后,钩子抛出的异常会带完整堆栈
- 用
Hook::listen('hook_name', $params)可手动触发,便于单测
- 注册钩子时避免在
__construct里做重活,会影响所有请求