Back to Main Site

Tài liệu tham khảo toàn tập về Hooks & Filters trong PolyCMS

Last updated on Jul 10, 2026 3:31 AM

Tổng quan

PolyCMS cung cấp hệ thống Hook và Filter được lấy cảm hứng từ WordPress, cho phép các nhà phát triển mở rộng tính năng của hệ thống mà không cần can thiệp hay sửa đổi trực tiếp các file mã nguồn cốt lõi của mô-đun. Đây chính là nền tảng cốt lõi phục vụ việc tự xây dựng plugin tùy biến và thiết lập các giao diện theme riêng.

Hệ thống có hai loại điểm neo (hooks):

  • Actions (Hành động) — Thực thi một đoạn mã tùy biến tại các mốc thời gian cụ thể của hệ thống (ví dụ: gửi mail ngay sau khi bài viết được lưu thành công).
  • Filters (Bộ lọc) — Chỉnh sửa hoặc biến đổi dữ liệu trước khi dữ liệu được sử dụng hoặc ghi vào database (ví dụ: thay đổi tiêu đề bài viết trước khi render hiển thị ra màn hình).

Các hàm API cốt lõi

Đăng ký một Action

polycms_add_action(string $hook, callable $callback, int $priority = 10, int $args = 1);

Giải thích tham số:

  • $hook — Tên gọi của action hook hệ thống.
  • $callback — Hàm hoặc phương thức sẽ được gọi thực thi.
  • $priority — Thứ tự ưu tiên thực thi (số càng nhỏ sẽ chạy càng sớm). Giá trị mặc định: 10.
  • $args — Số lượng tham số truyền vào hàm callback. Giá trị mặc định: 1.

Ví dụ mẫu:

// Tự động gửi tin nhắn thông báo Slack ngay khi xuất bản bài viết mới
polycms_add_action('polycms_post_published', function($post) {
    $message = "New post published: {$post->title}";
    send_slack_notification($message);
}, 10, 1);

Đăng ký một Filter

polycms_add_filter(string $hook, callable $callback, int $priority = 10, int $args = 1);

Các hàm callback của Filter **bắt buộc phải trả về (return)** giá trị sau khi đã xử lý biến đổi.

Ví dụ mẫu:

// Tự động chèn thêm ghi chú bản quyền ở cuối mỗi bài viết
polycms_add_filter('polycms_post_content', function($content) {
    return $content . '<p class="disclaimer"><em>Bài viết thuộc bản quyền của tác giả.</em></p>';
}, 20, 1);

Cách kích hoạt các điểm neo

// Kích hoạt một Action
polycms_do_action(string $hook, ...$args);

// Thực thi một Filter
$value = polycms_apply_filters(string $hook, $value, ...$args);

Tài liệu danh sách đầy đủ các Hooks hệ thống

Vòng đời của Bài viết (Post Lifecycle Actions)

Tên HookThời điểm kích hoạtCác tham số truyền vào
polycms_post_saveTrước khi bản ghi bài viết được lưu vào cơ sở dữ liệu$data (mảng dữ liệu)
polycms_post_savedSau khi lưu bài viết thành công$post (đối tượng bài viết)
polycms_post_publishedKhi trạng thái bài viết chuyển sang xuất bản (published)$post (đối tượng bài viết)
polycms_post_deleteTrước khi bài viết bị xóa khỏi hệ thống$post_id (ID bài viết)
polycms_post_deletedSau khi bài viết đã được xóa thành công$post_id (ID bài viết)
polycms_post_status_changedKhi trạng thái bài viết thay đổi$post, $old_status, $new_status

Vòng đời của Trang tĩnh (Page Lifecycle Actions)

Tên HookThời điểm kích hoạtCác tham số truyền vào
polycms_page_savedSau khi lưu trang tĩnh thành công$page (đối tượng trang)
polycms_page_deletedSau khi xóa trang tĩnh thành công$page_id (ID trang)

Các hoạt động về Bình luận (Comment Actions)

Tên HookThời điểm kích hoạtCác tham số truyền vào
polycms_comment_submittedKhi độc giả vừa gửi một bình luận mới$comment (đối tượng bình luận)
polycms_comment_approvedKhi bình luận được duyệt hiển thị$comment (đối tượng bình luận)
polycms_comment_deletedKhi bình luận bị xóa khỏi hệ thống$comment_id (ID bình luận)

Hiển thị và kết xuất giao diện (Frontend Rendering Actions)

