本篇文章更新時間:2023/04/06
如有資訊過時或語誤之處,歡迎使用 Contact 功能通知。
一介資男的 LINE 社群開站囉!歡迎入群聊聊~
如果本站內容對你有幫助,歡迎使用 BFX Pay 加密貨幣新台幣 贊助支持。


前面一章節的 [WordPress] 外掛開發安全性指南 – 上架外掛前必須通過的考驗 關於安全性的部分如果已經有深刻概念後。接下來就是了解 WordPress 精華設計的架構: Hooks 勾點 啦!

絕對可以說是這個設計,把整個社群給串連起來。不管是外掛還是佈景主題的開發,也不會錯過他的。

Hook 勾點

「Hook」(以下稱「勾點」),是一種讓程式碼在特定的預定義位置互相作用/修改的方式。它們是外掛和佈景主題與 WordPress 核心互動的基礎,而且 WordPress 核心本身也廣泛使用它們。

有兩種類型的勾點:「Actions」事件動作 和「Filters」事件過濾器。使用其中一種,你需要撰寫自訂函式稱為「回呼函式(Callback)」,然後將它註冊到 WordPress 勾點 以供特定的「Action」或「Filter」使用。

「Actions」允許你新增資料或更改 WordPress 的運作方式。Actions 將在 WordPress 核心、外掛和佈景主題執行的特定時間點運行。Action 的 Callback 函式可以執行某些任務,例如向使用者顯示輸出或將某些東西插入資料庫,但是它們不會回傳任何東西給呼叫的 Action 勾點。

「Filters」讓你有能力在 WordPress 核心、外掛和佈景主題執行期間更改資料。Filters 的 Callback 函式會接受一個變數,修改它,然後返回它。它們應以隔離的方式工作,不應該有副作用(例如影響全域變數和輸出)。Filters 是希望有東西回傳回來(或者說「過濾資料」)的勾點。

WordPress 提供了許多勾點,你可以使用它們,但你也可以創建自己的勾點,以便其他開發人員可以擴展和修改你的外掛或佈景主題。

Actions 事件動作 vs. Filters 事件過濾器

動作(Action)和過濾器(Filter)的主要區別可以總結為以下兩點:

  • 動作接收到的資訊,執行相對應的操作後不返回任何內容,換句話說,它會對某些事物進行操作並離開,不會返回任何結果給呼叫的勾點(hook)。
  • 過濾器則是接收到資訊,對其進行修改後返回。換句話說,它會對某些事物進行過濾並將其返回到勾點供後續使用。

另一種解釋:

  • 「動作」會中斷程式碼的執行流程,執行某些操作後再回到正常的流程,而不對任何事物進行修改;
  • 「過濾器」則是用於以特定方式修改某些事物,以便後續的程式碼使用。

勾點中會定義透過參數代入的「某些資訊」。更多細節請參閱後續章節。

其他資源

Actions 事件動作

Actions(事件動作) 是其中一種勾點行為。它們提供了一種在 WordPress 核心、外掛和主題的執行過程中並於特定點運行函式的方法。動作的回呼函式不會向呼叫的事件勾點回傳任何內容。它們是過濾器(Filters)的對應部分。以下是動作和過濾器之間差異的回顧。

新增一個事件動作(Actions)的勾點

兩個步驟新增一個事件動作:

建立一個回呼函式(Callback)方法

首先,建立一個『回呼函式』。當掛勾的動作到位執行時,此函式將會被一起呼叫執行。

回呼函式就像一個普通的函式:應該有前綴,而且應該被放置於 functions.php 或其他可被呼叫的位置。它應該接收的參數也由你掛勾的動作所定義;大多數的掛勾都應明確定義,因此請參閱勾點相關文件,以查看你所選擇的動作會傳遞哪些參數到函式中使用。

指派回呼函式到指定的勾點

其次,將回呼函式新增到動作中。這稱為「掛勾」,告訴系統在運行到該事件時要呼叫你定義的回呼函式。

當回呼函式準備好時,使用 add_action() 將其掛勾到所選動作。最少需要兩個參數:

  1. string $hook_name,即你要掛勾的動作名稱;
  2. callable $callback,即你的回呼函式名稱。

以下示範執行 init 勾子時執行 wporg_callback()

function wporg_callback() {
    // do something
}
add_action( 'init', 'wporg_callback' );

你可以參考本章節後段內容以獲得更多可用的勾點列表資訊。

以經驗來說,瀏覽 WordPress Core 核心原始碼將有助於你找到最適合的勾點。

附加的參數

add_action() 函式可以接受兩個附加參數,int $priority 用於指定回呼函式的優先順序,int $accepted_args 用於指定傳遞給回呼函式的引數數目。

Priority 執行勾點事件的優先順序(權重)

單一事件可以掛勾多個回呼函式(callback functions)。例如,init ,使用這個「初始化」勾子的事件非常多。然而,有時候你可能需要確保你的回呼函式在其他回呼函式之前或之後執行,即使那些函式還沒被掛勾。

