Chuyển tới nội dung chính
Phiên bản: 8.0.0

Hook System

Hệ thống Hook của SkillDo CMS v8 được thiết kế theo mô hình WordPress Hook (Event-driven). Đây là cơ chế cốt lõi cho phép Plugin và Theme mở rộng hoặc thay đổi hành vi của CMS mà không cần sửa code gốc.


1. Hai Loại Hook

LoạiKhi nào dùngTrả về
ActionThực hiện một hành động tại thời điểm nhất địnhKhông (void)
FilterBiến đổi/lọc một giá trị trước khi dùngGiá trị đã được lọc

Quy tắc đơn giản:

  • Cần làm gì đó (gửi mail, thêm class, xóa cache...) → dùng Action
  • Cần thay đổi dữ liệu (sửa nội dung, thêm HTML, lọc mảng...) → dùng Filter

2. Action Hooks

add_action() — Đăng Ký Callback Cho Action

add_action(string $tag, callable $callback, int $priority = 10, int $accepted_args = 1): bool
Tham sốMô tảMặc định
$tagTên event/hookbắt buộc
$callbackHàm sẽ được gọibắt buộc
$priorityThứ tự thực thi (càng nhỏ càng chạy trước)10
$accepted_argsSố tham số mà callback nhận1
// Dạng function đơn giản
add_action('init', function () {
// Chạy khi CMS khởi tạo
});

// Dạng static method
add_action('init', [MyPlugin\Services\TaxonomyService::class, 'register']);

// Dạng instance method
$service = new MyService();
add_action('save_post', [$service, 'onPostSaved']);

// Với priority tùy chỉnh (chạy sau các hook priority 10)
add_action('init', function () {
// Chạy sau các handler có priority 10
}, 20);

// Nhận nhiều tham số từ do_action
add_action('user_created', function ($userId, $userData) {
// xử lý
}, 10, 2); // accepted_args = 2

do_action() — Phát Ra Action Event

Dùng trong code core/plugin để thông báo một sự kiện đã xảy ra:

do_action(string $tag, mixed ...$args): void
// Phát event đơn giản
do_action('my_plugin_loaded');

// Phát event kèm dữ liệu
do_action('order_completed', $orderId);

// Phát event với nhiều dữ liệu
do_action('user_created', $userId, $userData);

has_action() & did_action() — Kiểm Tra Action

// Kiểm tra xem có callback nào đăng ký cho hook chưa
if (has_action('my_plugin_loaded')) {
// có ít nhất 1 callback đăng ký
}

// Kiểm tra action đã được chạy bao nhiêu lần
$count = did_action('init');
if ($count > 0) {
// 'init' đã chạy rồi
}

remove_action() — Hủy Đăng Ký Callback

// Hủy một callback cụ thể (phải đúng priority ban đầu)
remove_action('init', [TaxonomyService::class, 'register'], 10);

// Hủy tất cả callbacks của một action
remove_all_actions('init');

3. Filter Hooks

add_filter() — Đăng Ký Callback Lọc Giá Trị

add_filter(string $tag, callable $callback, int $priority = 10, int $accepted_args = 1): true
// Filter đơn giản — nhận giá trị, trả về giá trị đã sửa
add_filter('the_title', function ($title) {
return strtoupper($title);
});

// Filter với nhiều tham số
add_filter('get_post_thumbnail', function ($imgHtml, $postId, $size) {
// Thêm class vào ảnh
return str_replace('<img', '<img class="post-thumb"', $imgHtml);
}, 10, 3); // accepted_args = 3

// Filter trong Plugin
add_filter('products_list_query', function ($query) {
$query->where('status', 'active');
return $query;
});

apply_filters() — Áp Dụng Filter Lên Giá Trị

Dùng trong code core/plugin để cho phép bên ngoài lọc một giá trị:

apply_filters(string $tag, mixed $value, mixed ...$args): mixed
// Cơ bản
$title = apply_filters('the_title', $post->title);

// Truyền thêm tham số để filter có thể dùng
$imgHtml = apply_filters('get_post_thumbnail', $imgHtml, $post->id, 'medium');

// Trong Model hoặc Service
$items = apply_filters('my_plugin_product_list', $products, $categoryId);

has_filter() — Kiểm Tra Filter

if (has_filter('the_title')) {
// Có filter nào đó đang lọc the_title
}

remove_filter() — Hủy Đăng Ký Filter

remove_filter('the_title', 'my_custom_title_function', 10);
remove_all_filters('the_title');

4. Tạo Hook Riêng Trong Plugin

Nếu Plugin của bạn muốn cho phép các Plugin/Theme khác mở rộng, bạn cần tự tạo hook ở những điểm thích hợp:

