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 Hook | Filter 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_footer、the_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 解決方案。歡迎點擊這裡,填寫表單與我們聯繫,一起把你的想法變成現實!
延伸閱讀
常見問題
WordPress 的 Action Hook 和 Filter Hook 差在哪裡?
為什麼 Filter Hook 沒有寫 return 文章內容就變空白?
如何把 Google Analytics 追蹤碼透過 Hook 加到 WordPress 頁尾?
add_action 和 add_filter 各自對應哪些觸發函式?
為什麼客製化 WordPress 功能要用 Hooks 而不是直接改核心檔案?
訂閱免費電子報
把 AI 自動化、企業系統設計與 WordPress / Laravel 開發的真實案例和可直接照做的技巧,整理成電子報寄給你。只寄精選內容、不灌垃圾信,一鍵就能退訂。