當前位置:首頁>WordPress建站>WordPress開發(fā)>WordPress 插件開發(fā)教程 Part 3 – 鉤子( Hooks )

WordPress 插件開發(fā)教程 Part 3 – 鉤子( Hooks )

本節(jié)內容

  • 為動作鉤子創(chuàng)建動作
  • 為過濾器鉤子創(chuàng)建過濾器
  • 使用 PHP 類里面的鉤子
  • 為插件添加自定義鉤子
  • 尋找 WordPress 中的鉤子

鉤子是 WordPress 的精髓。他們允許插件開發(fā)人員鉤進 WordPress 工作流程內部來改變它的工作,而不用直接修改核心代碼。這就使得用戶可以方便的升級到 WordPress 的新版本而不需要修改一行代碼。

如果一個開發(fā)人員修改了核心代碼,這些改動在 WordPress 下一次升級的時候就會消失。升級會覆蓋這些改動。使用鉤子讓你能夠在核心以外的目錄中單獨開發(fā)插件,這就在升級時保證了插件代碼的安全。

沒有鉤子,插件就沒辦法改變 WordPress 的功能了。本節(jié)介紹的鉤子系統(tǒng)會貫穿整個教程,同時也會在幾乎每一個插件的開發(fā)中用到。在你學會了鉤子的用法后,你就會明白為什么 WordPress 這個平臺這么強大,并有上千個插件供幾百萬用戶使用了。

WordPress 主要有兩種類型的鉤子:動作鉤子和過濾器鉤子(action hooks and filter hooks )。第一個使得你可以在一個特定時刻上執(zhí)行一個函數(shù),第二個使得你可以操作通過鉤子的輸出。

鉤子不是僅僅針對插件的。WordPress 內部也使用鉤子。如果你瀏覽核心代碼,你就能見到很多 WordPress 自己鉤自己的例子了。

動作鉤子 ( actions )

動作鉤子讓你可以在 WordPress 加載過程中或者當某個事件發(fā)生的特定時刻觸發(fā)一個函數(shù)。例如:你可能希望當 WordPress 第一次加載一個頁面或者保存一篇文章時執(zhí)行一個函數(shù)。

你需要理解 do_action() 函數(shù)。當鉤進 WordPress 中時,你的插件不會直接調用這個函數(shù);但是你的插件幾乎都會間接的使用它。

<?php
  do_action( $tag, $arg = '' );
?>
  • $tag — 動作鉤子的名稱
  • $arg — 傳遞給已注冊的動作的值。它看起來像一個單獨的參數(shù),但通常都不是這樣的。動作鉤子可以傳遞任何個數(shù)的參數(shù),或者根本不傳參數(shù)。對特殊的鉤子,你需要查看 WordPress 的源碼,因為參數(shù)個數(shù)在每個鉤子的基礎改變。

下面是一個具有多參數(shù)的動作鉤子的例子:

<?php
  do_action( $tag, $arg_1, $arg_2, $arg_3 );
?>

下面看看一個叫做 wp_head 的鉤子是怎么出現(xiàn)在 WordPress 中的。這個鉤子出現(xiàn)在前臺的 <head> 里面。 WordPress 和插件經常用這個鉤子來添加 meta 信息,樣式表,和 js 腳本。

<?php
  do_action('wp_head');
?>

當這段代碼在 WordPress 中執(zhí)行時,它會尋找任何為 wp_head 動作鉤子注冊的動作。然后按照特殊順序執(zhí)行它們。如你所見,它名叫 wp_head 但是沒有傳遞額外的參數(shù)。動作鉤子通常都這樣。下面是有兩個額外參數(shù)的動作鉤子的例子:

<?php
  do_action( 'save_post', $post_ID, $post );
?>

這個 save_post 的鉤子傳遞兩個參數(shù),一個 $post_ID,一個 $post。

什么是動作?

從技術上講,一個動作就是一個 PHP 函數(shù)。一個函數(shù)要成為一個動作,它需要被注冊成一個動作鉤子。在上面的部分可以看到什么是動作鉤子,但是動作鉤子要用作任何目的,需要有個動作為它們注冊。這就是插件的來源。你開發(fā)的自定義的函數(shù)(動作)當動作鉤子出發(fā)之后就可以執(zhí)行一個特定任務了。要實現(xiàn)這個,就要使用 add_action() 函數(shù)。

<?php
add_action( $tag, $function, $priority, $accepted_args );
?>
  • $tag – 你的函數(shù)執(zhí)行時代動作鉤子的名稱。
  • $function – WordPress 要調用的函數(shù)名。
  • $priority – 一個表示動作調用順序的整數(shù),默認是10。數(shù)字越小,這個函數(shù)越早被調用。
  • $accepted_args – 動作鉤子要傳遞給你的函數(shù)的參數(shù)個數(shù)。默認只有一個參數(shù)。

動作鉤子并不局限于單個動作。你的插件可以將多個函數(shù)添加到一個動作鉤子上。其他插件,甚至是 WordPress 核心,經常將多個函數(shù)添加到同一個鉤子上。

現(xiàn)在是使用動作鉤子的時候了。一個常見的動作鉤子是 wp_footer 。它提供給前端用戶的 WordPress 模板使用。通常它剛好在</body>前調用。在下面的例子中,將要為 wp_footer 注冊一個動作并添加一條自定義信息到 footer。

<?php
add_action( 'wp_footer', 'boj_example_footer_message', 100 );
function boj_example_footer_message() {
    echo "基于 <a href="https://wordpress.org" >WordPress </a>架設。;
}
?>

