WordPress 掛鉤索引
一份可搜尋的索引,收錄開發者真正會用到的 WordPress 動作與篩選器——附上精確的 add_action/add_filter 簽章、觸發時機、可實際運作的範例,以及那個最容易讓人踩雷的地方。
39 個掛鉤,附上確切的 add_action / add_filter 簽章、觸發時機、可實際運作的範例,以及最容易讓人踩雷的地方。 其中有 1 個被標記為未驗證 — 我們尚未對照 WordPress 原始碼核對它們的參數數量,與其把猜測當成事實呈現,我們寧可先把這點標示出來。
這份清單並不詳盡,也無意假裝詳盡 — WordPress 有數以千計的掛鉤。這裡收錄的是大家實際上真正會用到的那些。
在 WordPress 載入完成之後、任何標頭送出之前執行。這是註冊自訂文章類型、分類法與重寫規則的標準位置。
觸發時機
在每一次請求時觸發,無論前台或後台,時機為核心、外掛與佈景主題都載入之後。
簽章
add_action( 'init', 'my_callback' );範例
add_action( 'init', function () {
register_post_type( 'book', array(
'public' => true,
'label' => 'Books',
'show_in_rest' => true, // required for the block editor
) );
} );常見陷阱
init 會在每一次請求時執行,包括 AJAX、REST 與 cron。在這裡做任何耗時的事(一個 HTTP 請求、一個沉重的查詢)都會拖累每一次頁面載入。另外:此時已可取得目前使用者,但你還不能輸出任何內容——標頭雖然尚未送出,卻即將送出。
在佈景主題載入後執行一次。這是使用 add_theme_support()、add_image_size() 以及註冊導覽選單的正確位置。
觸發時機
在佈景主題的 functions.php 載入之後、init 之前。
簽章
add_action( 'after_setup_theme', 'my_callback' );範例
add_action( 'after_setup_theme', function () {
add_theme_support( 'post-thumbnails' );
add_theme_support( 'title-tag' );
add_image_size( 'card', 600, 400, true ); // true = hard crop
} );常見陷阱
在 init 而非這裡註冊圖片尺寸,多數情況下是碰巧能用,但在某些情況下卻會莫名其妙地失敗。請使用 after_setup_theme——它本來就是為此而生。
在所有已啟用的外掛都載入後執行一次。這是與其他外掛互動最早的安全時機。
觸發時機
在每個外掛檔案都被載入之後、佈景主題載入之前。
簽章
add_action( 'plugins_loaded', 'my_callback' );常見陷阱
此時尚無法取得目前使用者——wp_get_current_user() 無法可靠運作。若你需要使用者資料,請改用 init。
在 WordPress 完全載入後執行——外掛、佈景主題、init 與使用者都已就緒。
觸發時機
在 init 之後、且目前使用者設定完成之後。
簽章
add_action( 'wp_loaded', 'my_callback' );在每一次後台請求開始時執行。用於 register_setting()、權限檢查與後台轉址。
觸發時機
在每一次後台端的請求時觸發。
簽章
add_action( 'admin_init', 'my_callback' );常見陷阱
它也會在 admin-ajax.php 請求時觸發,而那些其實並不是「後台畫面」。如果你的回呼函式假設畫面存在,請用 wp_doing_ajax() 加以防護。
載入前台 CSS 與 JavaScript 唯一正確的位置。
觸發時機
在前台頁面載入時、head 渲染之前觸發。
簽章
add_action( 'wp_enqueue_scripts', 'my_callback' );範例
add_action( 'wp_enqueue_scripts', function () {
wp_enqueue_style(
'child-style',
get_stylesheet_uri(),
array( 'parent-style' ), // load AFTER the parent
wp_get_theme()->get( 'Version' ) // cache-bust on version change
);
} );常見陷阱
儘管名稱如此,它同時處理樣式與指令碼——根本沒有 wp_enqueue_styles 這個掛鉤,卻有人為了找它而白白浪費時間。另外:它不會在後台觸發(請用 admin_enqueue_scripts),也不會在區塊編輯器中觸發(請用 enqueue_block_editor_assets)。
在後台載入 CSS/JS。它會接收目前畫面的掛鉤後綴,讓你只在特定某個畫面載入資源。
觸發時機
在後台頁面載入時觸發。
簽章
add_action( 'admin_enqueue_scripts', 'my_callback' ); // receives $hook_suffix範例
add_action( 'admin_enqueue_scripts', function ( $hook ) {
if ( 'settings_page_my-plugin' !== $hook ) {
return; // do not load our JS on every admin screen
}
wp_enqueue_script( 'my-admin', plugins_url( 'admin.js', __FILE__ ), array(), '1.0', true );
} );常見陷阱
沒有針對 $hook 加以判斷,正是外掛破壞其他無關後台畫面最常見的單一原因。只在需要的地方載入你的資源,其餘一律不載入。
只將資源載入到區塊編輯器(Gutenberg)——不含前台,也不含後台的其他部分。
觸發時機
在區塊編輯器載入時觸發。
簽章
add_action( 'enqueue_block_editor_assets', 'my_callback' );將輸出內容印入 <head>。用於 meta 標籤與行內的關鍵 CSS。
觸發時機
在前台的 <head> 內部觸發。
簽章
add_action( 'wp_head', 'my_callback' );常見陷阱
請勿在這裡載入指令碼或樣式——請改用 wp_enqueue_scripts,讓 WordPress 處理相依性與去除重複。直接把 <script> 標籤 echo 進 wp_head 會繞過這一切,這也正是為什麼那麼多網站會載入 jQuery 三次。
在 </body> 之前印出輸出內容。這是放置分析程式碼片段與延後載入標記的正確位置。
觸發時機
在前台頁面的結尾觸發。
簽章
add_action( 'wp_footer', 'my_callback' );常見陷阱
忘記呼叫 wp_footer() 的佈景主題會弄壞管理工具列、弄壞任何載入頁尾指令碼的外掛,並且在 wordpress.org 佈景主題審查中會被直接退件。
在文章內容顯示之前的最後一刻加以篩選。這是為文章前後附加標記的常用位置。
觸發時機
每次呼叫 the_content() 時觸發。
簽章
add_filter( 'the_content', 'my_callback' ); // receives $content範例
add_filter( 'the_content', function ( $content ) {
if ( ! is_singular( 'post' ) || ! in_the_loop() || ! is_main_query() ) {
return $content; // <- the guard everyone forgets
}
return $content . '<p class="cta">Enjoyed this? Read more.</p>';
} );常見陷阱
它執行的頻率遠比你想像的高——在小工具中、在 REST 回應中、在某些外掛產生摘要時,以及在彙整頁的迴圈裡每篇文章各執行一次。若沒有 is_singular/in_the_loop/is_main_query 的防護,你的行動呼籲會在網誌首頁與 RSS feed 中出現十五次。這是 WordPress 中最常被誤用的篩選器。
在顯示之前篩選文章標題。
觸發時機
每次呼叫 the_title() 或 get_the_title() 時觸發。
簽章
add_filter( 'the_title', 'my_callback', 10, 2 ); // receives $title, $post_id常見陷阱
它也會對後台選單、導覽選單以及文件 <title> 中的標題觸發。若不加條件地篩選它,會在你意想不到的地方把東西改名。
設定自動產生的摘要包含多少個「字詞」。預設為 55。
觸發時機
當 WordPress 為沒有手動摘要的文章產生摘要時觸發。
簽章
add_filter( 'excerpt_length', 'my_callback' ); // receives $length (words)範例
add_filter( 'excerpt_length', function ( $length ) {
return 25;
}, 999 ); // high priority: many themes set this too, and last one wins常見陷阱
它對設有「手動摘要」的文章沒有作用——那些摘要會被原封不動地使用。而且許多佈景主題會自行設定這個篩選器,所以你往往需要一個較高的優先順序數字才能勝出。
變更接在被截斷摘要後面的字串。預設為「 […]」。
觸發時機
當自動產生的摘要被截斷時觸發。
簽章
add_filter( 'excerpt_more', 'my_callback' ); // receives $more在查詢執行「之前」修改它。這是變更彙整頁顯示內容的正確做法——遠比另開一個 WP_Query 好得多。
觸發時機
在查詢變數解析完成之後、SQL 建構之前。
簽章
add_action( 'pre_get_posts', 'my_callback' ); // receives WP_Query $query (by reference)範例
add_action( 'pre_get_posts', function ( $query ) {
if ( is_admin() || ! $query->is_main_query() ) {
return; // <- both guards are mandatory
}
if ( $query->is_category() ) {
$query->set( 'posts_per_page', 12 );
}
} );常見陷阱
它在「後台」也會執行,而且會對「每一個」查詢執行,包括選單、小工具與媒體庫。若省略 is_admin() 與 is_main_query() 的防護,你會在不知不覺中改變後台文章列表的顯示內容——這是一個真的很難追查回源頭的 bug。另外請注意:直接修改 $query,不要回傳任何東西。
篩選查詢中原始的 SQL WHERE 子句。
觸發時機
在查詢的 SQL 組建過程中觸發。
簽章
add_filter( 'posts_where', 'my_callback', 10, 2 ); // receives $where, WP_Query $query常見陷阱
你正在撰寫原始 SQL。務必用 $query->is_main_query() 加以防護,並且對任何使用者輸入都務必使用 $wpdb->prepare()。這是把 SQL injection 引入 WordPress 網站最快的途徑。
篩選查詢找到的文章總數——分頁正是依此計算的。
觸發時機
在查詢執行之後、分頁計算之前。
簽章
add_filter( 'found_posts', 'my_callback', 10, 2 ); // receives $found_posts, WP_Query $query設定一個像素門檻,超過此門檻時 WordPress 會將上傳的圖片縮小,並改以「-scaled」副本取代你的原始檔提供。預設為 2560。
觸發時機
在上傳時、當 WordPress 判斷一張圖片是否「過大」的時候觸發。
簽章
add_filter( 'big_image_size_threshold', 'my_callback' ); // receives int $threshold範例
// Serve originals at full resolution — no -scaled copy.
add_filter( 'big_image_size_threshold', '__return_false' );
// Or just raise the ceiling:
add_filter( 'big_image_size_threshold', function () {
return 3840;
} );常見陷阱
這是「我的圖片上傳到 WordPress 後看起來變模糊」最常見的單一原因,而幾乎沒有人知道它的存在。你的原始檔仍在磁碟上——只是永遠不會被提供。請注意它是以「最長邊」為準,而且只影響在此篩選器生效之後才上傳的圖片。
篩選 WordPress 即將為上傳項目產生的圖片尺寸陣列。將某個尺寸 unset 即可停止產生它。
觸發時機
在上傳時、衍生檔案建立之前觸發。
簽章
add_filter( 'intermediate_image_sizes_advanced', 'my_callback', 10, 2 ); // receives $sizes, $metadata範例
add_filter( 'intermediate_image_sizes_advanced', function ( $sizes ) {
unset( $sizes['1536x1536'] );
unset( $sizes['2048x2048'] );
return $sizes;
} );常見陷阱
移除一個你的佈景主題實際上「有在用」的尺寸,會讓 WordPress 回退到全尺寸原始檔——這比你省下的磁碟空間更糟。而且它只會阻止產生「新」檔案;既有的檔案在你重新產生之前仍會保留。
設定 WordPress 重新編碼上傳圖片時所用的 JPEG 品質。預設為 82。
觸發時機
每當 WordPress 寫入 JPEG 時觸發。
簽章
add_filter( 'jpeg_quality', 'my_callback', 10, 2 ); // receives $quality, $context常見陷阱
品質 82 對照片來說沒問題,但對螢幕截圖、標誌與純色扁平圖形而言則明顯偏差——那些圖形有銳利的邊緣,也沒有攝影雜訊可以掩蓋壓縮瑕疵。另外:wp_editor_set_quality 是較新的篩選器,直接涵蓋圖片編輯器類別;兩者一起設定是常見做法。
設定 WP_Image_Editor 類別(GD 與 Imagick)所使用的輸出品質。
觸發時機
當圖片編輯器實例設定其品質時觸發。
簽章
add_filter( 'wp_editor_set_quality', 'my_callback', 10, 2 ); // receives $quality, $mime_type將你的自訂圖片尺寸加入媒體對話框與區塊編輯器中的尺寸下拉選單。
觸發時機
當媒體介面建構其尺寸選擇器時觸發。
簽章
add_filter( 'image_size_names_choose', 'my_callback' ); // receives $sizes範例
add_filter( 'image_size_names_choose', function ( $sizes ) {
return array_merge( $sizes, array( 'card' => __( 'Card', 'textdomain' ) ) );
} );常見陷阱
add_image_size() 會註冊尺寸,但「不會」讓它在編輯器中可供選取。每一則「我的自訂圖片尺寸沒有出現在下拉選單裡」的疑問,都是因為少了這個篩選器。
在檔案被移入上傳資料夾「之前」檢查或拒絕它。
觸發時機
在上傳過程中、檔案寫入之前觸發。
簽章
add_filter( 'wp_handle_upload_prefilter', 'my_callback' ); // receives $file常見陷阱
若要拒絕一個檔案,請將 $file['error'] 設為一段訊息字串並回傳 $file。回傳 false 或拋出例外都不會達到你想要的效果。
在附件處理完成後,篩選其中繼資料陣列(包含已產生的各種尺寸)。
觸發時機
在上傳時衍生圖片建立完成之後觸發。
簽章
add_filter( 'wp_generate_attachment_metadata', 'my_callback', 10, 2 ); // receives $metadata, $attachment_id常見陷阱
這是圖片最佳化外掛所使用的掛鉤。它可能很慢——它會在每一種圖片尺寸寫入之後執行,而在這裡發出 HTTP 請求,會讓每一次上傳都得等它。
篩選 WordPress 為響應式圖片產生的 srcset 候選項目。
觸發時機
當響應式圖片被渲染時觸發。
簽章
add_filter( 'wp_calculate_image_srcset', 'my_callback', 10, 5 );常見陷阱
Removing the medium_large (768w) size elsewhere silently degrades srcset — that size exists almost entirely to serve it.
我們尚未對照 WordPress 原始碼驗證這個掛鉤確切的參數數量。在正式依賴它之前,請先查閱 developer.wordpress.org。與其悄悄把猜測當成事實呈現,我們寧可先標明這份不確定性。
註冊後台選單與子選單頁面。
觸發時機
當後台選單正在建構時觸發。
簽章
add_action( 'admin_menu', 'my_callback' );範例
add_action( 'admin_menu', function () {
add_options_page(
'My Plugin',
'My Plugin',
'manage_options', // capability — NOT a role
'my-plugin',
'my_render_settings_page'
);
} );常見陷阱
capability 這個引數是一種「權限(capability)」,而不是角色。傳入「administrator」看起來能用(因為在某些設定中,管理員剛好有一個同名的權限),卻會在暗中把存取權授予不該有的人。請使用 manage_options。
在後台畫面頂端印出一則通知。
觸發時機
在後台頁面渲染時觸發。
簽章
add_action( 'admin_notices', 'my_callback' );常見陷阱
它會在「每一個」後台畫面觸發。一個在所有畫面上都無條件顯示「感謝安裝!」通知的外掛,正是 WordPress 後台中最惹人厭的單一行為模式。請為它加上條件判斷,並讓它可以關閉。
每當文章被建立或更新時執行。這是儲存自訂欄位框(meta box)資料的常用位置。
觸發時機
在文章寫入資料庫之後觸發。
簽章
add_action( 'save_post', 'my_callback', 10, 3 ); // receives $post_id, $post, $update範例
add_action( 'save_post', function ( $post_id ) {
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;
if ( wp_is_post_revision( $post_id ) ) return;
if ( ! current_user_can( 'edit_post', $post_id ) ) return;
// ... now it is safe to save
}, 10, 1 );常見陷阱
除了真正的儲存之外,它也會在「自動儲存」與「修訂版本」時觸發。若沒有上述三道防護,你的中繼資料每次在編輯器自動儲存時,都會被空值覆寫——這種 bug 看起來就像資料無緣無故消失一樣。
在文章編輯畫面上註冊自訂欄位框(meta box)。
觸發時機
當編輯畫面被建構時觸發。
簽章
add_action( 'add_meta_boxes', 'my_callback', 10, 2 ); // receives $post_type, $post常見陷阱
傳統的自訂欄位框不會出現在區塊編輯器中,除非區塊編輯器回退到相容模式。若是原生使用區塊編輯器的網站,請改以 show_in_rest 註冊文章中繼資料,並改為建構一個側邊欄面板。
在使用者成功登入之後執行。
觸發時機
在驗證成功時觸發。
簽章
add_action( 'wp_login', 'my_callback', 10, 2 ); // receives $user_login, WP_User $user在新使用者建立後立即執行。
觸發時機
在註冊時觸發。
簽章
add_action( 'user_register', 'my_callback', 10, 2 ); // receives $user_id, $userdata篩選驗證結果。回傳一個 WP_Error 即可阻擋登入。
觸發時機
在嘗試登入的過程中觸發。
簽章
add_filter( 'authenticate', 'my_callback', 30, 3 ); // receives $user, $username, $password常見陷阱
優先順序在這裡非常重要。WordPress 核心把自己的檢查掛在優先順序 20 與 30——若掛得太早,你會在密碼都還沒被檢查之前就先執行。
註冊 REST 路由與欄位。
觸發時機
當 REST API 初始化時觸發。
簽章
add_action( 'rest_api_init', 'my_callback' );範例
add_action( 'rest_api_init', function () {
register_rest_route( 'myplugin/v1', '/items', array(
'methods' => 'GET',
'callback' => 'my_get_items',
'permission_callback' => '__return_true', // BE DELIBERATE ABOUT THIS
) );
} );常見陷阱
permission_callback 是「必填」的——自 WP 5.5 起,省略它會拋出一則提示,而把它設為 __return_true 則會讓該端點完全公開。對真正屬於公開的資料而言這沒問題,但對其他任何資料都是嚴重的漏洞。請自行決定,別便宜行事用預設值。
為 wp_schedule_event() 新增自訂的重複執行間隔。
觸發時機
當 WordPress 建構其可用排程清單時觸發。
簽章
add_filter( 'cron_schedules', 'my_callback' ); // receives $schedules範例
add_filter( 'cron_schedules', function ( $schedules ) {
$schedules['every_five_minutes'] = array(
'interval' => 300, // seconds
'display' => __( 'Every 5 minutes', 'textdomain' ),
);
return $schedules;
} );常見陷阱
WP-Cron 並不是真正的 cron。它只在有人造訪網站時才會觸發,所以流量低的網站並不會每五分鐘就執行一次五分鐘排程。如果時間點真的很重要,請停用 WP-Cron(DISABLE_WP_CRON),並改由真正的系統 cron 來呼叫 wp-cron.php。
在留言儲存後立即執行。
觸發時機
在留言送出時觸發。
簽章
add_action( 'comment_post', 'my_callback', 10, 3 ); // receives $comment_id, $approved, $commentdata在留言資料儲存之前加以篩選。用於垃圾留言檢查與驗證。
觸發時機
在留言寫入之前觸發。
簽章
add_filter( 'preprocess_comment', 'my_callback' ); // receives $commentdata常見陷阱
若要在這裡拒絕一則留言,請呼叫帶有訊息的 wp_die()——回傳 false 並不會阻止它。
在結帳成功後的「已收到訂單」頁面上執行。
觸發時機
當顧客抵達感謝頁面時觸發。
簽章
add_action( 'woocommerce_thankyou', 'my_callback' ); // receives $order_id常見陷阱
這「不是」觸發出貨作業的可靠位置。它只有在顧客真的抵達感謝頁面時才會觸發——如果他們付款後就把分頁關掉,它便永遠不會執行。任何非發生不可的事,請改用 woocommerce_payment_complete 或訂單狀態轉換的掛鉤。
在商品頁面上「加入購物車」按鈕的正前方輸出標記。
觸發時機
在商品頁面渲染的過程中觸發。
簽章
add_action( 'woocommerce_before_add_to_cart_button', 'my_callback' );在傳統結帳頁面上新增、移除或重新排序欄位。
觸發時機
當結帳表單被建構時觸發。
簽章
add_filter( 'woocommerce_checkout_fields', 'my_callback' ); // receives $fields常見陷阱
它只會影響「傳統」(短代碼)結帳頁面。較新的區塊式結帳頁面會完全忽略它,改為透過 JavaScript 中的 Slot & Fill 來自訂。這一點幾乎讓每個人第一次都栽跟頭。