WordPress 根據兩個方式來決定回呼函式的執行順序:第一種方式是通過手動設置 Priority(優先級)。這可以使用 add_action() 的第三個參數來完成。

以下是一些重要的資訊:

  • 優先級是正整數,通常介於 1 到 20 之間。
  • 預設優先級(即,當未指定提供 priority 參數值時分配的優先級)為 10。
  • 優先級值理論沒有上限,但現實上限制為 100。

如果回呼函式的優先級是 11,則它將在優先級為10的函式之後運行; 如果回呼函式的優先級是 9,則它將在優先級為10的函式之前運行。

回呼函式順序的第二種方式,就是它們在相同優先級值中註冊的順序。因此,如果兩個回呼函式使用相同的優先級值註冊到相同的勾子上,它們將按照被註冊到勾子上的順序運行。

例如下列回呼函式都是註冊在 init 勾子上,但優先順序不同:

add_action('init', 'wporg_callback_run_me_late', 11);
add_action('init', 'wporg_callback_run_me_normal');
add_action('init', 'wporg_callback_run_me_early', 9);
add_action('init', 'wporg_callback_run_me_later', 11);

在上面的例子中:

  • 首先執行的函式是 wporg_call_backrun_me_early(),因為它手動設定了優先級為 9。
  • 接著執行 wporg_callback_run_me_normal(),因為它沒有設定優先級,所以優先級為 10。
  • 接下來執行 wporg_callback_run_me_late(),因為它手動設定了優先級為 11。
  • 最後執行 wporg_callback_run_me_later(),雖然它的優先級也是 11,但是它是在 wporg_callback_run_me_late() 之後才勾上的。
參數

有時候希望回呼函式(callback function)可以接收與動作相關的額外資料。

例如,當 WordPress 儲存一篇文章並執行 save_post 勾子時,它會向回呼函式傳遞兩個參數:當前儲存事件發生的文章 ID 和文章物件本身。

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

當一個回呼函式註冊 save_post 勾子的時候,它可以指定想要接收這兩個參數。透過使用 add_action 方法來實現,在本例中是透過將 2 放入第四個參數中完成:

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

為了在你的回呼函式中可以接收到這些參數,請修改你回呼函式中接受傳入的參數,像這樣:

function wporg_custom( $post_id, $post ) {
    // do something
}

將回呼函式的參數名稱設置成與原傳遞的參數相同,或盡可能一樣,是一種良好的開發習慣。

Filters 事件過濾器

Filters(事件過濾器) 是一種勾點的類型。

過濾器提供一種功能,能夠在 WordPress Core 核心、外掛和主題的程式執行過程中修改資料。它與 Action 事件動作相對應。

與事件動作不同的是,過濾器旨在以獨立的方式工作,並且不應該具有像影響全域變數和輸出等「副作用」(side effects)的作用。過濾器會期望有資料回傳給它們。

新增事件過濾

新增過濾器的過程包含兩個步驟。

首先,你需要建立一個回呼函式,在過濾器運行時會被呼叫。其次,你需要將該回呼函式加入到一個勾子中,以執行呼叫該函式的動作。

你將使用 add_filter() 函式,傳遞至少兩個參數:

  1. string $hook_name 表示你要勾住的過濾器名稱,
  2. callable $callback 表示你的回呼函式名稱。

以下範例將在執行 the_title 過濾器時執行。

function wporg_filter_title( $title ) {
    return 'The ' . $title . ' was filtered';
}
add_filter( 'the_title', 'wporg_filter_title' );

假設我們有一個文章標題為「Learning WordPress」,上述的例子將會修改它成為「The Learning WordPress was filtered」。

你可以參考 Hook 勾點章節中提供的可用勾子

隨著你經驗的增加,查詢 WordPress 核心原始碼將有幫助你找到最適合的勾子。

附加的參數

add_filter() 函式可以接受兩個附加的參數。int $priority 用於指定回呼函式的優先級(權重),int $accepted_args 用於指定即將傳遞给回呼函式的參數數量。

針對這兩個參數的解釋,可以參考前述事件動作。

範例

當滿足某個條件時,將一個定義好 CSS 的 Class 新增到 body 標籤中:

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

客製化勾子

一個重要但常常被忽略的做法是在你的外掛中使用自訂勾子,以便其他開發人員可以擴展和修改它。

客製化勾子的創建和呼叫方式與 WordPress 核心中的勾子相同。

建立

若要建立自訂勾子的掛載點,請使用 do_action() 來製作 Actions 事件動作,並使用 apply_filters() 來製作 Filters 事件過濾器。

給勾子新增一個回呼函式

若要將回呼函式新增到客製化勾子上,請使用 add_action() 新增 Actions 事件動作呼叫,使用 add_filter() 新增 Filters 事件過濾器呼叫。

命名衝突

由於任何外掛都可以建立自訂勾子,因此為了避免與其他外掛之間發生衝突,重要的是要為你的勾子名稱加上前綴。

