~/blog/wordpress-action-vs-filter-hooks-deep-dive.md
WordPress 開發與技巧 · 2025 / 08 / 22

Action vs. Filter 徹底解剖:你真的懂 WordPress Hooks 的『執行』與『修改』嗎?

Eric — 浪花科技創辦人 / AI 架構師
Eric
浪花科技創辦人 · AI 架構師
Action vs. Filter 徹底解剖:你真的懂 WordPress Hooks 的『執行』與『修改』嗎?
目錄 table-of-contents.md

WordPress 的兩種 Hook,骨子裡是兩份不同的契約:Action 承諾「在這個時間點執行一件事」——輸出追蹤碼、寄信、寫 log,做完不必回傳任何東西;Filter 則承諾「把這筆資料修改完還回來」——文章內容、標題經你手之後一定要 return 回去,少了這一步,畫面會直接變成空白。搞懂「執行」與「修改」的分工,Hooks 才算真的學會。

因此判斷準則很簡單:想在某個時機「做一件事」就用 Action;想在某筆資料被使用前「改它一下」就用 Filter。以下我會用流水線的比喻、可直接貼進 functions.php 的範例,以及一張對照表,帶你徹底分清楚這兩者,並補上優先權、參數數量等進階用法。

如果你想從一個只會裝外掛、改版型的人,進階到能真正客製化、打造彈性功能的 WordPress 開發者,WordPress Hook 與 Filter 差異與應用就是你非過不可的「新手村最終 Boss」。用錯了,輕則功能沒反應,重則整個網站畫面空白。接下來就用流水線比喻和實際範例,把這兩個靈魂核心徹底解剖。

什麼是 WordPress Hooks?不動核心的客製化魔法

在深入 Action 和 Filter 之前,你得先理解什麼是「Hook(鉤子)」。

想像 WordPress 是一條正在運行的龐大工廠流水線:從初始化、處理請求、查詢資料庫、到最後輸出 HTML 畫面,每個環節都依序進行。而 WordPress 的核心開發者非常聰明,他們在流水線的各個關鍵節點上預留了很多「鉤子」。

這些鉤子就像預留的插座,讓你把自己寫的功能「掛」上去,在特定時間點執行特定任務,或是「攔截」流水線上的零件(資料)來加工。這就是 WordPress 的核心哲學:「Don't Hack the Core」。你不需要修改 WordPress 原始碼,就能透過鉤子擴充或修改它的功能,讓你的客製化程式碼安全地存活在佈景主題的 functions.php 或你自己的外掛裡,就算核心更新了也不會被蓋掉。

而這些鉤子,主要分成兩大類:Action Hooks 和 Filter Hooks。

Action Hooks 是什麼?事件的廣播站(執行某件事)

我喜歡把 Action Hook 形容成一個「廣播站」或「事件觸發器」。它的運作邏輯非常單純:「當某件事發生的時候,請幫我「執行」這些額外的動作。

舉個例子,當 WordPress 準備在頁面最下方輸出結尾的 </body> 標籤之前,它會廣播一下:「嘿!我要結束頁面了喔!」這個廣播的代號就是 wp_footer。你可以寫一個函式,然後用 add_action() 告訴 WordPress:「聽到 wp_footer 這個廣播時,麻煩幫我執行一下我這個函式!」

  • 核心功能:在特定時間點觸發一個或多個函式。
  • 關鍵字:執行(Do)、觸發(Trigger)。
  • 返回值:它不期望你回傳任何東西。你做完事就好,流水線會繼續往下走。

實戰演練:在網站頁尾加入 Google Analytics 追蹤碼

這是最經典的 Action Hook 應用。你總不希望手動去改每個頁面的 footer.php 吧?我們只需要把追蹤碼掛在 wp_footer 這個鉤子上就行。打開佈景主題的 functions.php,加入以下程式碼:

<?php
// 將我們的函式掛到 'wp_footer' 這個 action hook 上
add_action( 'wp_footer', 'roamer_add_ga_tracking_code' );

function roamer_add_ga_tracking_code() {
    // 這段只是示意,請換成你自己的 GA 追蹤碼
    ?>
    <script async src="https://www.googletagmanager.com/gtag/js?id=YOUR_TRACKING_ID"></script>
    <script>
      window.dataLayer = window.dataLayer || [];
      function gtag(){dataLayer.push(arguments);}
      gtag('js', new Date());

      gtag('config', 'YOUR_TRACKING_ID');
    </script>
    <?php
}
?>

看到了嗎?roamer_add_ga_tracking_code 這個函式做的事情就是 echo 出一段 JavaScript,它不需要 return 任何東西。當 WordPress 執行到頁尾時,就會乖乖地把這段程式碼印出來。

