WordPress插件開(kāi)發(fā)教程手冊(cè) — 鉤子(Hooks)

本文詳細(xì)介紹了WordPress插件開(kāi)發(fā)中的鉤子(Hooks)機(jī)制,包括Action和Filter的區(qū)別與使用方法。通過(guò)創(chuàng)建回調(diào)函數(shù)并使用add_action或add_filter,開(kāi)發(fā)者可以在特定時(shí)間點(diǎn)添加或修改功能。文章還講解了優(yōu)先級(jí)和參數(shù)個(gè)數(shù)的設(shè)置,幫助開(kāi)發(fā)者更靈活地使用鉤子。適合WordPress主題和插件開(kāi)發(fā)者學(xué)習(xí)參考。

鉤子是用一段代碼添加/修改另外一段代碼的方式,是 WordPress插件和主題與 WordPress 內(nèi)核交互的基礎(chǔ),鉤子在 WordPress 內(nèi)核中也被廣泛使用。WordPress 中有兩種鉤子,Action 和 Filter。使用鉤子時(shí),我們需要先編寫(xiě)一個(gè)自定義函數(shù)作為鉤子的回調(diào)函數(shù),然后使用 add_action 或 add_filter 函數(shù)將我們的回調(diào)函數(shù)掛載到指定的 Action 或 Filter 上。

Action 可以讓我們?cè)诤瘮?shù)執(zhí)行的某個(gè)時(shí)間點(diǎn)添加一些自定義操作(如輸出內(nèi)容到文章尾部),F(xiàn)ilter 和 Action 類(lèi)似,不同的是我們可以通過(guò) Filter 修改并返回?cái)?shù)據(jù),因此,掛載到 Filter 上的函數(shù)會(huì)接受一些變量,并返回修改后的變量。簡(jiǎn)單來(lái)說(shuō),Action 用來(lái)添加功能,F(xiàn)ilter 用來(lái)修改數(shù)據(jù)。

WordPress 內(nèi)核提供了很多鉤子,來(lái)幫助開(kāi)發(fā)者開(kāi)發(fā)WordPress主題或插件。通過(guò)創(chuàng)建自定義鉤子,我們也可以讓第三方開(kāi)發(fā)者添加或修改我們的功能。

WordPress Action  和 Filter 鉤子參考鏈接

Action 鉤子

Action 是 WordPress 的兩種鉤子之一,提供了一種在 WordPress 核心、主題或插件執(zhí)行的特性時(shí)間點(diǎn)運(yùn)行附加函數(shù)的功能。Action 和 Filter 是不一樣的。

添加 Action 的操作

我們可以通過(guò)兩個(gè)步驟添加一個(gè)函數(shù)到某個(gè) Action。首先,我們需要?jiǎng)?chuàng)建一個(gè)回調(diào)函數(shù),這個(gè)函數(shù)在 Action 運(yùn)行時(shí)會(huì)被調(diào)用。其次,我們需要把這個(gè)函數(shù)掛載到對(duì)應(yīng)的 Action 鉤子上面。使用 add_action() 函數(shù),至少需要傳遞兩個(gè)參數(shù) $tag (鉤子名稱(chēng)) 和 $function_to_add (回調(diào)函數(shù)名)。

下面的例子在 init 鉤子執(zhí)行時(shí)運(yùn)行:

function wporg_custom() {
    // 執(zhí)行某些操作
}
add_action('init', 'wporg_custom');

我們可以參考上文獲取可用的鉤子列表。隨著開(kāi)發(fā)經(jīng)驗(yàn)的日益增長(zhǎng),我們可以通過(guò)查看 WordPress 核心、主題或插件的源代碼找到更多合適的鉤子。

其他參數(shù)

add_action() 也可以接受兩個(gè)額外的參數(shù),$priority (整數(shù)) 規(guī)定了回調(diào)函數(shù)執(zhí)行的優(yōu)先級(jí),和 $accepted_args (整數(shù)) 規(guī)定了傳遞給回調(diào)函數(shù)的參數(shù)數(shù)量。

優(yōu)先級(jí)

如果一個(gè)鉤子上面掛載了多個(gè)回調(diào)函數(shù),鉤子就需要一個(gè)優(yōu)先級(jí),來(lái)確定這些回調(diào)函數(shù)的執(zhí)行順序。優(yōu)先級(jí)為整數(shù),默認(rèn)值為 10,數(shù)字越小,優(yōu)先級(jí)就越高。比如,優(yōu)先級(jí)為 11 的函數(shù)將在優(yōu)先級(jí)為 10 的函數(shù)之后執(zhí)行,優(yōu)先級(jí)為 9 的函數(shù)將在優(yōu)先級(jí)為 10 的函數(shù)之前執(zhí)行。

