Back to Main Site

挂钩和过滤器参考:完整的开发人员指南

Last updated on Jun 24, 2026 02:01

挂钩和过滤器参考

受众: 开发人员 — 需要 PHP / Laravel 知识。 类别: 技术参考 — 集成开发人员的技术文档。

你将学到什么

  • 了解PolyCMS中的Action vs Filter机制

  • 查找钩子名称、参数和调度位置

  • 注册主题 functions.php 和模块 ServiceProvider 的钩子

  • 使用优先级来控制执行顺序

  • 为每个钩子组应用实际用例

1. Hook系统简介

PolyCMS 使用类似 WordPress 的 Hook/Filter 系统,在 Laravel 上原生构建:

  • Action (Hook::doAction):执行副作用(记录、发送电子邮件、同步数据)。不需要返回值。

  • Filter (Hook::applyFilters):接收一个值,修改它,并且必须返回修改后的值。

基本语法

use App\Facades\Hook;

// Register an Action
Hook::addAction('order_completed', function ($order) {
    Mail::to($order->user)->send(new OrderCompletedMail($order));
}, priority: 10);

// Register a Filter
Hook::addFilter('post.default_image', function (?string $imageUrl, $post) {
    if ($post?->categories->contains('slug', 'news')) {
        return '/images/news-default.jpg';
    }
    return $imageUrl;
}, priority: 10);

2. 内容和帖子

过滤器

参数 描述
post.default_image $imageUrl, $context 帖子没有特色图片时的默认图片
post.frontend_url $url, $post 自定义帖子的公共 URL
post.content.render $html, $post 返回 API 之前过滤帖子 HTML 内容
post.query.builder $query, $request 修改帖子列表的 Eloquent 查询
category.frontend_url $url, $category 自定义类别的公共 URL
content.render.blocks $blocks 渲染前过滤块数组
content.render.html $html, $blocks 过滤最终输出HTML
content.render.block.{type} $html, $block 渲染或覆盖特定块类型

行动

参数 描述
tag.saved $tag, $context 创建/更新标签后触发
tag.deleted $tag, $context 删除标签后触发
category.saved $category, $context 创建/更新类别后触发
category.deleted $category, $context 删除类别后触发

实际用例

UC1 - 特定于类别的默认缩略图: 当帖子没有特色图像时,为每个类别保留特定的默认缩略图:

Hook::addFilter('post.default_image', function (?string $url, $post) {
    if ($post?->categories->contains('slug', 'tech')) return '/images/defaults/tech.jpg';
    if ($post?->categories->contains('slug', 'lifestyle')) return '/images/defaults/lifestyle.jpg';
    return $url; // fallback to admin setting
});

UC2 — Wiki URL 结构: 将帖子 URL 结构从 /posts/slug 降级/更改为 /docs/slug 以实现 wiki 风格的布局:

Hook::addFilter('post.frontend_url', function ($url, $post) {
    return ($post->type === 'wiki') ? '/docs/' . $post->slug : $url;
});

UC3 — 自动插入内嵌广告: 在帖子的第三段后自动插入广告横幅块:

Hook::addFilter('content.render.html', function (string $html) {
    $adBanner = '<div class="ad-inline">Advertisement</div>';
    $parts = explode('</p>', $html, 4);
    if (count($parts) > 3) {
        $parts[2] .= '</p>' . $adBanner;
        return implode('</p>', $parts);
    }
    return $html;
});

3.媒体库

过滤器

参数 描述
media.upload.file $file, $data 处理前修改上传文件
media.upload.data $data, $file 修改上传元数据
media.create.data $mediaData, $file 保存到数据库之前修改媒体记录属性
media.delete.should $shouldDelete,$media 安全门:返回“false”以阻止媒体删除
media.url $url, $media 重写 URL(例如,重定向到 CDN)

行动

参数 描述
media.uploaded $media, $file, $data 上传成功后触发
media.deleting $media 删除前触发
media.deleted $media 删除后触发

实际用例

UC1 — CDN URL 重写: 与 Cloudflare R2 或 Amazon S3 集成,自动将本地存储路径转换为 ​​CDN URL:

Hook::addFilter('media.url', function (string $url, $media) {
    return str_replace('/storage/', 'https://cdn.mysite.com/', $url);
});