Filter Hooks 是什麼?資料的加工廠(修改某個值)

如果說 Action 是廣播站,那 Filter Hook 就是一個「加工廠」或「攔截點」。它的邏輯是:「當我有個資料準備要被使用前,我先把它交給你,看你要不要「修改」它。修改完之後,請務必還給我,我好繼續接下來的工序。

舉個例子,當 WordPress 準備顯示一篇文章內容時,它會先把文章內容(一個長長的字串)通過一個叫做 the_content 的 Filter。你可以用 add_filter() 告訴 WordPress:「嘿!the_content 的資料先別急著印出來,先拿來給我,我要在文章後面加個簽名檔,加完再還你。」

  • 核心功能:接收一個值,對它進行修改,然後回傳它。
  • 關鍵字:修改(Modify)、過濾(Filter)、更改(Change)。
  • 返回值它「必須」回傳一個值!這點超級重要。你把資料拿去加工,最後一定要把成品(即使沒做任何修改,也要把原來的還回去)交回來,不然流水線到你這邊就斷了!

實戰演練:在每篇文章結尾自動加上作者版權宣告

這是一個非常常見的需求,我們可以用 the_content 這個 Filter Hook 輕鬆達成。同樣在 functions.php 中,加入以下程式碼:

<?php
// 將我們的函式掛到 'the_content' 這個 filter hook 上
add_filter( 'the_content', 'roamer_add_signature_to_content' );

function roamer_add_signature_to_content( $content ) {
    // 我們只希望在文章頁面(非首頁、彙整頁)加上簽名檔
    if ( is_single() && in_the_loop() && is_main_query() ) {
        $signature = '<hr><p><em>本文由浪花科技 Eric 撰寫,轉載請註明出處。</em></p>';
        // 將簽名檔附加到原始內容的後面
        return $content . $signature;
    }

    // 如果不是文章頁,務必將原始內容原封不動地回傳!
    return $content;
}
?>

注意到了嗎?我們的函式接收了一個參數 $content,這就是 WordPress 遞過來的原始文章內容。我們加工完(或不加工),最後都一定要 return $content;

如果你忘了這行 return 會發生什麼事?你的文章內容會直接變成空白!這是新手最常踩的坑,沒有之一。忘了 return,資料就石沉大海,畫面直接空白,這種災難一次就夠了。

Action vs. Filter 一張表看懂差異

理論跟實作都講了,我們來做個總結。如果你還是有點模糊,下面這張對照表應該可以幫你釐清所有觀念。

比較項目Action HookFilter Hook
目的執行一個動作(Side Effect),例如發送 email、寫入 log、輸出 HTML修改一筆資料(Data Transformation),例如更改文字、增減陣列元素
參數可以接收參數(例如文章 ID),但主要作為執行動作的參考資訊第一個參數必定是「要被過濾的資料」,後續可有其他參考資訊
回傳值不需要回傳任何值必須回傳修改後(或原始)的資料
掛載函式add_action()add_filter()
觸發函式do_action()apply_filters()
生活化比喻鬧鐘響了(事件發生),你起床刷牙(執行動作)你拿到一杯白開水(原始資料),加入檸檬片(修改),變成檸檬水(回傳修改後的資料)

一個常被忽略的觀念:Action 在底層其實是 Filter 的特例。do_action()apply_filters() 共用同一套掛載機制,差別在於 Action 不在意回傳值、Filter 會把上一個函式的回傳值往下傳遞。理解這點,你就會明白為什麼 Filter「忘了 return」會直接讓資料變成空值。

如何像專家一樣使用 Hooks?三個進階課題

搞懂基本差異,你已經贏過大多數人了。但要成為真正的高手,還需要知道這幾件事。

1. 控制執行順序:優先權(Priority)

add_action()add_filter() 其實還有第三個參數 $priority(優先權),它是一個數字,預設是 10。數字越小,函式越早被執行。

這在多個函式掛在同一個 hook 上時非常重要。例如兩個函式都掛在 wp_footer,一個 priority 是 10、一個是 20,那 priority 10 的會先執行。對 Filter 來說,越早執行的函式,其回傳結果會成為下一個函式的輸入,所以順序會直接影響最終資料。

// 這個會先執行
add_action( 'wp_footer', 'my_first_function', 10 );

// 這個會後執行
add_action( 'wp_footer', 'my_second_function', 20 );

2. 接收更多資訊:參數數量(Accepted Args)

第四個參數是 $accepted_args,預設是 1。它決定你的函式要接收幾個從 hook 傳來的參數。