仔細看看上面的代碼中如何使用 add_action() 函數(shù)的。

<?php
add_action( 'wp_footer', 'boj_example_footer_message', 100 );
?>

第一個參數(shù)是鉤子的名字( wp_footer )。第二個參數(shù)是要回調的函數(shù) ( boj_example_footer_message )。第三個參數(shù)是優(yōu)先級 ( 100 )。這個函數(shù)比起其他鉤到 wp_footer 中的函數(shù),會在比較靠后的次序執(zhí)行。如果設置成1,就較先執(zhí)行。

要說明,鉤子可能會因為許多原因在 WordPress 執(zhí)行過程中多次觸發(fā)。任何添加到這個鉤子中的動作每當鉤子觸發(fā)時都會執(zhí)行一次。

動作鉤子函數(shù)

你已經知道了最基本的兩個動作鉤子函數(shù)怎么使用;do_action() 和 add_action()。WordPress 還有其他類型的與動作鉤子相關的函數(shù)用于插件開發(fā)。

do_action_ref_array

do_action_ref_array() 函數(shù)和 do_action() 函數(shù)完成同樣的工作,只不過參數(shù)傳遞的方式不同。它并不傳遞通過附加參數(shù)的值來確定的多個參數(shù),而是傳遞一個包含參數(shù)的數(shù)組。這個參數(shù)數(shù)組也是一個必須的參數(shù)。這個函數(shù)的目的是通過引用傳遞一個對象給添加到特定鉤子的動作(函數(shù))。這意味著這個函數(shù)可以不用返回就改變對象本身。

<?php
do_action_ref_arrray( $tag, $args );
?>
  • $tag – 動作鉤子的名字。
  • $args – 要傳遞給注冊到這個鉤子的函數(shù)的參數(shù)的數(shù)組。通常,這是一個動作可以改變的對象。

下面看一個 WordPress 如何調用 do_action_ref_array() 的實例。下面的代碼展示了 pre_get_posts 動作鉤子。WordPress 在從數(shù)據(jù)庫取得 posts 之前執(zhí)行這個鉤子,使得插件可以改變查詢 posts 的方式。

<?php
do_action_ref_array( 'pre_get_posts', array( & $this ) );
?>

第一個參數(shù) pre_get_posts 是鉤子的名字。第二個參數(shù)是從數(shù)據(jù)庫中查詢 posts 的參數(shù)的數(shù)組。這個鉤子使你可以執(zhí)行基于那個參數(shù)數(shù)組的代碼。

假如你想安裝隨機的順序來得到首頁的 blog,而不是默認的通過發(fā)布時間來得到。你就需要注冊一個動作到這個鉤子,并改變排序順序。

<?php
add_action( 'pre_get_posts', 'boj_randomly_order_blog_posts' );
function boj_randomly_order_blog_posts( $query ) {
    if( $query -> is_home && empty( $query -> query_vars['suppress_filters']))
        $query -> set( 'rderby', 'rand' );
}
?>
remove_action

remove_action() 可以刪除先前添加到一個鉤子的動作。代表性的,你可以刪除 WordPress 默認添加的動作。要刪除一個動作,這個動作必須已經用 add_action() 函數(shù)添加了。如果你在動作注冊之前執(zhí)行 remove_action(),那么動作并不會被從鉤子中刪除。

如果動作被成功刪除,則函數(shù)返回 true,否則返回 false。

<?php
remove_action( $tag, $function_to_remove, $priority, $accepted_args );
?>

參數(shù)類似于 do_action()。要成功的從一個鉤子中刪除一個動作, $tag, $function_to_remove, 和 $priority 必須完全的復合 do_action() 中使用的參數(shù)。否則動作不會被溢出,同時 remove_action() 返回 flase。

我們看一個叫做 rel_canonical 的 WordPress 默認動作。這個動作在 <head> 和 </head> 元素之間添加一個 canonical 鏈接。

<?php
add_action( 'wp_head', 'rel_canonical' );
?>

要刪除這個動作,就要使用 remove_action() 函數(shù)。你需要定義 $tag 和 $function_to_rmove 參數(shù)。這里你不用添加 $priority 因為先前定義動作的時候沒有明確指定優(yōu)先級。

<?php
remove_action( 'wp_head', 'rel_canonical' );
?>

WordPress、plugin 或者 theme 添加的任何動作都可以在插件中刪除。通常只刪除 WordPress 添加的動作。許多默認的動作都定義在 wp-includes/default-filters.php 文件中。通過瀏覽這個文件你就會明白 WordPress 是如何使用動作鉤子的。

remove_all_actions

在有些插件中,可能需要刪除所有特定 tag 或者 特定 tag + 特定優(yōu)先級的所有鉤子。使用 remove_all_actions() 可以一次刪除所有符合條件的動作。

<?php
remove_all_actions( $tag, $priority );
?>

$priority 參數(shù)是可選的,默認是 false。如果你設置了這個參數(shù),那么只有這個優(yōu)先級的動作會被刪除。下面的例子從 wp_head 動作鉤子中刪除不管任何優(yōu)先級的動作。

<?php
remove_all_actions( 'wp_head' );
?>

在使用這個函數(shù)的時候必須要小心。其他 plugin 或者 theme 可能添加了你不知道動作。這就可能破壞插件應有的功能。通常應該保持你的代碼盡可能的特殊。在大多數(shù)情況下,你應該使用 remove_action() 函數(shù)來代替。