UC2 — 保护关键系统资产: 防止意外删除当前用作站点徽标的任何图像:

Hook::addFilter('media.delete.should', function (bool $allow, $media) {
    $logoUrl = get_option('site_logo', null, 'general');
    return ($media->url === $logoUrl) ? false : $allow;
});

UC3 — 上传时自动优化图像: 调度后台队列以从标准上传生成轻量级 WebP 图像:

Hook::addAction('media.uploaded', function ($media, $file) {
    if (str_starts_with($media->mime_type, 'image/')) {
        dispatch(new ConvertToWebpJob($media));
    }
});

4. 电子商务 — 订单和退款

行动

参数 描述
order_status_updated $order, $oldStatus, $newStatus 订单状态变化时触发
order_completed $order 订单成功完成时触发
order.refund.processing $order, $validated 在处理退款之前触发
order.refund.completed $order, $result 退款成功后触发
order.refund.succeeded $order, $result, $validated, $userId API退款成功
order.refund.failed $order, $validated, $exception, $userId API退款失败

过滤器

参数 描述
order.refund.preview.result $preview, $order, $input 修改退款预览数据

实际用例

UC1 — 新订单的电报通知:

Hook::addAction('order_status_updated', function ($order, $old, $new) {
    if ($old === 'pending' && $new === 'processing') {
        TelegramBot::send(" Order #{$order->code} has been confirmed!");
    }
});

UC2 — 订单完成时的忠诚奖励积分:

Hook::addAction('order_completed', function ($order) {
    if ($order->user_id) {
        $points = (int) floor($order->total / 10); // 1 point per $10 spent
        LoyaltyService::addPoints($order->user_id, $points, "Order #{$order->code}");
    }
});

UC3 — 退款失败的审核日志:

Hook::addAction('order.refund.failed', function ($order, $data, $exception, $userId) {
    AuditLog::create([
        'action' => 'refund_failed',
        'order_id' => $order->id,
        'user_id' => $userId,
        'reason' => $exception->getMessage(),
    ]);
});

5. 电子商务 — 购物车、运输、税收、库存

过滤器

参数 描述
cart.totals $totals, $cart 修改购物车总计
shipping.calculate_cost $cost, $method, $cart 覆盖运费
shipping.available_methods $methods, $address, $cart 根据地址和购物车内容过滤运输方式
tax.calculated $result, $subtotal, $address 覆盖计算的税务结果
inventory.is_stockable_product $default, $product, $context 检查产品是否跟踪库存水平
review.can_submit $allowed, $user, $product 安全门:允许用户提交评论?

行动

参数 描述
cart.item.added $item, $cart 将商品添加到购物车后触发
cart.item.updated $item, $oldQty, $newQty 商品数量变化后触发
cart.item.removed $item, $cart 删除项目后触发
cart.cleared $cart 清空购物车后触发
cart.merged $userCart, $guestCart 当访客购物车合并到经过身份验证的用户购物车时触发
review.submitted $review 提交评论后触发
review.approved $review 批准审核后触发
review.rejected $review 拒绝审核后触发

实际用例

UC1 — 订单超过 100 美元免运费:

Hook::addFilter('shipping.calculate_cost', function ($cost, $method, $cart) {
    $subtotal = collect($cart->items)->sum(fn($i) => $i->price * $i->quantity);
    return ($subtotal >= 100) ? 0 : $cost;
});

UC2 — 如果用户未购买产品则阻止评论:

Hook::addFilter('review.can_submit', function (bool $allowed, $user, $product) {
    $hasPurchased = Order::where('user_id', $user->id)
        ->where('status', 'completed')
        ->whereHas('items', fn($q) => $q->where('product_id', $product->id))
        ->exists();
    return $hasPurchased;
});

UC3 — AddToCart 事件的 Facebook 像素跟踪:

Hook::addAction('cart.item.added', function ($item, $cart) {
    session()->push('fb_pixel_events', [
        'event' => 'AddToCart',
        'product_id' => $item->product_id,
        'value' => $item->price,
    ]);
});

6. 电子商务——支付网关

过滤器

