稍有接觸過 WordPress 主題或插件制作修改的朋友,對 WordPress 的Hook機制應該不陌生,但通常剛接觸WordPress Hook 的新手,對其運作原理可能會有點混亂或模糊。本文針對 WordPress Hook 運作大緻做個簡單的說明,而預設讀者是了解基本的 PHP function 文法及運作,但對 WordPress Hook 機制不是很明白。
先從“登場角色”的個别說明開始:
指的是 WordPress 内建的程式碼架構,提供 WordPress 主要的基本功能。
也許你早已聽說,Hook 本身雖是鈎子的意思,但直譯又有點奇怪,是以一般通常都不直譯它,而是直接稱它 Hook 。WordPress 的 Hook 也可以想像成“鈎子”,這些“鈎子”會埋在 WordPress 網站中特定幾處的程式碼中,埋進去時使用的文法,其“标示位置”的意義比較大,沒有實質運作的内容。當程式執行到有埋 Hook 的地方時,它會找出所有對應到自己的 Hook Function (也就是所有“鈎到”該 Hook 的 hook function),并一一執行。
是以若沒有針對此 Hook 去“加入”要鈎上去的 Hook Function,執行到此什麼也不會做。是以,它等于是WordPress核心預留一個執行的機會給未來想要加入定制功能的開發者。
Hook Function 裡會有實質運作的内容,即是實作了一些定制功能,可能是存取 DB、增加 HTML code、執行其他函式等等。我們在 Hook Function 裡寫好所需的功能後,就可以利用“加入至對應 Hook”的文法,把 Hook Function自已鈎到該 Hook 上,使得該 Hook 被執行到時,也會連帶執行自己。
舉個例子,我們拿 wp_head 及 wp_footer 這兩個内建的hook來說明,wp_head 這個 hook 就是用來埋在負責輸出标簽的程式碼中,而 wp_footer 就是用來埋在輸出頁尾的程式碼中 (定義于 wp-includes/general-template.php,用 wp_head() 及 wp_footer() 包裝起來)。這兩個 hook,主要都是在布景檔案中使用的,常見會出現在 header.php 及 footer.php 中。
請看下面的情境示例圖,我們把 wp_head 及 wp_footer 看成是”鈎子“,而别的 hook functions 就能來鈎住它:

我們馬上來寫一個簡單的例子。我們要寫一個 hook function,就叫它 print_sth(),然後把它鈎上 wp_head 這個hook。因為 wp_head() 的内容實際上就隻有 do_action( 'wp_head' ); 這一行内容,而 wp_footer() 的内容也隻有 do_action('wp_footer');是以我們直接把 do_action 的文法換到圖上去,比較容易做說明,是以示意圖變成:
如此,隻要執行到輸出 header.php 時,就會執行到 wp_head(),就如同執行到 do_action( 'wp_head' ); 此時WP核心會去找所有”鈎上”wp_head 這個 hook 的 hook function,於是就找到我們寫的 print_sth() ,然後就執行它,是以結果它做的事就會出現在網站上,也完成了”定制”的動作:
簡單的說,Hook 機制就是:WP 核心或其他插件、主題 提供想定制功能的人一個置入定制程式碼(Hook Function)到特定的執行時間點(Hook)的機會。
WordPress中的 Hook 有兩種,分别是”Action Hook“及”Filter Hook“,我們剛才舉例的 wp_head 及wp_footer 都是屬於 Action Hook。不過,一開始你可以先把這兩種 Hook 看成是一樣的東西,隻是 Filter 多了一點點不同的特色,接着說明。
WP核心 (或主題、插件)在做它們該做的事時,如果執行到有埋 action hook 的程式碼 (即是 do_action 文法) 時,會去找尋對應到的 hook functions,進而執行這些 hook functions(即那些透過 add_action() 來加入的 hook functions),藉此完成定制功能。WP核心并不期待 Action Hook functions 會有回傳值,是以這裡的 hook function 隻被視為一個”獨立切出來運作的功能“。
WP核心做它該做的事,你做你想做的事,做完就各自結束。
跟 Action Hook 一樣,WP核心 (或主題、插件)在做它們該做的事時,如果執行到有埋 filter hook 的程式碼 (即是apply_filters文法) 時,就會去找尋對應的 hook functions ,進而執行這些 hook functions(即那些透過add_filter() 來加入的 hook functions ),藉此完成定制功能。與 Action Hook 不同之處是,所有”鈎上“ Filter Hook 的 hook functions 通常都會接收到參數,而WP核心會期待你拿到它提供的參數,并做完你想做的事後,要回傳(return)一個值,讓WP核心再利用你回傳的值來接着完成它該做的事。
透過你的幹涉,修改了WP核心丢給你的參數,WP核心再接着拿你改過的參數,繼續完成它該做的事,此動作就像”過濾“的動作,因而得名 filter。
比較一下兩種 Hook 在埋進某處程式碼時所用的文法,假設我們在某處 (可能是在輸出頁首的程式碼處,或輸出文章标題、文章内容、側邊欄…等地方,要”出現定制效果“的地方)埋下這兩種 hook:
<a></a>
然後我們可以在某處 (可能是其他插件、functions.php 等處,要”實作定制功能“的地方)添加對應的 hook function:
是以其實兩種 Hook 的運作方式幾乎一樣,隻差在增加 Action Hook 函式不需回傳值,而增加 Filter Hook function時,你必須要回傳一個值。是以 Filter Hook 函式通常都有提供參數,讓想定制的人可以取得它,處理後再回傳。
但如果有一個 Filter Hook,它沒有任何 hook function 有去鈎它,它該怎麼取得回傳值?答案是,直接拿第一個它給的參數,以上面的例子來說,它會直接拿 $a 丢進 $c 。另外,其實我們也可以把 filter 寫的跟 action 一樣,隻要不回傳值就行,但 action hook 就沒辦法”模仿“ filter hook,因為無法取得回傳值。
如果有很多地方(主題或者插件的 functions.php)都 添加同一個 hook ,會怎麼決定出現順序?答案很顯然是可以透過 Hook Function 的 Priority 參數來作優先序的設定:
就像我們剛才說明的例子中,我們使用 add_filter 加入 special_func 時設定的優先序是 10 ,這也是 Priority 參數的預設值。如果你希望它能優先被執行,就設定小于 10 的數字,反之,就設個 100、500 之類的,讓它延後被執行。
但其實這裡有個隐含的沖突問題。
以 wp_head 這個 hook 為例,如果我寫了一個插件,希望透過 wp_head 來輸出”增加 a.css 檔案“的 HTML 文法,而 a.css 會重新設定 body 元素的樣式,是以我希望它可以最後才被彙入,不要被其他 css 檔幹擾,于是我将 Priority 設為 900,但我怎麼知道 Priority 900 夠不夠大?若某個WP網站,它除了安裝我的插件,也安裝了其他插件,而其他插件剛好也重新設定body元素的樣式,然後把 Priority 設為 950,此時我寫的插件在處理 body 樣式時就出事了,于是就跟其他插件沖突了。
是以此時我們需要了解的是:我的WP網站可能裝了很多插件,我怎麼知道同一個 Hook 被加了多少 Hook Function,而每個 Hook Function 的 Priority 被設定為多少?
答案是,我們可以透過 $wp_filters 這個 global 變數來取得所有 hook 的資訊,像是如下的 function:
當我們呼叫 list_hooked_functions('wp_head'); 時,就會列出 wp_head 這個 Hook 所鈎住的所有 hook function,可以看到 priority 10 之後有好幾個都沒有數字,因為它們都沒有特别指定 priority,是以都是 10 ,包括我們剛才寫的 print_sth 也在其中:
>>>>> wp_head 1 wp_enqueue_scripts 2 feed_links 3 feed_links_extra 8 wp_print_styles 9 wp_print_head_scripts 10 rsd_link wlwmanifest_link index_rel_link parent_post_rel_link start_post_rel_link adjacent_posts_rel_link_wp_head locale_stylesheet wp_generator rel_canonical wp_shortlink_wp_head print_sth wp_admin_bar_header _admin_bar_bump_cb
是以,沖突很難提早避免,但發生沖突時,可以預先思考有沒有可能是因為 priority 的設定,導緻結果跟預期不符合。
本文轉自黃聰部落格園部落格,原文連結:http://www.cnblogs.com/huangcong/p/4774220.html,如需轉載請自行聯系原作者