has_action

有的時候需要確定一個鉤子是否包含一些動作,或者一個特定的動作是否已經添加到了鉤子里面。has_action() 提供了這些功能。

<?php
has_action( $tag, $function_to_check );
?>

has_action() 函數(shù)的返回值是 Boolean 或者 一個整型值。如果 $function_to_check 參數(shù)為空,那么如果有動作已經添加到了鉤子中就返回 true,反之,返回 false。而如果 $function_to_check 設置了,而且這個函數(shù)已經添加到了鉤子里面,則返回該動作的優(yōu)先級,否則返回 false。

下面的例子中,根據(jù) wp_footer 動作鉤子中是否有注冊的動作來確定顯示的信息。

<?php
if( has_action( 'wp_footer' ) )
    echo '<p> footer 中已經注冊有動作了。</p>';
else
    echo '<p> footer 中還沒有注冊動作。</p>';
?>

下面看一個 WordPress 核心添加到 wp_footer 中的動作。wp_print_footer_script() 默認注冊給這個鉤子。

<?php
add_action( 'wp_footer', 'wp_print_footer_scripts' );
?>
did_action

did_action() 使你的插件可以檢查一個動作鉤子是否已經被執(zhí)行,或者記錄執(zhí)行的次數(shù)。這也意味著這一次頁面的加載過程中有些動作被執(zhí)行了多次。

<?php
did_action( $tag );
?>

這個參數(shù)返回動作已經執(zhí)行的次數(shù),如果還未執(zhí)行,返回 false。這個函數(shù)的一般用途是判斷一個動作鉤子是否已經被觸發(fā),并執(zhí)行基于 did_action() 的返回值的代碼。

下面的例子中,如果 plugins_loaded 動作鉤子已經被觸發(fā),就定義一個 PHP 常量。

<?php
if ( did_action( 'plugins_loaded' ) )
    define( 'BOJ_MYPLUGIN_READY' ,true );
?>
register_activation_hook 和 register_deactivation_hook

在第二章中已經介紹了這兩個函數(shù)。

常用的動作鉤子

WordPress 有許多動作鉤子,有一些是很常用的。

plugins_loaded

對插件開發(fā)者來說,plugins_loaded 動作鉤子也許是最重要的動作鉤子了。它在大多數(shù) WordPress 文件加載完成之后,并在pluggable 函數(shù)和 WordPress 開始執(zhí)行任何東西之前觸發(fā)。在大多數(shù)的插件中,在這個鉤子觸發(fā)之前,不應該執(zhí)行其他的代碼。plugins_loaded 在所有用戶啟用的插件都被 WordPress 加載之后執(zhí)行。這也是在加載過程中插件開發(fā)這最早能用到的鉤子。

WordPress 的插件應該在這個鉤子中執(zhí)行安裝。其他動作也應該添加到這個鉤子的回調函數(shù)中。

下面的例子中,使用前面部分創(chuàng)建的 boj_example_footer_message 動作。要把它添加到鉤到 plugins_loaded 鉤子中的安裝動作中,而不是單獨調用它。

<?php

add_action( 'plugins_loaded', 'boj_footer_message_plugin_setup' );

function boj_footer_message_plugin_setup() {

/* 添加 footer 信息動作 */

add_action( 'wp_footer', 'boj_example_footer_message', 100 );

}

function boj_example_footer_message() {

echo "基于 <a href="https://wordpress.org" >WordPress </a>架設。;

}

?>

創(chuàng)建一個安裝函數(shù)并把它鉤到 plugins_loaded 中。這樣做就可以確保不會由于特定的 WordPress 函數(shù)還沒有加載而觸發(fā)錯誤。

init

init 鉤子在大多數(shù)的 WordPress 都建立之后。WordPress 同樣添加許多內部的功能到這個鉤子中,例如 post types 和 taxonomies 的廚廁以及默認 widgets 的初始化。

因為這時幾乎 WordPress 中的所有內容都就緒了,當 WordPress 的所有信息都可用時,你的插件使用這個鉤子差不多可以做任何需要的事情了。

下面的例子中,為用戶添加了給 pages 寫摘要的功能。這應該在 init 中執(zhí)行,因為 “page” post type 在這時使用 add_post_type_support() 函數(shù)來創(chuàng)建。( 詳見 Part-11, “擴展 posts”)

<?php

add_action( 'init', 'boj_add_excerpts_to_pages' );

function boj_add_excerpts_to_pages() {

add_post_type_support( 'page', array( 'excerpt' ) );

}

?>
admin_menu

admin_menu 鉤子在管理員頁面加載的時候調用。無論何時你的插件直接在管理頁面下工作,你都要用這個鉤子來執(zhí)行你的代碼。

下面的例子添加了一個內容是 BOJ Settings 的 sub-menu 項到 WordPress 管理頁面的設置菜單。(詳見:Part-7,”插件設置”)

<?php

add_action( 'admin_menu', 'boj_admin_settings_page' );

function boj_admin_settings_page() {

add_options_page(

'BOJ Settings',

'BOJ Settings',

'manage_options',

'boj_admin_settings',

'boj_admin_settings_page'

);

}

?>
template_redirect

template_redirect 動作鉤子很有用,因為它是 WordPress 知道用戶正在瀏覽的頁面的關鍵。它在特定的頁面選擇 theme template 之前執(zhí)行。在只在網站的前端觸發(fā),并不在管理員頁面觸發(fā)。

當你需要為特定的頁面加載代碼的時候,這個鉤子很有用。