参数 描述
payment.gateway.config_schema $schema, $gateway 扩展网关的架构配置字段

实际用例:向银行转账网关添加自定义字段:

Hook::addFilter('payment.gateway.config_schema', function ($schema, $gateway) {
    if ($gateway->code === 'bank_transfer') {
        $schema['branch_code'] = [
            'type' => 'text', 'label' => 'Branch Code', 'required' => false,
        ];
    }
    return $schema;
});

7. 主题和外观

过滤器

参数 描述
theme.view.data $data, $viewName 为任何 Blade 模板注入/修改视图变量
theme.template.resolve $viewName, $templateTheme, $entityType, $entity 覆盖匹配的 Blade 视图
theme.template.registry $templates, $viewType 注册新页面模板
theme.options.values $options 过滤加载的主题选项值
theme.options.css_vars $cssVars, $themeOptionValues 修改自定义 CSS 属性
theme.breadcrumbs.post $breadcrumbs, $post 过滤帖子面包屑
theme.breadcrumbs.product $breadcrumbs, $product 过滤产品面包屑
theme.show_page_header $show, $page 切换页眉的可见性
frontend.topbar.banners $banners 注入顶栏促销横幅
themes.list $themes 过滤管理中可用主题的列表

行动

参数 描述
theme.activated $theme 激活主题时触发
theme.main.changed $theme, $oldMainTheme 更改主题时触发
theme.installing $file 在提取主题 ZIP 之前触发
theme.activating $slug, $type, $mode 在激活主题之前触发
theme.deactivating $slug 在停用主题之前触发
theme.deleting $theme 删除主题前触发
cms_head (无) 布局 <head> 标记内的输出挂钩

实际用例

UC1 — 从模块注入促销横幅:

Hook::addFilter('frontend.topbar.banners', function (array $banners) {
    $banners[] = [
        'text' => ' Flash Sale — 30% Off Today!',
        'url' => '/sale',
        'bg_color' => '#ff4444',
    ];
    return $banners;
});

UC2 — Google Analytics 头部注入:

Hook::addAction('cms_head', function () {
    $ga = get_option('google_analytics_id', null, 'seo');
    if ($ga) {
        echo "<script async src='https://www.googletagmanager.com/gtag/js?id={$ga}'></script>";
    }
});

UC3 — 加载热门帖子侧边栏变量:

Hook::addFilter('theme.view.data', function ($data, $viewName) {
    if ($viewName === 'posts.index') {
        $data['popular_posts'] = Post::orderBy('views', 'desc')->limit(5)->get();
    }
    return $data;
});

8. 设置和配置

过滤器

参数 描述
settings.defaults $defaults, $settingsService 扩展或覆盖基本设置定义
settings.media.drivers $drivers 注册新的媒体存储驱动程序
settings.permalinks.structure $structure, $settingsService 过滤系统永久链接

行动

参数 描述
setting.updating $key, $value, $group, $type 保存设置前触发
settings.saved $payload 设置保存后触发

实际用例

UC1 — 通过模块注册自定义设置部分:

Hook::addFilter('settings.defaults', function ($defaults) {
    $defaults['mymodule'] = [
        'mymodule_api_key' => [
            'key' => 'mymodule_api_key', 'value' => '', 'type' => 'text',
            'label' => 'API Key', 'description' => 'Enter your API key',
        ],
    ];
    return $defaults;
});

UC2 — 清除永久链接上的路由缓存更新:

Hook::addAction('settings.saved', function ($payload) {
    if (($payload['group'] ?? '') === 'permalinks') {
        Artisan::call('route:clear');
        Cache::tags('routes')->flush();
    }
});

9. 用户、角色和身份验证

过滤器

参数 描述
user.resource.to_array $data, $user, $request 扩展用户API资源输出
auth.login.pre_token $response, $user, $request 拦截登录生命周期(例如,用于多重身份验证)

行动

参数 描述
user.creating / user.updating / user.deleting `$user $data`
role.creating / role.updating / role.deleting / role.cloning `$role $data`

实际用例

UC1 — 多重身份验证拦截器:

Hook::addFilter('auth.login.pre_token', function ($response, $user, $request) {
    if ($user->hasRole('admin') && !$request->filled('otp_code')) {
        return response()->json(['requires_2fa' => true, 'user_id' => $user->id], 403);
    }
    return $response; // null = continue token generation
});

