當(dāng)前位置:首頁>WordPress建站>WordPress開發(fā)>WordPress 的 Hook 機(jī)制與原理

WordPress 的 Hook 機(jī)制與原理

稍有接觸過 WordPress 主題或插件制作修改的朋友,對 WordPress 的Hook機(jī)制應(yīng)該不陌生,但通常剛接觸WordPress Hook 的新手,對其運作原理可能會有點混亂或模糊。本文針對 WordPress Hook 運作大致做個簡單的說明,而預(yù)設(shè)讀者是理解基本的 PHP function 語法及運作,但對 WordPress Hook 機(jī)制不是很明白。

wpdaxue.com-201303510

Hook機(jī)制里登場的角色

先從“登場角色”的個別說明開始:

WordPress核心

指的是 WordPress 內(nèi)建的程式碼架構(gòu),提供 WordPress 主要的基本功能。

Hook

也許你早已聽說,Hook 本身雖是鉤子的意思,但直譯又有點奇怪,所以一般通常都不直譯它,而是直接稱它 Hook 。WordPress 的 Hook 也可以想像成“鉤子”,這些“鉤子”會埋在 WordPress 網(wǎng)站中特定幾處的程式碼中,埋進(jìn)去時使用的語法,其“標(biāo)示位置”的意義比較大,沒有實質(zhì)運作的內(nèi)容。當(dāng)程式執(zhí)行到有埋 Hook 的地方時,它會找出所有對應(yīng)到自己的 Hook Function (也就是所有“鉤到”該 Hook 的 hook function),并一一執(zhí)行。

因此若沒有針對此 Hook 去“加入”要鉤上去的 Hook Function,執(zhí)行到此什么也不會做。因此,它等于是WordPress核心預(yù)留一個執(zhí)行的機(jī)會給未來想要加入定制功能的開發(fā)者。

Hook Function

Hook Function 里會有實質(zhì)運作的內(nèi)容,即是實作了一些定制功能,可能是存取 DB、增加 HTML code、執(zhí)行其他函式等等。我們在 Hook Function 里寫好所需的功能后,就可以利用“加入至對應(yīng) Hook”的語法,把 Hook Function自已鉤到該 Hook 上,使得該 Hook 被執(zhí)行到時,也會連帶執(zhí)行自己。

Hook機(jī)制是如何運作的?

舉個例子,我們拿 wp_head 及 wp_footer 這兩個內(nèi)建的hook來說明,wp_head 這個 hook 就是用來埋在負(fù)責(zé)輸出標(biāo)簽的程式碼中,而 wp_footer 就是用來埋在輸出頁尾的程式碼中 (定義于 wp-includes/general-template.php,用 wp_head() 及 wp_footer() 包裝起來)。這兩個 hook,主要都是在布景檔案中使用的,常見會出現(xiàn)在 header.php 及 footer.php 中。

請看下面的情境示例圖,我們把 wp_head 及 wp_footer 看成是”鉤子“,而別的 hook functions 就能來鈎住它:

wpdaxue.com-201303507

我們馬上來寫一個簡單的例子。我們要寫一個 hook function,就叫它 print_sth(),然後把它鉤上 wp_head 這個hook。因為 wp_head() 的內(nèi)容實際上就只有 do_action( ‘wp_head’ );  這一行內(nèi)容,而 wp_footer() 的內(nèi)容也只有 do_action(‘wp_footer’);所以我們直接把 do_action 的語法換到圖上去,比較容易做說明,因此示意圖變成:

wpdaxue.com-201303508

如此,只要執(zhí)行到輸出 header.php 時,就會執(zhí)行到 wp_head(),就如同執(zhí)行到 do_action( ‘wp_head’ ); 此時WP核心會去找所有”鉤上”wp_head 這個 hook 的 hook function,於是就找到我們寫的 print_sth() ,然後就執(zhí)行它,所以結(jié)果它做的事就會出現(xiàn)在網(wǎng)站上,也完成了”定制”的動作:

wpdaxue.com-201303509

簡單的說,Hook 機(jī)制就是:WP 核心或其他插件、主題 提供想定制功能的人一個置入定制程式碼(Hook Function)到特定的執(zhí)行時間點(Hook)的機(jī)會。

WordPress的Action Hook與Filter Hook

WordPress中的 Hook 有兩種,分別是”Action Hook“及”Filter Hook“,我們剛才舉例的 wp_head 及wp_footer 都是屬於 Action Hook。不過,一開始你可以先把這兩種 Hook 看成是一樣的東西,只是 Filter 多了一點點不同的特色,接著說明。