下面的例子中,僅僅為 singular post 加載一個樣式表文件。

<?php

add_action( 'template_redirect', 'boj_singular_post_css' );

function boj_singular_post_css() {

if( is_singular( 'post' ) ) {

wp_enqueue_style (       

'boj-singular-post',

'boj-example.css',

false,

0.1,

'screen'

);

}

}

?>
wp_head

在網站的前端,WordPress 的模板調用 wp_head() 函數(shù),會觸發(fā) wp_head 鉤子。插件使用這個鉤子在 <head> 和 </head> 標簽之間添加 HTML。

下面的例子中在前端添加一個 meta description。

<?php

add_action( 'wp_head', 'boj_front_page_meta_description' );

function boj_front_page_meta_description() {

/* 得到站點描述 */

$description = esc_attr( get_bloginfo( 'description' ) );

/* 如果 description 設置了,顯示 meta 元素 */

if ( !empty( $description ) )

echo '<meta name="description" content="'. $description. '"/>';

}

?>

有些插件錯誤的使用了 wp_head 動作鉤子來添加 JavaScript 代碼,實際上應該使用 wp_enqueue_script() 函數(shù)的。( 詳見:Part-12,”JavaScript 和 AJAX “)。唯一一種使用這個鉤子來添加 JavaScript 的情形是當 JavaScript 代碼不在一個單獨的文件中時。

過濾器 Filters

過濾器鉤子和動作鉤子有很大的區(qū)別。它讓你可以控制代碼的輸出。動作鉤子是讓你插入代碼,而過濾器鉤子讓你重寫 WordPress 傳遞給鉤子的代碼。你的函數(shù)會對輸出進行”過濾”。

要掌握過濾器鉤子的概念,必須首先明白 WordPress 的 apply_filters() 函數(shù)是如何工作的。

<?php

apply_filters( $tag, $value );

?>
  • $tag – 過濾器鉤子的名字。
  • $value – 傳遞給任何添加到這個鉤子的過濾器的參數(shù)。這個函數(shù)可以添加任意個額外的 $value 參數(shù)傳遞給過濾器。

注意:在寫一個過濾器的時候 $value 必須返回給 WordPress。

下面是 WordPress 核心的一個過濾器鉤子的例子:

<?php

apply_filters( 'template_include', $template );

?>

這個例子中,template_include 是一個過濾器鉤子的名字,$template 是一個可以通過注冊到這個過濾器鉤子的過濾器改變的文件名。

什么是過濾器?

一個過濾器是一個注冊到過濾器鉤子的函數(shù)。這個函數(shù)最少接受一個參數(shù)并在執(zhí)行完代碼后返回那個參數(shù)。沒有過濾器的過濾器鉤子沒有任何作用。插件開發(fā)者可以通過過濾器鉤子改變不同的變量 – 從字符串到多位數(shù)組。

當一個過濾器鉤子被 apply_filters() 函數(shù)調用時,所有注冊到這個鉤子的過濾器都會被執(zhí)行。要添加一個過濾器,使用 add_filter() 函數(shù)。

<?php

add_filter( $tag, $function, $priority, $accepted_args );

?>

和動作鉤子添加動作類似。$accepted_args 是過濾器函數(shù) $function 接受的參數(shù)個數(shù),默認是1。你的函數(shù)必須至少接受一個參數(shù)并返回。

可以給一個過濾器鉤子添加多個過濾器。同樣其他 WordPress 插件也可以給這個鉤子添加過濾器。過濾器鉤子并不限制給一個鉤子。注意:因為每個過濾器都必須返回一個值供其他過濾器使用。如果你的函數(shù)沒有返回值,那就可能會破壞整個 WordPress 或者其他的插件。

下面看看 wp_title 過濾器鉤子,它是負責頁面的 <title> 元素的過濾器鉤子。

<?php

apply_filters( 'wp_title', $title, $sep, $seplocation );

?>
  • wp_title – 鉤子名。
  • $title – 一個字符串,要過濾并返回給 WordPress 的值。
  • $sep – 說明 <title> 元素之間的分隔符是什么。
  • $seplocation – 分隔符的位置。下一個例子中要用到。

現(xiàn)在寫一個函數(shù)來過濾 $title 的輸出 – 在頁面的 title 后面附加站點的名字:

<?php

add_filter( 'wp_title', 'boj_add_site_name_to_title', 10, 2 );

function boj_add_site_name_to_title( $title, $seq ) {

/* 得到網站名稱 */

$name = get_bloginfo( 'name' );

/* 附加到 $title 變量。 */

$title .= $sqp.' '.$name;

/* 返回 $title */

return $title;

}

?>

boj_add_site_name_to_title() 函數(shù)修改 $title 參數(shù)并返回給 WordPress。$sep 參數(shù)在函數(shù)中使用,但沒有返回。

過濾器鉤子函數(shù)

除了前面提到的 apply_filters() 和 add_filter() 函數(shù),WordPress 還提供其他的操作過濾器鉤子的函數(shù)。

apply_filters_ref_array

類似于動作鉤子里面的 do_action_ref_array() 函數(shù)。

<?php

apply_filters_ref_array( $tag, $args );

?>

假設你要執(zhí)行一個一般的 WordPress 沒有的復雜的數(shù)據(jù)庫查詢來加載首頁的 posts。WordPress 提供了一個叫做 posts_results 的過濾器鉤子使得你可以改變它。下面是 WordPress 核心中的代碼:

<?php