UC2 — 用户注册欢迎电子邮件:

Hook::addAction('user.creating', function ($data) {
    dispatch(new SendWelcomeEmail($data['email'], $data['name']));
});

10. 搜索引擎优化

过滤器

参数 描述
seo.canonical_url $url 覆盖规范 URL
seo.site_favicon $iconUrl 覆盖图标路径

实际用例 — 多语言设置的规范 URL:

Hook::addFilter('seo.canonical_url', function (string $url) {
    $locale = app()->getLocale();
    if ($locale !== 'en') {
        return url("/{$locale}" . parse_url($url, PHP_URL_PATH));
    }
    return $url;
});

11. 小部件

过滤器

参数 描述
widget.render.instance $instance 渲染前修改小部件实例设置
widget.render.{widget_type} $widget 修改特定小部件数据
widget.area.render.instances $instances, $area 过滤区域内加载的小部件实例
widget.render.output $html, $instance 过滤单个小部件的 HTML 输出
widget.area.render.output $html, $area 过滤小部件区域的渲染输出
widgets.types $widgets 已注册小部件类型的过滤器列表

行动

参数 描述
widgets.register_types $widgetManager 注册新的小部件类型
widgets.register_areas $widgetManager 注册新的小部件区域

实际用例 — 注册“商店地图”小部件类型:

Hook::addAction('widgets.register_types', function ($manager) {
    $manager->registerType('store_map', [
        'label' => 'Store Map',
        'description' => 'Google Maps showing store locations',
        'fields' => [
            'api_key' => ['type' => 'text', 'label' => 'Google Maps API Key'],
            'lat' => ['type' => 'text', 'label' => 'Latitude'],
            'lng' => ['type' => 'text', 'label' => 'Longitude'],
        ],
        'view' => 'widgets.store-map',
    ]);
});

12. 管理导航和编辑器

过滤器

参数 描述
topbar.menu.items $items, $request, $user 从前端管理栏中添加/删除项目
topbar.menu.should_show $show, $user 切换前端顶部管理栏的可见性
admin.editor.panels $panels, $type, $user 将自定义面板添加到块编辑器侧边栏

行动

参数 描述
admin.menu.build (无) 组装侧边栏导航菜单时触发
topbar.menu.context $request, $user 前端管理栏初始化时触发

实际用例 - 将自定义 SEO 状态菜单项添加到顶栏:

Hook::addFilter('topbar.menu.items', function (array $items, $request, $user) {
    $items[] = [
        'key' => 'seo_score',
        'label' => 'SEO Score',
        'icon' => 'chart-bar',
        'url' => '/admin/seo/score',
        'position' => 50,
    ];
    return $items;
});

13. 模块

过滤器

参数 描述
module.resource.meta $meta, $moduleData 扩展模块元数据详细信息
modules.list $modulesArray 过滤管理中列出的模块
product.query.builder $query, $request 修改产品 Eloquent 列表查询

行动

参数 描述
module.activating $moduleKey, $module 激活模块之前触发
module.deactivating $moduleKey, $module 在停用模块之前触发
module.deleting $moduleKey, $module 删除模块前触发
module.installing $uploadedFile 上传新模块 ZIP 时触发

实际用例 - 在模块激活时自动运行迁移:

Hook::addAction('module.activating', function ($moduleKey, $module) {
    Artisan::call('migrate', [
        '--path' => "modules/Polyx/{$moduleKey}/database/migrations",
        '--force' => true,
    ]);
});

14. 系统引导

行动

参数 描述
roles.register_permissions $permissionRegistry 注册新系统权限
register_email_templates $emailTemplateManager 注册核心电子邮件模板
layout.register_assets $layoutAssetManager 注册自定义管理/前端布局资源
routes.frontend.register (无) 注入自定义前端路由

实际用例 - 模块注册自定义功能/权限:

Hook::addAction('roles.register_permissions', function ($registry) {
    $registry->register('manage analytics', 'Analytics', 'View and manage analytics dashboard');
    $registry->register('export reports', 'Analytics', 'Export analytics reports to CSV');
});

相关文章