# Hook 机制

# Hook 说明

BeikeShop 采用类似 WordPresshook机制, 包括filteraction以及blade。 一般hook会搭配插件Plugin来使用。

在访问 BeikeShop 任意页面的生命周期内,系统提供了一个 hook_filterhook_action 函数, 进行一些额外的操作。 hook_action 用来执行额外的函数,而 hook_filter 则是用来对输出的内容进行处理。 每一个特定的 hook 都有预定义好的名字,如产品详情页的产品数据的hook就叫product.show.data

BeikeShop 在系统初始化的时候,插件可以将自己的处理函数用 add_hook_filteradd_hook_action 注册到特定名称的 hook 上, 等到页面执行到 hook_filter 或者 hook_action 时,就会调用相应的处理函数。

BeikeShop 在很多 hook 位置上都设定了默认的处理函数,如果您发现某处地方需要修改但是没有合适的地方可以注入或修改,可以联系我们或者提交PR。

另外, blade hook 是指可以在插件中修改blade模板, 当然前提是在对应的blade模板中已经定义好了 @hook 或者 @hookwrapper

# Hook 分类

# 1. 数据 Hook: add_hook_filter

  • 系统中对应的埋点方法: hook_filter, 可以不关注此方法。
  • 该 hook 主要用于修改系统中特定方法返回的数据, 且修改后的数据会返回给系统使用, 比如前台产品详情页的数据, 后台顶部导航菜单。 用法实例:
// 首页头部新增一个链接菜单
add_hook_filter('menu.content', function ($data) {
    $data[] = [
        'name' => '新增Google菜单',
        'link' => 'https://www.google.com',
    ];
    return $data;
}, 0);

# 2. 流程 Hook: add_hook_action

  • 系统中对应的埋点方法: hook_action, 可以不关注此方法。
  • 该 hook 主要用于修改流程, 比如订单下单成功后推送到其他 ERP 系统。
add_hook_action('checkout.order.confirm.after', function ($data) {
    dump($data);
    // 这里可以推送到你的 ERP 系统
}, 0);

# 3. 模板 Hook: add_hook_blade

  1. 系统中blade模板嵌入埋点方法: @hook 或者 @hookwrapper/@endhookwrapper, 可以不关注这两个标签。
  2. 该 hook 用于修改 blade 模板, 比如在前台顶部电话前面加一句话如下所示:
  • 在系统中 /themes/default/layout/header.blade.php 中已经预埋 hookwrapper:
<div class="right nav">
    @hookwrapper('header.top.telephone')
    <span class="px-2"><i class="bi bi-telephone-forward me-2"></i> {{ system_setting('base.telephone') }}</span>
    @endhookwrapper
</div>
  • 在你自己的插件中添加以下代码:
add_hook_blade('header.top.telephone', function ($callback, $output, $data) {
    return '电话前' . $output;
});
  • 效果如下: new_plugin

# Hook 命名规则

TIP

模块一般对应类名, 操作是类的方法

# 前台 Filter

  1. Controller: hook_filter(模块.操作.data)
  2. Repository: hook_filter(repo.模块.操作.data)
  3. Service: hook_filter(service.模块.操作.data)

# 前台 Action

  1. Controller: hook_action(模块.操作.before|after)
  2. Repository: hook_action(repo.模块.操作.before|after)
  3. Service: hook_action(service.模块.操作.before|after)

# 前台 Blade

  1. @hook
  • @hook('模块.页面.页面标志.before|after|left|right'), 比如 @hook('product.detail.buy.after')
  1. @hookwrapper
  • @hookwrapper('模块.页面.页面标志'), 比如 @hookwrapper('header.top.currency')

# 后台 Filter|Action|Blade

统一在前台规则前面添加 admin.

# Hook 使用

在插件根目录创建 Bootstrap 类(文件名为Bootstrap.php), 代码如下:

namespace Plugin\你的插件目录名称;

class Bootstrap
{
    public function boot()
    {
        // 这里使用 add_hook_filter、add_hook_action 或者 add_hook_blade 方法修改系统数据、流程或者页面
        // 比如上面的三种hook实例之一
        add_hook_blade('header.top.telephone', function ($callback, $output, $data) {
            return '电话前' . $output . '电话后';
        });
    }
}

# 实例讲解

比如, 我们想在产品的详情页产品名字加个前缀 - 疯狂热销, 步骤如下:

# 1. 新建插件

创建文件夹ProductPrefix, 并创建 config.jsonBootstrap.php 两个文件

new_plugin

插件基本信息 config.json 内容如下,也可以按照你自己的想法修改

{
  "code": "product_prefix",
  "name": "产品名前缀",
  "description": "修改产品详情页产品名称前缀",
  "type": "feature",
  "version": "v1.0.0",
  "icon": "",
  "author": {
    "name": "成都光大网络科技有限公司",
    "email": "yangjin@guangda.work"
  }
}

其中,type表示插件类型,目前系统预定义的类型有8种,分别是:

[
        'payment',    // 支付方式
        'shipping',   // 配送方式
        'theme',      // 主题模板
        'feature',    // 功能模块
        'total',      // 订单金额
        'social',     // 社交网络
        'language',   // 语言翻译
        'translator', // 翻译工具
]

启动文件 Bootstrap.php 内容如下

<?php
/**
 * bootstrap.php
 *
 * @copyright  2022 beikeshop.com - All Rights Reserved
 * @link       https://beikeshop.com
 * @author     Edward Yang <yangjin@guangda.work>
 * @created    2022-07-20 15:35:59
 * @modified   2022-07-20 15:35:59
 */

namespace Plugin\ProductPrefix;

class Bootstrap
{
    public function boot()
    {
        // 通过数据 hook 修改产品详情页产品名称
        add_hook_filter('product.show.data', function ($product) {
            $product['product']['name'] = '[疯狂热销]'. $product['product']['name'];
            return $product;
        });
        
        // 修改产品详情页blade模板, 在立即购买后添加一个按钮
        add_hook_blade('product.detail.buy.after', function ($callback, $output, $data) {
            $view = '<button class="btn btn-dark ms-3 fw-bold"><i class="bi bi-bag-fill me-1"></i>新增按钮</button>';
            return $output . $view;
        });
    }
}

# 2. 进入后台安装并启用插件

依次点击系统设置 - 插件列表 - 安装 - 启用

new_plugin

# 3. 查看产品详情

可以看到,产品名称前面多了 [疯狂热销] 前缀, Buy Now 按钮之后也添加了一个 新增按钮。

new_plugin

这样,我们就在不改变核心代码的情况下修改了产品详情页产品名称以及添加了一个按钮。