$this -> posts = apply_filters_ref_array(

'posts_results', array( $this -> posts, & $this )

);

?>

這個過濾器鉤子向所有注冊到它的過濾器傳遞一個 post 對象的數(shù)組。下面的例子,你完全重寫這個 post 對象的數(shù)組并用自定義的內容代替。默認情況下,WordPress 查詢 post 類型的 posts。下面改成查詢 page 類型的 psots 并顯示在首頁。

這段代碼使用了 wpdb 類,在 part-6 “插件安全” 中將詳細介紹。

<?php

add_filter( 'posts_result', 'boj_custom_home_page_posts' );

function boj_cumstom_home_page_posts( $result ) {

global $wpdb, $wp_query;

/* 檢查是否在首頁 */

if ( is_home() ) {

/* 每頁的 post 個數(shù) */

$per_page = get_option( 'posts_per_page' );

/* 得到當前頁 */

$paged = get_query_var( 'paged' );

/* 設置 $page 變量 */

$page = ( ( 0 == $paged || 1 == $paged ) ? 1 : absint( $paged ) );

/* 設置偏移的 posts 的個數(shù) */

$offset = ( $page - 1 ) * $per_page. ',';

/* 通過 $offset 和 要顯示的 posts 數(shù)量來設置 limit */

$limits = 'LIMIT'. $offset . $per_page;

/* 從數(shù)據(jù)庫查詢結果 */

$result = $wpdb -> get_results("

SELECT SQL_CALC_FOUND_ROWS $wpdb -> posts. *

FROM $wpdb -> posts

WHERE 1 = 1

AND post_type = 'page'

AND post_status = 'publish'

ORDER BY post_title ASC $limits "

); 

}

return $result;

}

?>
remove_filter
<?php 

remove_filter( $tag, $function_to_remove, $priority, $accepted_args );

?>

這和前面的 remove_action 類似。

下面看看 WordPress 定義在 wp-includes/default-filters.php 頁面中的默認的過濾器。其中一個有意思的過濾器叫做 wpautop(),它將雙換行轉換成 HTML 的 <p> &lt/p>。這也就是我們在 HTML 發(fā)布內容時,直接回車便可在最終前端顯示的時候換行的原因。它在核心代碼中的幾個鉤子中都執(zhí)行。下面是其中一個實例:

<?php

add_filter( 'the_content', 'wpautop' );

?>

這將 wpautop() 過濾器應用到 post 的內容中,把每個換行都轉換成段落( <p> )。但是也許有的客戶不希望他的內容自動變成段落。那么你就可以使用 remove_filter() 函數(shù)從 the_content 鉤子中刪除這個過濾器。

<?php

remove_filter( 'the_content', 'wpautop' );

?>

因為在 add_filter 的時候沒有定義優(yōu)先級,所以這里也不需要。

remove_all_filters

和前面的remove_all_actions類似。

<?php

remove_all_filters( $tag, $priority );

?>
has_filter

和前面的 has_action 類似。

current_filter

同樣類似于 did_action。不過它不僅僅對過濾器鉤子有效,同樣對動作鉤子也有效,所以它返回的是當前的 action 或者 filter 鉤子。這個函數(shù)在你對多個鉤子使用單個函數(shù),但是需要依賴不同的鉤子執(zhí)行不同的內容的時候非常的有用。例如,客戶希望在 post 標題 和內容中限制一些內容,但是這兩個限制的minganci的集合是不同的。使用 current_filter() 函數(shù)來根據(jù)鉤子設置不同的minganci表就可以實現(xiàn)用一個函數(shù)同時過濾 the_content 和 the_title。使用下面的代碼,你可以把minganci替換成**。

<?php

add_filter( 'the_content', 'boj_replace_unwanted_words' );

add_filter( 'the_title', 'boj_replace_unwanted_words' );

function boj_replace_unwanted_words( $text ) {

/* 如果過濾器鉤子是 the_content */

if( 'the_content' == current_filter() )

$words = array( 'min', 'gan', 'ci' );

/* 如果鉤子是 the_title */

elseif( 'the_title' == current_filter() )

$words = array( 'zhen', 'de', 'hen', 'min', 'gan' );

/* 替換minganci */

$text = str_replace( $words, '**', $text );

return $text;

}

?>

快速返回函數(shù)

你經常需要寫一個函數(shù)返回一個常用的值給一個過濾器鉤子,例如 true,false,或者一個空數(shù)組。你甚至嘗試使用 PHP 的 create_function() 函數(shù)來快速返回一個值。

WordPress 提供幾個函數(shù)處理這種情況。

下面是例子禁用了 user contact 方法 – 在 WordPress 的個人用戶管理頁面中的一系列 &ltinput>。要禁用這些表單項,你需要返回一個空數(shù)組。通常,你必須添加過濾器鉤子調用和函數(shù)。

<?php

add_filter( 'user_contactmethods', 'boj_return_empty_array' );

function boj_return_empty_array() {

return array();

}

?>

寫這樣的代碼一兩次并沒什么。但是寫一個返回空數(shù)組的函數(shù)太傻了。WordPress 使之簡單化了。因為要禁用這些表單項,你只需要使用 WordPress 的 __return_empty_array() 函數(shù)作為過濾器來快速返回一個空數(shù)組。如下:

add_filter( 'user_contactmethods', '__return_empty_array' );

還有幾個類似的快速返回函數(shù):

  • __return_false
  • __return_true
  • __return_zero

