Action vs. Filter 大亂鬥?資深工程師帶你拆解 WordPress Hooks 底層邏輯,別再搞混了!

2025/08/22 | WP 開發技巧

Action vs. Filter 大亂鬥?資深工程師帶你拆解 WordPress Hooks 底層邏輯,別再搞混了!

嗨,我是浪花科技的資深工程師 Eric。在 WordPress 的世界裡打滾了這麼多年,我看過無數開發者,從新手到老手,都會在一個核心觀念上卡關,那就是 WordPress 的 Hooks 系統,特別是 add_actionadd_filter 這對看似兄弟、實則性格迥異的函式。很多人會說:「啊不就都掛鉤子嗎?能動就好啦!」

唉,這就是典型的工程師壞習慣——「能動就好」。這種心態在初期或許能讓你快速解決問題,但長遠來看,混用 Action 和 Filter 不僅會讓你的程式碼難以維護,更可能埋下難以察覺的效能地雷或邏輯錯誤。今天,就讓我這個老骨頭帶你深入底層,徹底搞懂這兩者的差異,讓你從「會用」晉升到「精通」,寫出更優雅、更健壯的 WordPress 程式碼。

WordPress Hooks 到底是什麼?一個生活化的比喻

在我們深入技術細節前,先來個比喻吧。你可以把 WordPress 核心想像成一棟已經蓋好的房子,裡面有完整的電力系統。而 Hooks 就像是牆上預留的「插座」。

  • Action Hooks (動作掛鉤):像是「電源開關」。當你按下開關(例如:文章發佈了),它會觸發一個事件,通知所有連接到這個開關的電器(你的函式)開始運作。例如,按下開關後,電燈亮了、音響響了。它們各自完成自己的任務,但不會互相影響,也不會改變「按下開關」這個事件本身。
  • Filter Hooks (過濾器掛鉤):則像是「變壓器」或「濾水器」。電流(資料)流過它時,它會對電流進行加工處理(例如:把 220V 降為 110V),然後再把處理過的電流傳遞下去。它接收一個東西,處理完後,再把「處理過的」東西交出去。如果這個濾水器壞了(忘了回傳處理後的水),那下一關就沒水可用了。

有了這個基本概念,我們就來拆解這兩個函式的真正面貌吧。

add_action:WordPress 事件的觸發器——「去做某件事,別回報!」

Action 的核心精神在於「執行」。當 WordPress 運行到某個特定的時間點(例如 wp_headsave_postinit),它會大喊一聲:「嘿!現在是『儲存文章』時間點了,有沒有人要在這個時候做點什麼?」

這時候,所有透過 add_action('save_post', 'your_function_name'); 掛載的函式就會依照順序被觸發執行。這些函式是「獨立」的,它們的目的不是要修改傳入的資料,而是要執行一個「副作用 (Side Effect)」。

所謂的副作用,就是指函式執行後對外部世界產生的影響,例如:

  • 發送一封 Email 通知。
  • 將資料寫入 Log 檔。
  • 呼叫一個外部 API。
  • 更新另一個資料庫欄位。

它們的共同點是:完成任務就結束了,不需要「回報」任何東西給 WordPress 核心。

實戰範例:在文章儲存後自動發送 LINE 通知

想像一下,我們希望編輯每次更新文章時,就自動發送一個通知到公司的 LINE 群組。這就是一個典型的「動作」,我們不是要修改文章內容,而是要觸發一個外部行為。


<?php
/**
 * 當文章儲存時,觸發 LINE Notify 通知
 * 
 * @param int     $post_id 文章 ID
 * @param WP_Post $post    文章物件
 * @param bool    $update  是否為更新文章
 */