有些 hook 會提供多個參考資訊。例如 save_post 這個 Action Hook,除了文章 ID,還會傳遞整個文章物件 WP_Post。如果你想用到它,就必須把 $accepted_args 設為 2(或更多)。

// 告訴 WordPress 我的函式要接收 2 個參數
add_action( 'save_post', 'my_save_post_function', 10, 2 );

function my_save_post_function( $post_id, $post ) {
    // 這裡就可以同時使用 $post_id 和 $post 物件了
}

常見陷阱:如果你的函式宣告了第二個參數,卻忘了把 $accepted_args 設成 2,WordPress 只會傳第一個參數進來,第二個參數會是預期外的值,導致難以察覺的 bug。參數的「宣告數量」與「$accepted_args 設定」要一致。

3. 如何尋找可用的 Hooks?工程師的偵探技巧

你可能會問:「Eric,你怎麼知道有 wp_footerthe_content 這些鉤子?」這裡有三條路:

  • 官方文件WordPress Code Reference 是你的好朋友,所有核心 Hooks 都有詳細說明。
  • 直接看原始碼:這最直接,也最硬核。在 WordPress 核心或外掛程式碼中搜尋 do_action(apply_filters(,就能找到所有可用的鉤子。
  • 使用外掛:像 Query Monitor 這種開發者工具,可以幫你列出當前頁面執行了哪些 Hooks,非常方便。

結語:Hooks 是你通往 WordPress 大師的鑰匙

看到這裡,相信你對 WordPress Hook 與 Filter 差異與應用 已經有了非常深刻的理解。它們是 WordPress 最偉大的設計之一,也是整個生態系如此靈活、強大的基石。

記住這個心法:

  • 想在某個時間點「做」一件事,就用 Action
  • 想在某個資料被使用前「改」它一下,就用 Filter

當你不再滿足於現成的外掛,想要打造真正符合需求的客製化功能時,熟練運用 Action 和 Filter 將是你最強大的武器。這不只是寫程式碼,更是一種架構思維的體現。

如果你在 WordPress 開發上遇到更複雜的挑戰,或是有客製化系統、API 串接的需求卻不知該如何下手,浪花科技的團隊擁有多年實戰經驗,能協助你打造高效、穩定且可擴展的 WordPress 解決方案。歡迎點擊這裡,填寫表單與我們聯繫,一起把你的想法變成現實!

延伸閱讀

// FAQ

常見問題

WordPress 的 Action Hook 和 Filter Hook 差在哪裡?
最關鍵的差別在於目的與回傳值。Action 用來在特定時間點「執行」一個動作,例如輸出追蹤碼、寄信、寫 log,不需要回傳任何東西;Filter 用來「修改」一筆即將被使用的資料,例如文章內容或標題,而且一定要把資料 return 回去。想做一件事用 Action,想改一筆資料用 Filter。
為什麼 Filter Hook 沒有寫 return 文章內容就變空白?
Filter 的運作是接收一個值、加工後再回傳,WordPress 會拿這個回傳值繼續後續流程。如果函式沒有 return,等於把資料丟掉了,流水線到這裡就斷掉,畫面因此變成空白。即使不做任何修改,也必須把原始值原封不動地回傳回去。
如何把 Google Analytics 追蹤碼透過 Hook 加到 WordPress 頁尾?
使用 add_action 把自訂函式掛到 wp_footer 這個 Action Hook 上,函式內直接輸出追蹤碼的 script。因為這是 Action,函式只需要把程式碼印出來,不需要回傳任何值,當 WordPress 渲染到頁尾時就會自動執行並印出。這樣就不必手動修改每個頁面的 footer.php。
add_action 和 add_filter 各自對應哪些觸發函式?
add_action 掛載的 Action Hook 由 do_action() 觸發,不在意回傳值;add_filter 掛載的 Filter Hook 由 apply_filters() 觸發,會把上一個函式的回傳值往下傳遞。事實上 Action 在底層是 Filter 的特例,兩者共用同一套掛載機制,差別就在於是否處理回傳值。
為什麼客製化 WordPress 功能要用 Hooks 而不是直接改核心檔案?
Hooks 是 WordPress 「Don't Hack the Core」哲學的實現,讓你不必修改 WordPress 原始碼就能擴充或修改功能。你的自訂程式碼可以安全地放在佈景主題的 functions.php 或自訂外掛中,就算核心更新也不會被覆蓋掉。
~/roamer-tech/newsletter // FREE
// newsletter

訂閱免費電子報

把 AI 自動化、企業系統設計與 WordPress / Laravel 開發的真實案例和可直接照做的技巧,整理成電子報寄給你。只寄精選內容、不灌垃圾信,一鍵就能退訂。

$
// final.exec()

準備好讓你的網站開始為你工作了嗎?