如果上面的函數(shù)不符合你的要求,你還可以創(chuàng)建自己的快速返回函數(shù)。

常用的過濾器鉤子

WordPress 上百種過濾去鉤子提供給插件開發(fā)者。下面介紹一些常用的過濾器鉤子。

the_content

the_content 可以說是用的最多的過濾器鉤子了。沒有內容,一個網站一點用處也沒有。內容是一個網站上最重要的東子,插件使用這個鉤子為網站添加許多特色。

the_content 鉤子向所有注冊給它的過濾器傳遞一個 post 的內容。之后由過濾器來控制內容,通常添加一些格式化或者附加而外的一些信息。下面的例子根據(jù) post 分類,當用戶閱讀一篇 post 時顯示一個附加的相關 post 列表到 the_content。

<?php

add_filter( 'the_content', 'boj_add_related_posts_to_content' );

function boj_add_related_posts_to_content( $content ) {

/* 如果不是單篇文章,直接返回 content */

if ( !is_singular( 'post' ) )

return $content;

/* 得到當前 post 的分類 */

$terms = get_the_terms( get_the_ID(), 'category' );

/* 循環(huán)分類,并將它們的 ID 放到一個數(shù)組中 */

$categories = array();

foreach ( $terms as $term )

$categories[] = $term -> term_id;

/* 從數(shù)據(jù)庫查詢相同分類的 posts */

$loop = new WP_Query(

array(

'cat__in' => $categories,

'posts_per_page' => 5,

'post__not_in' => array( get_the_ID() ),

'orderby' => 'rand'

)

);


/* 是否有相關 posts 存在 */

if( $loop -> have_posts() ) {

/* 開始 ul */

$content .= '<ul class="related-posts">';

while( $loop -> have_posts() {

$loop -> the_post();

/* 添加 post 標題 */

$content .= the_title (

'<li><a href="'.get_permalink().'">',

'</a></li>',

false

);

}

/* 結束 ul */

$content .= '</ul>';

/* 重置 query */

wp_reset_query();

}

/* 返回 content */

$return $content;

}

?>
the_title

文章的標題幾乎和內容一樣重要,所以 the_title 也是一個常用的過濾器鉤子。你可以使用這個鉤子添加信息,或者直接重寫。

應用給 the_title 鉤子的一個有用的過濾器就是去除標題中 HTML 標簽的過濾器函數(shù)。用戶有時會添加一些標簽到標題中,這可能會破壞正常的格式。使用下面的代碼,你可以過濾掉所有用戶可能添加到標簽。

<?php

add_filter( 'the_title', 'boj_strip_tags_from_titles' );

function boj_strip_tags_from_title( $title ) {

$title = strip_tags( $title );

$return $title;

}

?>
同樣 comment_text 也很常用

下面的例子中,檢查一條評論是否是網站的注冊用戶發(fā)表的。如果是注冊用戶,你可以附加一段用戶信息的說明( 詳見:Part-8,”用戶” )

<?php

add_filter( 'comment_text', 'boj_add_role_to_comment_text' );

function boj_add_role_to_comment_text( $text ) {

global $comment;

/* 檢查是否是注冊用戶 */

if( $comment -> user_id > 0 ) {

/* 新建一個用戶對象 */

$user = new WP_User( $comment -> user_id );

/* 如果用戶有一個角色,添加到評論內容中 */

if( is_array( $user -> roles ) )

$text .= '<p>User Role: ' .$user -> roles[0]. '</p>';

}

return $text;

}

?>
template_include

template_include 是其他一些更特殊的過濾器鉤子的一類”雜物包”( catchall )過濾器鉤子。

  • front_page_template
  • home_template
  • single_template
  • page_template
  • attachment_template
  • archive_template
  • category_template
  • tag_template
  • author_template
  • date_template
  • search_template
  • 404_template
  • index_template

它用在 theme template 過濾器后面,當當前頁被選中后。WordPress 根據(jù)讀者當前瀏覽的頁面來選擇一個模板。你可以為每一個獨立的過濾器鉤子添加一個過濾器,也可以在最后使用 template_include 鉤子一起過濾他們。

比如你想按照你的插件的標準構造一個模板層級結構,而不是使用 WordPress 默認的模板層級。template_include 和上面列表中的鉤子可以滿足你。

下面的例子中,根據(jù)分類判斷一個 posts 的模板是否存在。默認情況下,WordPress 先檢查 single.php,如果不存在,再檢查 index.php文件。而你的函數(shù)查找一個叫做 single-category-$slug.php ( $slug 是分類的別名 )的文件。所以如果用戶有一個叫 art 的分類,同時一個模板的名字叫做 single-category-art.php,那么這個文件會被用來代替 single.php。

<?php

add_filter( 'single_template', 'boj_single_template' );

function boj_single_template( $template ) {

global $wp_query;

/* 檢查是否在瀏覽單個 post */

if( is_singular( 'post' ) ) {

/* 獲得 post ID */

$post_id = $wp_query -> get_queried_object_id();

/* 獲得 post 的分類 */

$terms = get_the_terms( $post_id, 'category' );

/* 循環(huán)分類,添加別名作為文件名的一部分 */

$template = array();

foreach ( $terms as $term )

$templates[] = "single-category-{$term->slug}.php";

/* 檢查模板是否存在 */

$locate = locate_template( $templates );

/* 如果找到,讓它成為新模板 */

if( !empty ( $locate ) )

$template = $locate;

}

/* 換回模板文件名 */

return $template;

}

?>

使用一個類中的鉤子

前面已經講了許多通過 PHP 函數(shù)來使用動作鉤子和過濾器鉤子的例子。在類中添加一個方法作為一個動作或者過濾器的時候,格式和 add_action() 和 add_filter() 略微有些不同。

一般來說,插件使用函數(shù)而不是類中的方法作為動作或者過濾器。但是,可能有些時候使用類更適合,所以你要知道如何類在類中將方法注冊到鉤子。

前面已經提到的注冊函數(shù)到一個動作鉤子的方法:

<?php

add_action( $tag, $function_to_add );

?>

當在類中將方法作為 $function_to_add 參數(shù)時,你必須把 $function_to_add 變成一個數(shù)組,其中 & $this 作為第一個參數(shù),方法名作為第二個參數(shù):

<?php

add_action( $tag, array( & $this, $method_to_add ) );

?>

對于過濾器鉤子也是一樣。一般的將函數(shù)添加到一個過濾器鉤子類似于:

<?php

add_filter( $tag, $function_to_add );

?>

當使用類的方法的時候,要改成:

<?php

add_filter( $tag, array( & $this, $method_to_add ) );

?>

下面的例子中,創(chuàng)建了一個類,包含一個構造函數(shù),一個作為動作的方法,和一個作為過濾器的方法。add_filters() 方法檢查用戶是否在瀏覽單篇 post。如果是 content() 方法附加最后的修改時間到 post 的內容中。

<?php

class BOJ_My_Plugin_Loader {

/* 類的構造函數(shù) */

function BOJ_My_Plugin_Loader() {

/* 為 'template_redirect' 鉤子添加 'singular_check' 方法 */

add_action( 'template_redirect', array( & $this, 'singular_check' ) );

}

/* 作為動作的方法 */

function singular_check() {

/* 如果在看單個文章,過濾內容 */

if ( is_singular() )

add_filter( 'the_content', array( & $this, 'content' ) );

}

/* 作為過濾器的方法 */

function content( $content ) {

/* 得到 post 的最后修改時間 */

$date = get_the_modified_time( get_option( 'date_format' ) );

/* 附加修改時間到 content */

$content .= '<p> 最后修改于:' .$date. '</p>';

return $content;

}

}

$boj_myplugin_loader = new BOJ_My_Plugin_Loader();

?>

創(chuàng)建自定義鉤子

插件不但可以使用內核的內置鉤子,他們也可以創(chuàng)建自定義的鉤子供其他插件和模板使用。

插件可以使用4個可用函數(shù)中的一個來創(chuàng)建自定義鉤子。

  • do_action()
  • do_action_ref_array()
  • apply_filters()
  • apply_filters_ref_array()

前兩個創(chuàng)建自定義動作鉤子,后兩個創(chuàng)建自定義過濾器鉤子。

創(chuàng)建自定義鉤子的優(yōu)點

自定義鉤子使得你的插件更靈活,使其可以被其他插件擴展,讓你可以鉤到你的整個插件自己的其他執(zhí)行過程中。

使用自定義鉤子還可以防止用戶直接修改你的插件。這一點的重要性在于,當你更新你的插件時,用戶不會失去他們修改的內容。

自定義動作鉤子實例

在這個例子中,建立了一個插件安裝函數(shù)。這個函數(shù)定義了一個可以更換的常量。別的插件也可以在這個鉤子上執(zhí)行任何代碼。因為你在那一點上提供了鉤子。

<?php

add_action( 'plugins_loaded', 'boj_myplugin_setup' );

function boj_myplugin_setup() {

/* 允許動作最先觸發(fā) */

do_action( 'boj_myplugin_setup_pre' );

/* 檢查 root slug 是否定義 */

if( !defined( 'BOJ_MYPLUGIN_ROOT_SLUG' ) )

define( 'BOJ_MYPLUGIN_ROOT_SLUG', 'articles' );

}

?>

其他插件或者模板可以鉤到 boj_myplugin_setup_pre 來執(zhí)行任何函數(shù)。

比如你想把 BOJ_MYPLUGIN_ROOT_SLUG 常量從 ‘articles’ 改為 ‘papers’ ,你可以建立一個動作并添加到這個鉤子中:

<?php

add_action( 'boj_myplugin_setup_pre', 'boj_define_myplugin_constants' );

function boj_define_myplugin_constants() {

define( 'BOJ_MYPLUGIN_ROOT_SLUG', 'papers' );

}

?>

自定義過濾器鉤子實例

假設有一個函數(shù)顯示一個具有一個特定闡述的文章列表。你也許希望其他人能夠過濾那個參數(shù)或者過濾最終結果。

下面的例子中,寫一個函數(shù)根據(jù)收到的評論條數(shù)列取了前10的文章。這個函數(shù)讓用戶可以在從數(shù)據(jù)庫獲取數(shù)據(jù)前過濾這個參數(shù),并且可以過濾最終輸出的 HTML 列表。

<?php

function boj_posts_by_comments() {

/* 默認參數(shù) */

$args = array(

'post_type' => 'post',

'posts_per_page' => 10,

'order' => 'DESC',

'oerderby' => 'comment_count'

);

/* 應用過濾器 */

$args = apply_filters( 'boj_posts_by_comments_args', $args );

/* 設置輸出變量 */

$out = '';

/* 由給定的參數(shù)從數(shù)據(jù)庫查詢文章 */

$loop = new WP_Query( $args );

/* 檢查是否返回結果 */

if( $loop -> have_posts() ) {

$out .= '<ul class="posts-by-comments" >';

while( $loop -> have_posts() ) {

$loop -> the_post();

$out .= the_title( '<li>', '</li>', false );

}

$out .= '</ul>';

}

$out = apply_filters( 'boj_posts_by_comments', $out );

echo $out;

}

?>

要過濾參數(shù),給 boj_posts_by_comments_args 添加一個過濾器。比如你希望把數(shù)量從默認的10變成15,添加下面的過濾器:

<?php

add_filter( 'boj_posts_by_comments_args', 'boj_change_posts_by_comments_args' );

function boj_change_posts_by_comments_args( $args ) {

$args['posts_per_page'] = 15;

return $args;

}

?>

要過濾最后的 HTML 輸出,添加一個過濾器到 boj_posts_by_comments。比如你想把 ul 改成 ol。

<?php

add_filter( 'boj_posts_by_comments', 'boj_change_posts_by_comments' );

function boj_change_posts_by_comments( $out ) {

$out = str_replace( '<ul', '<ol', $out );

$out = str_replace( '</ul>', '</ol>', $out );

return $out;

}

?>

上哪找鉤子?

要給出 WordPress 中所有鉤子的列表幾乎是不可能的。前面我們討論了一些常用的動作和過濾器鉤子,這一節(jié)僅僅討論一小部分 WordPress 提供的鉤子。

WordPress 的新版本會加入新的鉤子。最終查看不同版本的內核可以讓你找到可以用在插件中的新鉤子。

在內核中搜索鉤子

作為一個插件開發(fā)這,你應該熟悉 WordPress 的內核。尋找鉤子能很好的幫助你熟悉 WordPress 內核是如何工作的。沒有更好的方法來搞明白 PHP 代碼在內核中是如何工作的了。

要尋找鉤子的一個簡單的方法是在編輯器中打開一個 WordPress 文件然后搜索下面的四個詞:

  • do_action
  • do_action_ref_array
  • apply_filters
  • apply_filters_ref_array

這四個函數(shù),每一個都創(chuàng)建一個鉤子。

變量鉤子

在 WordPress 的內核中找鉤子的時候,你會遇到變量鉤子。通常鉤子的名字是一個靜態(tài)的字符串。但是變量鉤子的名字跟著特定的變量而改變。

一個很好的例子就是 load-$pagenow 動作鉤子。變量 $pagenow 根據(jù) WordPress 中當前瀏覽的 admin 頁面而改變。這個鉤子如下:

<?php

do_action( "load-$pagenow" );

?>

變量 $pagenow 會變成當前訪問頁面的名字。例如 new post 頁面的鉤子是 load-post-new.php,而編輯頁面的是 load-post.php。這就使得插件僅僅對特定的 admin 頁面執(zhí)行代碼。WordPress 有幾個動作和過濾器鉤子的名稱里面是含有變量的。

通常,這些鉤子的名字變成給定的內容,使得插件開發(fā)者可以在特定的環(huán)境下執(zhí)行代碼。

鉤子參考列表

雖然在核心里面搜索鉤子有助于你增長經驗,但是有時你需要一些網上的參考列表。

WordPress 在 Codex 中有官方的鉤子參考列表。

在 Part-18,開發(fā)人員工具箱,將介紹更多幫助插件開發(fā)者的工具。

總結

鉤子是創(chuàng)建 WordPress 插件的最重要的一環(huán)了。每次你開始創(chuàng)建一個插件,你都要把你的插件鉤到 WordPress 的動作鉤子和過濾器鉤子中。鉤子是插件開發(fā)中必不可少的工具。在了解了鉤子之后,就是時候開始創(chuàng)建插件了。

注:本文出自《Professional WordPress Plugin Development》一書,由 sixpoint.me 翻譯,倡萌整編。

您已閱讀完《WordPress 插件開發(fā)教程(共4篇)》專題的第 3 篇。請繼續(xù)閱讀該專題下面的文章:

聲明:本站所有文章,如無特殊說明或標注,均為本站原創(chuàng)發(fā)布。任何個人或組織,在未征得本站同意時,禁止復制、盜用、采集、發(fā)布本站內容到任何網站、書籍等各類媒體平臺。如若本站內容侵犯了原著者的合法權益,可聯(lián)系我們進行處理。

給TA打賞
共{{data.count}}人
人已打賞
歡迎關注WordPress大學公眾號 WPDAXUE
WordPress開發(fā)

WordPress 插件開發(fā)教程 Part 2 – WordPress 插件基礎

2013-3-27 6:59:00

WordPress開發(fā)

WordPress 的 Hook 機制與原理

2013-3-28 8:00:20

2 條回復 A文章作者 M管理員
  1. 可惜只有4課啊,如果能有完整的就好了

  2. 謝謝作者的翻譯!

?
個人中心
購物車
優(yōu)惠劵
今日簽到
有新私信 私信列表
搜索

海宁市| 伊金霍洛旗| 宜州市| 万荣县| 寻甸| 霍州市| 武夷山市| 堆龙德庆县| 桐庐县| 常宁市| 柳河县| 石阡县| 沁源县| 科技| 洛宁县| 周宁县| 宣武区| 新安县| 夏邑县| 蒙山县| 陕西省| 金平| 西宁市| 宜川县| 察雅县| 吴忠市| 饶河县| 泰州市| 电白县| 化州市| 营口市| 双辽市| 胶州市| 肥西县| 阿拉善右旗| 合川市| 文登市| 溧阳市| 台安县| 深水埗区| 康乐县|