function eric_send_line_notification_on_save($post_id, $post, $update) {
    // 防止自動儲存或修訂版本觸發
    if (wp_is_post_revision($post_id) || wp_is_post_autosave($post_id)) {
        return;
    }

    // 確保是我們想要的文章類型,例如 'post'
    if ($post->post_type !== 'post') {
        return;
    }

    // 這裡只是示意,請替換成你自己的 LINE Notify 邏輯
    $token = 'YOUR_LINE_NOTIFY_TOKEN';
    $message = '文章已更新:' . get_the_title($post_id) . ' 連結:' . get_permalink($post_id);

    $args = [
        'headers' => [
            'Authorization' => 'Bearer ' . $token,
        ],
        'body' => [
            'message' => $message,
        ],
    ];

    wp_remote_post('https://notify-api.line.me/api/notify', $args);
}

// 將我們的函式掛載到 'save_post' 這個 action hook 上
// 優先權設為 10,並接收 3 個參數
add_action('save_post', 'eric_send_line_notification_on_save', 10, 3);

?>

在這個例子中,eric_send_line_notification_on_save 函式執行了 wp_remote_post 來呼叫外部 API,它沒有回傳任何東西,完美詮釋了 Action 的精神。

add_filter:WordPress 資料的加工廠——「把東西給我,我改完再還你!」

Filter 的核心精神在於「修改」與「回傳」。當 WordPress 準備要輸出一筆資料時(例如文章標題、內容、摘要),它會先把這筆資料透過 Filter 傳遞出去,像是在問:「嘿!這是我準備要顯示的文章標題,有沒有人想在最後一刻對它做點什麼手腳?」

所有透過 add_filter('the_title', 'your_function_name'); 掛載的函式會像一條生產線一樣,依序接收這筆資料,對它進行加工,然後「必須」把加工後的結果回傳(return)出去,交給下一個函式處理。如果中間有任何一個環節忘了回傳,那這筆資料在這條生產線上就斷了,最終輸出的結果可能就是空的,甚至導致網站出錯。

`return` 是 Filter 的靈魂!

這點我要特別囉嗦一下,因為這是新手最常犯的錯。在 Filter 函式中,忘記 `return` 就等於謀殺了那筆資料。你的函式接收了一個參數(例如 $title),你對它做了一些處理,最後一定要 return $title;。就算你沒有做任何處理,也要原封不動地把原始資料 return 回去,否則下一個掛在同一個 Filter 上的函式就收不到東西了。

實戰範例:在文章標題前自動加上「獨家報導:」

假設我們想讓所有文章的標題在顯示時,前面都自動加上一個固定的前綴,這就是一個典型的「修改資料」的場景。


<?php
/**
 * 過濾文章標題,在前面加上前綴
 * 
 * @param string $title 原始文章標題
 * @param int    $id    文章 ID
 * @return string 修改後的文章標題
 */
function eric_add_prefix_to_title($title, $id) {
    // 只在主要查詢的單篇文章頁面中作用,避免影響選單、後台等地方的標題
    if (is_singular('post') && in_the_loop() && is_main_query()) {
        return '【獨家報導】' . $title;
    }

    // 對於其他情況,務必原封不動地回傳原始標題!
    return $title;
}

// 將我們的函式掛載到 'the_title' 這個 filter hook 上
// 優先權設為 10,並接收 2 個參數
add_filter('the_title', 'eric_add_prefix_to_title', 10, 2);

?>

看到了嗎?這個函式的結尾無論如何都有一個 return。這就是 Filter 的標準作業流程 (SOP),接收、處理、回傳,缺一不可。

Action vs. Filter 終極對決:一張表格讓你秒懂

講了這麼多,我們來做個總整理,讓你一眼看穿兩者的核心差異。

比較項目 add_action (動作) add_filter (過濾器)
核心目的 在特定時間點「執行」一個或多個函式。 在資料傳遞過程中「修改」資料。
回傳值 不需要。函式執行完就結束了。 必須有。一定要回傳處理後(或未處理)的資料。
函式參數 通常是事件相關的上下文資訊(如 $post_id, $user_id)。 第一個參數必定是要被過濾的資料本身(如 $content, $title)。
應用場景 寄送 Email、註冊腳本 (wp_enqueue_scripts)、註冊文章類型 (init)。 修改文章內容 (the_content)、改變摘要長度 (excerpt_length)、自訂 Body Class (body_class)。
常見錯誤 嘗試在 Action 中修改資料並期待它生效(並不會)。 忘記 return,導致資料消失,網站畫面空白或出錯。