例如,下面的回調(diào)函數(shù)全部掛載到了 init 鉤子上面,但他們有不同的優(yōu)先級(jí)。

add_action('init', 'run_me_early', 9);
add_action('init', 'run_me_normal'); // 如果沒(méi)有指定優(yōu)先級(jí),默認(rèn)為 10
add_action('init', 'run_me_late', 11);

在上面的鉤子運(yùn)行時(shí),第一個(gè)運(yùn)行的函數(shù)是 run_me_early(),run_me_normal(), 最后一個(gè)運(yùn)行的函數(shù) run_me_late()。

參數(shù)個(gè)數(shù)

有時(shí)候,回調(diào)函數(shù)需要接收一些額外的數(shù)據(jù)作為函數(shù)的參數(shù)。例如,當(dāng) WordPress 保存一篇文章時(shí),將會(huì)運(yùn)行 save_post 鉤子,這個(gè)鉤子會(huì)傳遞兩個(gè)參數(shù)給回調(diào)函數(shù):保存的文章 ID 和 文章對(duì)象:

do_action('save_post', $post->ID, $post);

所以,當(dāng)我們掛載函數(shù)到  save_post 鉤子時(shí),我們可以指定它需要接收這兩個(gè)參數(shù):

add_action('save_post', 'wporg_custom', 10, 2);

然后我們就可以在回調(diào)函數(shù)中使用鉤子提供的參數(shù)了。

function wporg_custom($post_id, $post){
    // 執(zhí)行某些操作
}

示例

假設(shè)我們需要在 WordPress 的前端文章查詢(xún)中修改獲取搜索結(jié)果的查詢(xún),我們可以使用 pre_get_posts 鉤子。

function wporg_search($query) {
    if (!is_admin() && $query->is_main_query() && $query->is_search) {
        $query->set('post_type', ['post', 'movie']);
    }
}
add_action('pre_get_posts', 'wporg_search');

Filter 鉤子

Filter 是 WordPress 鉤子兩種類(lèi)型中的另外一個(gè),可以讓我們通過(guò)注冊(cè)到某個(gè) Filter 鉤子上的回調(diào)函數(shù)來(lái)修改某些函數(shù)產(chǎn)生的數(shù)據(jù)。與 Action 不同,F(xiàn)ilter 應(yīng)該以獨(dú)立的方式運(yùn)行,不應(yīng)該有影響全局變量和輸出的副作用。

添加 Filter

我們可以通過(guò)兩個(gè)步驟掛載一個(gè)回調(diào)函數(shù)到某個(gè) Filter 上。首先,我們需要?jiǎng)?chuàng)建一個(gè)回調(diào)函數(shù),這個(gè)函數(shù)在 Action 運(yùn)行時(shí)被調(diào)用。其次,我們需要把這個(gè)函數(shù)掛載到對(duì)應(yīng)的 Action 鉤子上面。

我們可以使用 add_filter() 函數(shù)掛載一個(gè)回調(diào)函數(shù)到 Filter 鉤子上面,add_filter 函數(shù)至少需要兩個(gè)參數(shù):$tag (字符) 和 $function_to_add (回調(diào)函數(shù)名)。下面的例子將在 the_title Filter 執(zhí)行時(shí)運(yùn)行。

function wporg_filter_title($title) {
    return '文章:' . $title . '已被修改。';
}
add_filter('the_title', 'wporg_filter_title');

假設(shè)我們有一篇標(biāo)題為“學(xué)習(xí) WordPress插件開(kāi)發(fā)” 的文章,上面的例子將會(huì)在顯示標(biāo)題時(shí)把標(biāo)題修改為 “文章:學(xué)習(xí) WordPress插件開(kāi)發(fā)已被修改”,我們可以上文獲取可用的鉤子列表。隨著開(kāi)發(fā)經(jīng)驗(yàn)的日益增長(zhǎng),我們可以通過(guò)查看 WordPress 核心、主題或插件的源代碼找到更多有用的鉤子。

其他參數(shù)

add_filter() 也可以接受兩個(gè)額外的參數(shù),$priority (整數(shù)) 規(guī)定了回調(diào)函數(shù)執(zhí)行的優(yōu)先級(jí),和 $accepted_args (整數(shù)) 規(guī)定了傳遞給回調(diào)函數(shù)的參數(shù)數(shù)量。有關(guān)這些參數(shù)的詳細(xì)說(shuō)明,請(qǐng)閱讀關(guān)于 Action 的章節(jié)。