例如,一個名為 email_body 的過濾器就不太實用,因為很可能會有另一個開發者選擇相同的名稱。如果使用者安裝了兩個外掛,這可能導致難以追踪的錯誤。

將函式命名為 wporg_email_body(其中 wporg_ 是你的外掛的唯一前綴)將可以避免任何衝突。

範例

可延伸的事件動作:設定表單

如果你的外掛程式在管理後台中新增了一個設定表單,你可以使用 Action 事件動作來允許其他外掛程式在其上新增自己的設定。

    Foo:
    Bar:
   

現在另一個外掛程式可以註冊一個回呼函式至 wporg_after_settings_page_html 勾子 (hook),並加入新的設定:

    New 1:
    
可延伸的事件過濾器: Custom Post Type 客製化內容類型

在這個範例中,當註冊新的內容類型時,定義它的參數會經過一個過濾器(Filter)傳遞,這樣其他外掛就可以在文章類型建立之前對其進行修改。

現在另一個外掛可以註冊 wporg_post_type_params 勾子的回呼函式,並更改文章類型的參數:

外部資源

進階主題

移除 Actions 事件動作與 Filters 事件過濾器

有時候你想要從其他外掛、主題,甚至是 WordPress Core 註冊的勾子中刪除一個回呼函式。

要從勾子中刪除回呼函式,你需要呼叫 remove_action()remove_filter() 方法,具體取決於回呼函式是作為 Action 事件動作還是 Filter 事件過濾器加入的。

傳遞給 remove_action()/remove_filter() 的參數必須與註冊它的 add_action() / add_filter() 的參數相同,否則刪除將不會生效。

注意:要成功刪除回呼函式,你必須在回呼函式註冊之後執行刪除。執行順序很重要。

範例

假設我們想移除不必要的功能來改善一個大型佈景主題的效能。

透過檢視 functions.php,讓我們分析此佈景主題的程式碼。

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

wporg_setup_slider 函式加入了一個我們不需要的輪播圖,這可能會載入一個不小的 CSS 文件,然後附帶使用客製化開發的 JavaScript 初始化文件。我們可以嘗試去除它。

由於我們希望在 WordPress 的 wporg_setup_slider 回呼函式註冊(functions.php 執行)之後勾住 WordPress,我們最好的機會是使用 [after_setup_theme](https://developer.wordpress.org/reference/hooks/after_setup_theme/) 勾子。

function wporg_disable_slider() {
    // 確保所有參數與當初 add_action() 呼叫時完全一樣。
    remove_action( 'template_redirect', 'wporg_setup_slider', 9 );
}
// 確保我們在呼叫 add_action() 後再來呼叫 remove_action()。
add_action( 'after_setup_theme', 'wporg_disable_slider' );

移除全部回呼函式

你也可以使用 remove_all_actions() / remove_all_filters() 方法來移除與某個勾子相關聯的所有回呼函式。

判斷當前的勾子

有時你希望在多個勾子上執行事件動作或過濾器,但基於當前呼叫它的勾子的不同行為而有所不同。

你可以使用 current_action() / current_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' );

確認勾子執行次數

某些勾子在執行過程中會被多次呼叫,但你可能只想讓回呼函式運行一次。

在這種情況下,你可以使用 did_action() 檢查勾子被呼叫的次數。

function wporg_custom() {
   // If save_post has been run more than once, skip the rest of the code.
   if ( did_action( 'save_post' ) !== 1 ) {
      return;
   }
   // ...
}
add_action( 'save_post', 'wporg_custom' );

除錯「全部」的勾子

如果你想要一個回呼函式在每個勾子上都觸發,你可以註冊 all 這個勾子。這在除錯情境下很有用,可以幫助確定特定事件何時發生或網頁何時出現嚴重錯誤。

function wporg_debug() {
    echo '

' . current_action() . '

'; } add_action( 'all', 'wporg_debug' );

Share:

作者: Chun

資訊愛好人士。主張「人人都該為了偷懶而進步」。期許自己成為斜槓到變進度條 100% 的年輕人。[///////////____36%_________]

參與討論

6 則留言

  1. 自動引用通知: [WordPress] 強迫登出使用者的方法 – WP_Session_Tokens – 一介資男
  2. 自動引用通知: [WooCommerce] 給商品增加客製化分類選項的方法 – 一介資男
  3. 自動引用通知: [WooCommerce] 客製化新商品類型,實現開發特殊購物網站的方法 – 一介資男
  4. 自動引用通知: [WooCommerce] 移除或取代內建預設事件的方法 – 一介資男
  5. 自動引用通知: [WooCommerce] 數位商品結帳收到款項後能不能直接把訂單狀態改完成? – 一介資男
  6. 自動引用通知: [WooCommerce] 客製化已出貨訂單狀態顧客通知信的方法 – 一介資男

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *


文章
Filter
Apply Filters
Mastodon