Tên HookThời điểm kích hoạtCác tham số truyền vào
polycms_headNằm bên trong thẻ mở <head> của trang ngoàiKhông có
polycms_footerNằm ngay trước thẻ đóng </body> của trang ngoàiKhông có
polycms_frontend_initKhi controller frontend khởi động thiết lập ban đầuKhông có
polycms_before_render_postTrước khi kết xuất giao diện chi tiết một bài viết$post (đối tượng bài viết)
polycms_after_render_postSau khi kết xuất giao diện bài viết xong$post, $output (mã HTML đầu ra)
polycms_after_render_homepageSau khi kết xuất giao diện trang chủ blog$output (mã HTML đầu ra)
polycms_admin_bar_actionsHỗ trợ chèn các nút thao tác tùy biến trên thanh admin bar ngoài trang chủKhông có

Bộ lọc nội dung (Content Filters)

Tên FilterĐối tượng tác độngTham số truyền vàoKết quả trả về kỳ vọng
polycms_post_contentToàn bộ nội dung văn bản chi tiết bài viết$content (chuỗi HTML)Nội dung sau khi đã chỉnh sửa
polycms_post_titleTiêu đề bài viết$title (chuỗi tiêu đề)Tiêu đề sau khi đã chỉnh sửa
polycms_post_excerptNội dung mô tả ngắn bài viết$excerpt (chuỗi mô tả)Mô tả sau khi đã chỉnh sửa
polycms_page_contentToàn bộ nội dung chi tiết trang tĩnh$content (chuỗi HTML)Nội dung trang sau khi chỉnh sửa
polycms_post_metaThông tin siêu dữ liệu bài viết$meta (mảng meta)Mảng dữ liệu sau khi sửa đổi

Bộ lọc tối ưu hóa SEO (SEO Filters)

Tên FilterĐối tượng tác độngTham số đầu vào
polycms_meta_titleThẻ tiêu đề meta cuối cùng (meta title tag)$title (chuỗi tiêu đề)
polycms_meta_descriptionThẻ mô tả meta (meta description)$description (chuỗi mô tả)
polycms_og_tagsMảng chứa các thẻ định dạng Open Graph (Facebook)$tags (mảng tag)
polycms_twitter_tagsMảng chứa các thẻ định dạng Twitter Cards$tags (mảng tag)

Hoạt động Plugin & Theme (Plugin & Theme Actions)

Tên HookThời điểm kích hoạtCác tham số truyền vào
polycms_plugin_activatedKhi một plugin được kích hoạt thành công$plugin_slug (Mã định danh plugin)
polycms_plugin_deactivatedKhi một plugin bị tạm tắt thành công$plugin_slug (Mã định danh plugin)
polycms_theme_switchedKhi thay đổi giao diện hoạt động của blog$new_theme, $old_theme (Tên giao diện mới và cũ)

Các ví dụ lập trình thực tế

Ví dụ 1: Tự động trích xuất nội dung ngắn (Auto-Excerpt)

polycms_add_filter('polycms_post_excerpt', function($excerpt) {
    if (empty($excerpt)) {
        $CI = &get_instance();
        $content = $CI->load->get_var('post')->content ?? '';
        return mb_substr(strip_tags($content), 0, 160) . '...';
    }
    return $excerpt;
});

Ví dụ 2: Nhúng mã đo lường Google Tag Manager

polycms_add_action('polycms_head', function() {
    $gtm_id = get_option('polycms_gtm_id');
    if ($gtm_id) {
        echo "<script>(function(w,d,s,l,i){...})(window,document,'script','dataLayer','{$gtm_id}');</script>";
    }
});

Ví dụ 3: Giới hạn quyền đọc bài viết riêng tư cho nhân viên

polycms_add_filter('polycms_post_content', function($content) {
    $CI = &get_instance();
    $post = $CI->load->get_var('post');
    
    if ($post->visibility === 'private' && !is_staff_logged_in()) {
        return '<div class="restricted"><p>Nội dung này chỉ dành riêng cho các thành viên quản trị.</p></div>';
    }
    return $content;
});

Các nguyên tắc phát triển cần lưu ý

  1. Luôn khai báo tham số độ ưu tiên để chủ động điều phối thứ tự chạy code của bạn. Độ ưu tiên mặc định là 10.
  2. Filter bắt buộc phải trả về giá trị — việc bỏ quên lệnh return sẽ làm mất chuỗi truyền tải dữ liệu và gây lỗi hiển thị.
  3. Sử dụng các tên hàm có tính phân loại cao (như thêm tiền tố riêng) hoặc sử dụng hàm nặc danh (closures) để tránh lỗi trùng lặp tên hàm giữa các plugin.
  4. Không thay đổi trạng thái toàn cục khi đang xử lý filter — chỉ nên tập trung xử lý biến đổi dữ liệu đầu vào và trả về kết quả.

Tài liệu hướng dẫn liên quan