示例

在 <body> 滿足特定條件時(shí),向標(biāo)簽添加 CSS 類(lèi):

function wporg_css_body_class($classes) {
    if (!is_admin()) {
        $classes[] = 'wporg-is-awesome';
    }
    return $classes;
}

add_filter('body_class', 'wporg_css_body_class');

自定義鉤子

一個(gè)非常重要但經(jīng)常被忽略的做法是在我們可以在插件中使用自定義鉤子,以便其他開(kāi)發(fā)者可以擴(kuò)展或修改我們的插件。自定義鉤子的創(chuàng)建和使用方式和 WordPress 核心鉤子相同。

創(chuàng)建一個(gè)自定義鉤子

我們使用 do_action() 為創(chuàng)建 Action 鉤子,使用 apply_filters() 創(chuàng)建 Filter 鉤子。

建議在輸出到瀏覽器的文本上使用 apply_filters(),特別是在前端,這可以方便用戶根據(jù)需求修改插件輸出。

掛載回調(diào)函數(shù)到自定義鉤子

我們使用add_action() 添加回調(diào)函數(shù)到自定義 Action 鉤子上,使用 add_filter() 添加回調(diào)函數(shù)到自定義 Filter 鉤子上。

命名沖突

由于任何主題或插件都可以創(chuàng)建自定義鉤子,為了避免與鉤子名稱(chēng)沖突,我們應(yīng)該在鉤子名稱(chēng)前添加一個(gè)自定義前綴,這一點(diǎn)非常重要。例如,名為 email_body 的 Filter 就非常容易產(chǎn)品沖突,因?yàn)槠渌寮_(kāi)發(fā)人員可能發(fā)會(huì)選擇相同 Filter 名稱(chēng),如果用戶同時(shí)安裝了這兩個(gè)插件,就可能會(huì)導(dǎo)致難以追蹤的錯(cuò)誤。

給 Filter 名稱(chēng)加一個(gè)前綴,如 wporg_email_body(其中 wporg_ 是我們插件的唯一前綴),會(huì)避免和其他插件產(chǎn)生 Filter 名稱(chēng)沖突。

示例

可擴(kuò)展 Action:設(shè)置表單

如果我們的插件添加了一個(gè)設(shè)置表單到 “儀表盤(pán)” 中,我們可以使用自定義 Action 來(lái)允許其他插件開(kāi)發(fā)者添加他們自己的設(shè)置到我們的插件中。

function wporg_settings_page_html()
{
   ?>
    Foo: <input id=foo name=foo type=text>
    Bar: <input id=bar name=bar type=text>
   <?php
   do_action('wporg_after_settings_page_html');
}

如下,另外一個(gè)插件開(kāi)發(fā)者掛載了一個(gè)回調(diào)函數(shù)到 wporg_after_settings_page_html  Action 上面,來(lái)添加新設(shè)置。

function myprefix_add_settings()
{
   ?>
    New 1: <input id=new_setting name=new_settings type=text>
   <?php
}
add_action('wporg_after_settings_page_html', 'myprefix_add_settings');

可擴(kuò)展 Filter:自定義文章類(lèi)型

在下面的例子中,當(dāng)我們注冊(cè)自定義文章類(lèi)型時(shí),把文章類(lèi)型的參數(shù)傳遞給了一個(gè)自定義 Filter,另外一個(gè)插件開(kāi)發(fā)者可以在創(chuàng)建自定義文章類(lèi)型之前修改這個(gè)參數(shù)。

function wporg_create_post_type()
{
   $post_type_params = [/* ... */];

   register_post_type(
      'post_type_slug',
      apply_filters('wporg_post_type_params', $post_type_params)
   );
}

現(xiàn)在,另外一個(gè)插件開(kāi)發(fā)者可以掛載一個(gè)回調(diào)函數(shù)到 wporg_post_type_params Filter 上面,來(lái)修改自定義文章類(lèi)型的參數(shù)。

function myprefix_change_post_type_params($post_type_params)
{
   $post_type_params['hierarchical'] = true;
   return $post_type_params;
}
add_filter('wporg_post_type_params', 'myprefix_change_post_type_params');

外部資源

高級(jí)主題

刪除掛載到 Action 和 Filter 上的回調(diào)函數(shù)

