feat: 前台 .shtml 后缀 canonical + strict_types 全量启用 + 对外 API(Sanctum+Scramble 文档)+ pm2 ecosystem + GitHub Actions CI + 插件/主题/架构/API 文档 + REDIS_PREFIX 说明
This commit is contained in:
+119
@@ -0,0 +1,119 @@
|
||||
# 插件开发指南
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
plugins/{vendor}.{name}/
|
||||
├── plugin.json # 插件清单(必填)
|
||||
├── src/
|
||||
│ ├── ServiceProvider.php # 插件入口(继承基类)
|
||||
│ ├── ... # 业务代码
|
||||
│ └── Filament/ # 可选:后台页面/资源
|
||||
├── routes/web.php # 可选:前台路由(boot 时自动加载)
|
||||
├── database/migrations/ # 可选:迁移(migrate 时自动加载)
|
||||
└── views/ # 可选:视图(命名空间 plugin.{vendor}.{name})
|
||||
```
|
||||
|
||||
## plugin.json
|
||||
|
||||
```json
|
||||
{
|
||||
"title": "插件标题",
|
||||
"version": "1.0.0",
|
||||
"description": "插件描述",
|
||||
"author": "作者",
|
||||
"type": "core",
|
||||
"provider": "Plugins\\Vendor\\Name\\ServiceProvider",
|
||||
"requires": ["neatstudio.payment"],
|
||||
"filament_pages": ["Plugins\\Vendor\\Name\\Filament\\Pages\\SettingsPage"],
|
||||
"filament_resources": ["Plugins\\Vendor\\Name\\Filament\\Resources\\OrderResource"]
|
||||
}
|
||||
```
|
||||
|
||||
| 字段 | 说明 |
|
||||
|------|------|
|
||||
| `provider` | 入口类 FQCN;缺省时自动推断 `src/ServiceProvider.php` |
|
||||
| `requires` | 依赖的其他插件(如会员依赖支付),按 `vendor.name` 引用 |
|
||||
| `filament_pages` / `filament_resources` | 注册到后台的页面/资源(由 `PluginPages` 汇总) |
|
||||
|
||||
## ServiceProvider
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Plugins\Vendor\Name;
|
||||
|
||||
use App\Blog\Support\PluginManager;
|
||||
use App\Blog\Support\PluginServiceProvider;
|
||||
|
||||
class ServiceProvider extends PluginServiceProvider
|
||||
{
|
||||
protected function boot(PluginManager $manager): void
|
||||
{
|
||||
// 加载前台路由(可选)
|
||||
$this->loadRoutes(__DIR__.'/../routes/web.php');
|
||||
|
||||
// 注册视图命名空间(可选)
|
||||
$this->loadViews(__DIR__.'/../views', 'plugin.vendor.name');
|
||||
|
||||
// 注册动作/过滤器
|
||||
$manager->addAction('comment.created', function ($comment) { ... }, 10);
|
||||
$manager->addFilter('post.rendered', fn (string $html, $post) => $html, 10);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> 注意:插件入口类**不要**命名为 `PluginServiceProvider`(与基类短名冲突会导致 PHP 声明错误),统一用 `ServiceProvider`。
|
||||
|
||||
## 钩子系统
|
||||
|
||||
### addAction(hook, callback, priority) — 无返回值
|
||||
|
||||
| Hook | 参数 | 用途 |
|
||||
|------|------|------|
|
||||
| `comment.created` | `Comment` | 新评论创建(AI 审核在此监听) |
|
||||
| `payment.paid` | `Payment` | 支付成功(订阅激活/解锁在此监听) |
|
||||
|
||||
### addFilter(hook, callback, priority) — 返回值传给下一个过滤器
|
||||
|
||||
| Hook | 签名 | 用途 |
|
||||
|------|------|------|
|
||||
| `post.rendered` | `(string $html, Post $post): string` | 文章渲染后处理(付费内容过滤) |
|
||||
| `seo.structured_data` | `(array $data): array` | 扩展 JSON-LD 结构化数据 |
|
||||
| `payment.gateway` | `(array $gateways): array` | 注册支付渠道 |
|
||||
|
||||
## 迁移
|
||||
|
||||
插件迁移放在 `database/migrations/`,`app/Providers/AppServiceProvider` 启动时自动注册,`php artisan migrate` 会一并执行(无需手动 --path)。
|
||||
|
||||
## 打包与安装
|
||||
|
||||
- 将插件目录打成 ZIP(根目录含 plugin.json)
|
||||
- 后台「插件管理」→ 上传 ZIP 安装,或配置远程市场 `MARKET_URL`
|
||||
- 内置插件(config/plugins.php enabled 列表)不可卸载,只能停用
|
||||
|
||||
## 异步任务(配合 Workerman)
|
||||
|
||||
实现 `App\Blog\Jobs\AiJob` 接口并在 Workerman 常驻进程执行:
|
||||
|
||||
```php
|
||||
use App\Blog\Jobs\AiJob;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
|
||||
class MyAiJob implements AiJob, ShouldQueue
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
public function __construct(public int $id) {}
|
||||
|
||||
public function handle(\App\Blog\Services\LlmClient $llm): void
|
||||
{
|
||||
// LlmClient 由容器自动注入
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
入队:`dispatch(new MyAiJob($id))->onQueue('ai')`(Workerman 默认消费 `default,ai` 队列)。
|
||||
Reference in New Issue
Block a user