<?php
namespace MyPlugin\Services;

class ProductService
{
public function getProducts(array $filters = []): array
{
// Cho phép các plugin khác sửa đổi $filters trước khi query
$filters = apply_filters('my_plugin_product_filters', $filters);

$products = Product::where($filters)->get();

// Cho phép các plugin khác sửa đổi kết quả sau khi query
$products = apply_filters('my_plugin_products_result', $products, $filters);

return $products;
}

public function createProduct(array $data): int
{
// Action hook trước khi tạo
do_action('my_plugin_before_create_product', $data);

$id = Product::create($data);

// Action hook sau khi tạo (truyền id luôn)
do_action('my_plugin_after_create_product', $id, $data);

return $id;
}
}

Plugin khác có thể hook vào:

// Thêm điều kiện lọc sản phẩm
add_filter('my_plugin_product_filters', function ($filters) {
$filters['featured'] = 1;
return $filters;
});

// Gửi notification sau khi tạo sản phẩm
add_action('my_plugin_after_create_product', function ($productId, $data) {
// Gửi email notification
\Mail::send('admin@site.com', 'Sản phẩm mới: ' . $data['title']);
}, 10, 2);

5. Priority — Thứ Tự Thực Hiện

  • Priority mặc định là 10
  • Số nhỏ hơn → chạy trước
  • Số lớn hơn → chạy sau
  • Nhiều callback cùng priority → chạy theo thứ tự đăng ký
add_action('init', function () {
echo 'Chạy thứ 2'; // priority 10 (mặc định)
});

add_action('init', function () {
echo 'Chạy đầu tiên'; // priority 1
}, 1);

add_action('init', function () {
echo 'Chạy cuối'; // priority 99
}, 99);

6. Các Hook Quan Trọng CMS Cung Cấp Sẵn

Action Hooks Hệ Thống

HookKhi nào phát raTham số
cms_loadedCMS Loader đã load xong các thành phần cơ bản.
plugins_loadedTất cả Plugin đang active đã load xong ServiceProvider.
initCMS Controller khởi tạo xong (lúc bắt đầu vòng đời request).
admin_initHệ thống khởi tạo riêng cho khu vực Admin backend.
theme_init / client_initHệ thống khởi tạo riêng cho Theme frontend.
readyCMS Controller đã sẵn sàng thực thi logic trang hiện tại.
user_registerKhi một User mới đăng ký/tạo thành công.$userId
profile_updateKhi thông tin User được cập nhật.$userId
deleted_userKhi User bị xóa khỏi hệ thống.$user
set_user_roleKhi User được gán một role mới.$userId, $role, $userRole
update_{$name}_optionCập nhật một Option vào bảng system ($name là key option).$option, $name, $value
admin_{$module}_table_column_{$name}Dùng trong quản trị admin để in thêm HTML ra 1 cột trong bảng.$item

Filter Hooks Hệ Thống

HookMô tảTham số
the_contentLọc nội dung bài viết trước khi xuất ra view (VD: replace shortcode).$content
get_urlLọc URL (dùng cho đa ngôn ngữ hoặc rewrite rule).$slug
get_imgLọc HTML thẻ <img> của helper SkillDo\Cms\Support\Image.$html, $params
get_img_linkLọc URL ảnh của helper Image.$link, $params
cms_logoLọc/đổi logo của CMS Admin.$logoPath
user_has_cap / role_has_capLọc/thay đổi kết quả check quyền capability.$capabilities, $cap, $role
post_detail_view / post_index_viewLọc/đổi template view render cho trang chi tiết/danh sách bài viết.$view, $object
admin_table_object_form_searchThêm/Sửa các input trên thanh filter/search của bảng Admin.$form

7. Hook Trong Plugin — Ví Dụ Khởi Động

<?php
namespace MyPlugin\Providers;

use SkillDo\ServiceProvider;
use MyPlugin\Services\MyTaxonomyService;

class MyPluginServiceProvider extends ServiceProvider
{
public function boot(): void
{
// Đăng ký Taxonomy ở hook 'init'
add_action('init', [MyTaxonomyService::class, 'register']);

// Ghi log sau khi CMS tải xong plugin
add_action('plugins_loaded', function () {
\Log::info('MyPlugin đã sẵn sàng chạy');
});

// Lọc nội dung bài viết để thêm text
add_filter('the_content', function ($content) {
$text = '<p class="my-plugin-copyright">Nội dung đã được đăng ký bản quyền</p>';
return $content . $text;
});

// Đổi logo ở Admin backend
add_filter('cms_logo', function ($logo) {
return asset('my-plugin::images/my-custom-logo.png');
});
}
}