插件开发文档

纸鱼博客插件用于增加站点功能、监听系统事件、修改系统数据或输出前台内容。插件放在站点根目录的 plugins/ 下,每个插件使用一个独立目录。

插件目录

插件目录名只能使用小写字母、数字、下划线和连字符,长度为 1 到 50 个字符。

最小插件结构:

plugins/example/
├── plugin.json
└── index.php

plugin.json 描述插件,index.php 返回插件实现函数数组。

plugin.json

name 必须与目录名一致,titleversion 为必填项:

{
  "name": "example",
  "title": "示例插件",
  "version": "1.0.0",
  "apiVersion": 2,
  "description": "一个 Pafish 插件",
  "author": "你的名字",
  "authorUrl": "https://example.com",
  "homepage": "https://example.com/example-plugin",
  "settings": [],
  "injects": []
}

apiVersion 当前支持 12,建议使用 2。v2 插件只有在 injects 中声明过的前台注入点才会输出内容。

插件入口

index.php 必须返回数组。最常用的入口是 registerHooks

<?php
return [
    'registerHooks' => function (object $ctx): void {
        $ctx->on('after_login', function (array $user) use ($ctx): void {
            $ctx->log('用户登录:' . ($user['username'] ?? ''));
        });
    },
];

插件每次请求启动时都会注册钩子。停用插件后,系统会自动移除该插件注册的钩子。

插件上下文 ctx

registerHooks、生命周期和渲染函数都会收到插件上下文对象:

方法

用途

on($hook, $fn, $priority = 10)

注册 action 事件

filter($hook, $fn, $priority = 10)

注册 filter 过滤器

getData() / setData($data)

读写插件自有数据

getSettings() / setSettings($partial)

读写插件设置

log($message)

写入插件日志,最多保留 50 条

refreshInjections()

刷新注入内容;PHP 版即时渲染,无需额外操作

插件数据和插件设置分别保存在系统设置表的 plugin_data:{name}plugin_settings:{name} 中,使用 JSON 对象存储。

系统钩子

Action 事件

通过 $ctx->on() 注册:

钩子

参数

after_login

用户数组:idusernamerole

after_logout

用户 ID 数组

after_register

用户数组:idusername

after_post_save

保存事件数组:postcreatedactionextensions

after_create_post

新建文章数据

after_update_post

更新后的文章数据

after_post_published

已发布文章数据

after_delete_post

移入回收站的文章数据

after_purge_post

永久删除的文章数据

after_comment_submit

评论数据

after_comment_status

评论状态变更数据

after_comment_reply

回复评论数据

after_comment_delete

被删除的评论数据

示例:

'registerHooks' => function (object $ctx): void {
    $ctx->on('after_post_published', function (array $post) use ($ctx): void {
        $ctx->log('文章已发布:' . ($post['title'] ?? ''));
    });
},

Filter 过滤器

通过 $ctx->filter() 注册。过滤器的第一个参数是当前值,回调必须返回修改后的值:

'registerHooks' => function (object $ctx): void {
    $ctx->filter('frontend_meta', function (array $meta, array $context): array {
        $meta['robots'] = 'noindex';
        return $meta;
    });
},

当前常用过滤器包括:

  • before_login:登录前检查或修改登录决定

  • before_register:注册前检查或修改注册决定

  • before_comment_submit:评论写入前审核或拦截

  • frontend_meta:修改页面标题、描述、canonical、Open Graph 和 JSON-LD

  • upload_store_to_cloud:接管文件上传并返回云端 URL

  • upload_delete_from_cloud:删除云端文件时收到通知

过滤器应始终返回符合原接口约定的数据。需要阻止操作时,请返回带有 allowed: false 的决定数组,并提供清晰的 error 信息。

前台注入

plugin.json 中声明注入位置:

{
  "apiVersion": 2,
  "injects": ["head", "footer", "sidebar", "comment_form"]
}

然后在 index.php 中提供 renderInjection

'renderInjection' => function (string $target, object $ctx, array $context): string {
    if ($target !== 'footer') {
        return '';
    }
    return '<p class="plugin-note">由示例插件提供</p>';
},

支持的注入点:headfootersidebarcomment_formlogin_formregister_formpost_editor

head 注入只允许 scriptmetalinkstyle 标签;其他位置请自行保证输出安全。

插件设置

plugin.jsonsettings 中声明后台设置项:

{
  "settings": [
    {
      "key": "enabled_message",
      "label": "提示内容",
      "type": "text",
      "group": "基本设置",
      "default": "欢迎使用 Pafish"
    },
    {
      "key": "show_on_footer",
      "label": "显示在页脚",
      "type": "switcher",
      "default": "1"
    }
  ]
}

支持的类型:texttextareapasswordcheckboxswitcherselectradiocolorimage。选项型字段使用 options 对象。

插件中读取设置:

$settings = $ctx->getSettings();
$message = (string) ($settings['enabled_message'] ?? '');

生命周期

可以在 index.php 中定义以下回调:

return [
    'onActivate' => function (object $ctx): void {
        $ctx->log('插件已启用');
    },
    'onDeactivate' => function (object $ctx): void {
        // 停用时释放外部资源或清理运行状态
    },
    'onUninstall' => function (object $ctx): void {
        // 卸载前清理自有数据
    },
];

卸载时系统会在删除插件目录前调用 onUninstall,随后删除插件设置和自有数据。重要数据请在回调中完成清理或导出。

插件页面和页面模板

页面模板

在清单中声明页面模板:

{
  "pageTemplates": [
    {"name": "card", "title": "卡片页"}
  ]
}

再实现 renderPageTemplate($template, $page, $ctx)。返回空字符串或 null 时,系统会继续使用默认页面渲染。

插件前台页面

在清单中声明页面路径:

{
  "pages": [
    {"path": "dashboard", "title": "插件面板"}
  ]
}

实现 renderPluginPage($path, $ctx) 后,页面地址为:

/plugin/example/dashboard

页面只有在插件已激活、路径已声明且渲染函数返回非空 HTML 时才会显示。

安装和发布

  1. 将插件目录放入 plugins/,或在后台“应用商店”中安装。

  2. 检查插件清单是否通过校验。

  3. 在后台“插件”页面启用插件并配置设置。

  4. 测试前台页面、后台功能和停用后的回退行为。

  5. 发布时将插件目录压缩为 zip;压缩包只能包含一个顶层目录,大小不能超过 10MB。

开发建议

  • 使用 API v2,并在 plugin.json 中明确声明 injects

  • 插件名称、设置键和页面路径一旦发布,尽量保持不变。

  • 所有 HTML 输出和用户输入都要进行转义或严格校验。

  • 不要直接修改纸鱼博客核心文件;优先使用钩子、主题和插件接口。

  • 外部请求应设置超时,并处理网络失败,不要阻塞页面请求。

  • 不要把密钥写入代码或提交到公开仓库。

评论区

写下评论

1000 字内

昵称必填,邮箱不会公开。评论提交后会先进入审核。

全部评论

0

还没有评论,欢迎留下你的补充或反馈。