工程師的囉嗦時間:如何找到可用的 Hooks?

好的,現在你懂了 Action 和 Filter 的差別,下一個問題就是:「我怎麼知道 WordPress 在哪些地方安插了這些『插座』?」

  1. 官方文件是你的聖經WordPress 開發者中心的 Hooks 列表 是你最好的朋友。雖然是英文,但裡面詳細列出了所有 Action 和 Filter,以及它們的作用和參數。
  2. 善用偵錯外掛:像是 Query Monitor 這種神器,可以在頁面載入時告訴你當前頁面觸發了哪些 Hooks,以及有哪些函式掛載在上面。這對於理解主題或外掛的運作流程非常有幫助。
  3. 直接看原始碼:這是最硬核但也是最根本的方法。直接在 WordPress 核心檔案中搜尋 do_action(apply_filters(,你就能找到所有可用的掛鉤點。這也是我最推薦的方式,因為它能讓你真正理解 WordPress 的底層運作邏輯。

總結:掌握 Hooks,解鎖 WordPress 的無限可能

總結一下今天的重點:

  • Action 是「執行者」:在特定時間點做事,不求回報。
  • Filter 是「加工者」:接收資料、修改它,然後務必交還回去。

搞懂這兩者的分野,是從 WordPress 小白邁向專業開發者的關鍵一步。它能讓你用最乾淨、最有效率、最符合 WordPress 精神的方式去客製化網站,而不是到處亂改核心檔案或外掛程式碼,造成日後更新的災難。

希望這次的深度拆解對你有幫助。別再把 Action 和 Filter 搞混了,現在就打開你的 functions.php,開始用正確的方式來施展你的 WordPress 黑魔法吧!

延伸閱讀

需要更深入的 WordPress 客製化開發嗎?

如果你覺得這篇文章對你有幫助,但你在專案中遇到了更複雜、更棘手的問題,無論是效能調校、API 串接,還是高難度的客製化功能開發,都歡迎隨時與我們浪花科技的團隊聊聊。我們專注於提供企業級的 WordPress 解決方案,樂於為你打造穩定、高效且具擴展性的網站系統。
→ 立即填寫表單,與我們的技術顧問免費諮詢

常見問題 (FAQ)

Q1: add_actionadd_filter 最根本的差別是什麼?

最根本的差別在於「目的」和「回傳值」。add_action 的目的是在特定時間點「執行一個動作」(例如寄信、寫入資料庫),它不需要回傳任何東西。而 add_filter 的目的是「修改一筆資料」(例如文章標題、內容),它「必須」將修改後(或未修改)的資料回傳出去,否則會中斷資料鏈,導致錯誤。

Q2: 我在 add_filter 的函式中忘了加 return 會發生什麼事?

這是一個嚴重的錯誤。如果你的 filter 函式沒有回傳值,PHP 會預設回傳 NULL。這意味著傳遞到下一個 filter 或最終要輸出的資料會變成空的。在前端,你可能會看到文章標題或內容消失;在後端,這可能導致功能異常甚至網站出現「死亡白畫面」(White Screen of Death)。

Q3: 我怎麼知道一個外掛或主題用了哪些 hooks?

有幾種方法:第一是查閱該外掛或主題的官方文件。第二是使用像 Query Monitor 這類的開發者工具,它能列出當前頁面所有執行的 hooks。第三,也是最直接的方法,就是閱讀它的原始碼,搜尋關鍵字 do_actionapply_filters,就能找到所有它提供給開發者客製化的掛鉤點。

 
立即諮詢,索取免費1年網站保固