Action Hook

WP核心 (或主題、插件)在做它們該做的事時,如果執(zhí)行到有埋 action hook 的程式碼 (即是 do_action 語法) 時,會去找尋對應(yīng)到的 hook functions,進(jìn)而執(zhí)行這些 hook functions(即那些透過 add_action() 來加入的 hook functions),藉此完成定制功能。WP核心并不期待 Action Hook functions 會有回傳值,所以這里的 hook function 只被視為一個”獨立切出來運作的功能“。

WP核心做它該做的事,你做你想做的事,做完就各自結(jié)束。

Filter Hook

跟 Action Hook 一樣,WP核心 (或主題、插件)在做它們該做的事時,如果執(zhí)行到有埋 filter hook 的程式碼 (即是apply_filters語法) 時,就會去找尋對應(yīng)的 hook functions ,進(jìn)而執(zhí)行這些 hook functions(即那些透過add_filter() 來加入的 hook functions ),藉此完成定制功能。與 Action Hook 不同之處是,所有”鈎上“ Filter Hook 的 hook functions 通常都會接收到參數(shù),而WP核心會期待你拿到它提供的參數(shù),并做完你想做的事后,要回傳(return)一個值,讓W(xué)P核心再利用你回傳的值來接著完成它該做的事。

透過你的干涉,修改了WP核心丟給你的參數(shù),WP核心再接著拿你改過的參數(shù),繼續(xù)完成它該做的事,此動作就像”過濾“的動作,因而得名 filter。

比較Action Hook與Filter Hook的操作語法

比較一下兩種 Hook 在埋進(jìn)某處程式碼時所用的語法,假設(shè)我們在某處 (可能是在輸出頁首的程式碼處,或輸出文章標(biāo)題、文章內(nèi)容、側(cè)邊欄…等地方,要”出現(xiàn)定制效果“的地方)埋下這兩種 hook:

/*--------------- Action Hook ---------------*/
// 埋下一個名叫'do_more'的action hook

do_action('do_more');
 
/*--------------- Filter Hook ---------------*/
// 埋下一個名叫'get_special'的filter hook,注意它會有回傳值

$c = apply_filters('get_special',$a, $b);

然后我們可以在某處 (可能是其他插件、functions.php 等處,要”實現(xiàn)定制功能“的地方)添加對應(yīng)的 hook function:

/*--------------- Action Hook Function---------------*/
// 增加要鉤上'do_more'這個hook的hook function,
// 并為此hook function取名叫more_func。
// 第一個參數(shù)是hook名稱、第二個是hook function名稱

add_action('do_more', 'more_func');

// 添加more_func的內(nèi)容,不需回傳值

function more_func()
{
    echo 'do more thing...';
}
 
/*--------------- Filter Hook Function ---------------*/
// 增加要鉤上'get_special' hook的hook function,
//并為此hook function取名叫special_func。
// 參數(shù)1是hook名稱、參數(shù)2是hook function名稱
// 參數(shù)3是Priority(優(yōu)先序)、參數(shù)4是hook function參數(shù)的數(shù)目

add_filter('get_special', 'special_func', 10, 2);

// 添加special_func的內(nèi)容,需要給它回傳值

function special_func($a, $b)
{
    $c = $a.' & '.$b; //做一些事,例如把兩個參數(shù)連接起來
    return $c; //回傳值
}

所以其實兩種 Hook 的運作方式幾乎一樣,只差在增加 Action Hook 函式不需回傳值,而增加 Filter Hook function時,你必須要回傳一個值。所以 Filter Hook 函式通常都有提供參數(shù),讓想定制的人可以取得它,處理后再回傳。

但如果有一個 Filter Hook,它沒有任何 hook function 有去鉤它,它該怎么取得回傳值?答案是,直接拿第一個它給的參數(shù),以上面的例子來說,它會直接拿 $a 丟進(jìn) $c 。另外,其實我們也可以把 filter 寫的跟 action 一樣,只要不回傳值就行,但 action hook 就沒辦法”模仿“ filter hook,因為無法取得回傳值。

Hook Function的優(yōu)先序(Priority)

如果有很多地方(主題或者插件的 functions.php)都 添加同一個 hook ,會怎么決定出現(xiàn)順序?答案很顯然是可以透過 Hook Function 的 Priority 參數(shù)來作優(yōu)先序的設(shè)定:

就像我們剛才說明的例子中,我們使用 add_filter 加入 special_func 時設(shè)定的優(yōu)先序是 10 ,這也是 Priority 參數(shù)的預(yù)設(shè)值。如果你希望它能優(yōu)先被執(zhí)行,就設(shè)定小于 10 的數(shù)字,反之,就設(shè)個 100、500 之類的,讓它延后被執(zhí)行。

但其實這里有個隱含的沖突問題。

以 wp_head 這個 hook 為例,如果我寫了一個插件,希望透過 wp_head 來輸出”增加 a.css 檔案“的 HTML 語法,而 a.css 會重新設(shè)定 body 元素的樣式,所以我希望它可以最后才被匯入,不要被其他 css 檔干擾,于是我將 Priority 設(shè)為 900,但我怎么知道 Priority 900 夠不夠大?若某個WP網(wǎng)站,它除了安裝我的插件,也安裝了其他插件,而其他插件剛好也重新設(shè)定body元素的樣式,然后把 Priority 設(shè)為 950,此時我寫的插件在處理 body 樣式時就出事了,于是就跟其他插件沖突了。

所以此時我們需要了解的是:我的WP網(wǎng)站可能裝了很多插件,我怎么知道同一個 Hook 被加了多少 Hook Function,而每個 Hook Function 的 Priority 被設(shè)定為多少?

答案是,我們可以透過 $wp_filters 這個 global 變數(shù)來取得所有 hook 的信息,像是如下的 function:

// 列出所有的hook function及其priority

function list_hooked_functions($tag=false)
{
    global $wp_filter;
     
    if ($tag) 
    {
        $hook[$tag]=$wp_filter[$tag];
        if (!is_array($hook[$tag])) 
        {
            trigger_error("Nothing found for '$tag' hook", E_USER_WARNING);
            return;
        }
    }
    else
    {
        $hook=$wp_filter;
        ksort($hook);
    }
     
    echo '<pre>';
    foreach($hook as $tag => $priority)
    {
        echo "<br />>>>>>\t<strong>$tag</strong><br />";
        ksort($priority);
        foreach($priority as $priority => $function)
        {
            echo $priority;
            foreach($function as $name => $properties) echo "\t$name<br />";
        }
    }
    echo '</pre>';
    return;
}

當(dāng)我們呼叫 list_hooked_functions(‘wp_head’); 時,就會列出 wp_head 這個 Hook 所鉤住的所有 hook function,可以看到 priority 10 之后有好幾個都沒有數(shù)字,因為它們都沒有特別指定 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

所以,沖突很難提早避免,但發(fā)生沖突時,可以預(yù)先思考有沒有可能是因為 priority 的設(shè)定,導(dǎo)致結(jié)果跟預(yù)期不符合。

原文出自:http://www.mrmu.com.tw/2011/10/10/wordpress-hook/ ,倡萌整編。

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

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

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

2013-3-28 6:46:00

WordPress開發(fā)

WordPress 插件開發(fā)教程 Part 4 – 與WordPress整合

2013-3-29 6:56:00

11 條回復(fù) A文章作者 M管理員
  1. 么么噠!

    很受用!整整一天看了這么多hook的文章,終于在這里看懂了!

  2. 干貨啊,wp最核心的原理!

  3. 這是wordpress的精髓所在

  4. 樓主高手啊

  5. 謝謝你!非常受用,終于明白了!

  6. 代碼,25行:function special($a, $b)應(yīng)該是function special_func($a, $b)吧?

    • 感謝糾正,已更新

  7. 謝謝,在您的網(wǎng)站逛了一下午,獲益不少。

  8. 樓主很用心整理啊,終于遇到一個國內(nèi)的wp高手了,以后常來交流!

    • 高手算不上,還在學(xué)習(xí)中。歡迎常來交流

  9. 學(xué)習(xí)了,還能坐沙發(fā)真好

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

呼图壁县| 新昌县| 阿拉善右旗| 郁南县| 大邑县| 沧源| 中江县| 新乡市| 德江县| 咸丰县| 遂宁市| 兴宁市| 城步| 台南市| 温宿县| 吴旗县| 湄潭县| 昭平县| 东平县| 枞阳县| 达拉特旗| 冀州市| 广南县| 平昌县| 抚远县| 太原市| 庆阳市| 信宜市| 合肥市| 探索| 射洪县| 曲沃县| 澄城县| 陆丰市| 鄂托克旗| 泸定县| 建平县| 南部县| 金华市| 乡城县| 乌鲁木齐市|