有時(shí)候,我們需要?jiǎng)h除一個(gè)注冊(cè)到一個(gè)插件、主題甚至是 WordPress 核心的鉤子上的回調(diào)函數(shù)。這時(shí),我們可以使用 remove_action() 刪除掛載到 Action 上的回調(diào)函數(shù),使用 remove_filter() 刪除掛載到 Filter 上的回調(diào)函數(shù)。傳遞給 remove_action 和 remove_filter 的參數(shù)應(yīng)該和使用 add_action 和 add_filter 函數(shù)注冊(cè)他們的參數(shù)相同。

要成功刪除回調(diào)函數(shù),必須在注冊(cè)回調(diào)函數(shù)后執(zhí)行刪除操作,執(zhí)行順序很重要。

示例

舉個(gè)例子,我們需要?jiǎng)h除不必要的功能來(lái)提高大型主題的性能。讓我們來(lái)看一下主題代碼的 function.php

function my_theme_setup_slider()
{
   // ...
}
add_action('template_redirect', 'my_theme_setup_slider', 9);

這個(gè)主題的 my_theme_setup_slider 函數(shù)添加了一個(gè)我們不需要的幻燈模塊,這個(gè)模塊會(huì)加載一個(gè)非常大的 CSS 文件,然后初始化一個(gè) JavaScript 文件,這個(gè)文件使用了 1MB 的自定義庫(kù),我們可以通過(guò)卸載這個(gè)功能來(lái)移除這個(gè)幻燈模塊。

由于我們需要在 my_theme_setup_slider 回調(diào)函數(shù)注冊(cè)后 (在 functions.php 中執(zhí)行)卸載這個(gè)函數(shù),執(zhí)行這個(gè)卸載的最好的時(shí)機(jī)就是after_setup_theme鉤子。

function wporg_disable_slider(){
   // make sure all parameters match the add_action() call exactly
   remove_action('template_redirect', 'my_theme_setup_slider', 9);
}
// make sure we call remove_action() after add_action() has been called
add_action('after_setup_theme', 'wporg_disable_slider');

刪除所有回調(diào)

我們可以使用 remove_all_actions() 和 remove_all_filters() 來(lái)刪除掛載到某個(gè)鉤子上面的所有回調(diào)。

確定當(dāng)前鉤子

有時(shí)候,我們需要在多個(gè)鉤子上掛載同一個(gè)回調(diào)函數(shù),在回調(diào)函數(shù)中,我們需要根據(jù)它所掛載到的鉤子來(lái)確定對(duì)應(yīng)的操作。我們可以使用  current_action() / current_filter() 來(lái)確定當(dāng)前的 Action 或 Filter。

function wporg_modify_content($content){
   switch (current_filter()) {
      case 'the_content':
         // do something
         break;
      case 'the_excerpt':
         // do something
         break;
   }
   return $content;
}
add_filter('the_content', 'wporg_modify_content');
add_filter('the_excerpt', 'wporg_modify_content');

檢查鉤子是否已經(jīng)運(yùn)行了

一些鉤子在執(zhí)行過(guò)程中可能會(huì)被多次調(diào)用,但是我們只希望它被調(diào)用一次,在這種情況下,我們可以使用 did_action() 來(lái)檢查鉤子運(yùn)行了多少次。

function wporg_custom(){
   if (did_action('save_post') !== 1) {
      return;
   }
   // ...
}
add_action('save_post', 'wporg_custom');

使用 “全部” 鉤子進(jìn)行調(diào)試

如果我們想要一個(gè)回調(diào)函數(shù)在每一個(gè)鉤子上面都被觸發(fā),我們可以掛載回調(diào)函數(shù)到 ‘a(chǎn)ll’ 鉤子上面。在進(jìn)行調(diào)試時(shí),這個(gè)技巧非常有用,可以幫助我們確定某個(gè)事件在什么時(shí)候發(fā)生,頁(yè)面在什么時(shí)候崩潰等等。

我們提供 WordPress主題和插件定制開(kāi)發(fā)服務(wù)

本站長(zhǎng)期承接 WordPress主題、插件、基于 WooCommerce 的商店商城開(kāi)發(fā)業(yè)務(wù)。 我們有 10 年WordPress開(kāi)發(fā)經(jīng)驗(yàn),如果你想 用WordPress開(kāi)發(fā)網(wǎng)站, 請(qǐng)聯(lián)系微信: iwillhappy1314,或郵箱: [email protected] 咨詢(xún)。

發(fā)表回復(fù)

您的郵箱地址不會(huì)被公開(kāi)。 必填項(xiàng)已用 * 標(biāo)注

*