iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 8
0
自我挑戰組

Wordpress 外掛開發系列 第 8

「Wordpress 外掛開發」Worpdress 的核心鉤子 Hook - action

在WP中,hook是主要的元件來組成整個架構,不僅可以讓開發人員增加開發的彈性,也讓程式碼的重新利用率高很多,而他的最大益處,不管是WP的更新或是外掛的程式碼的變動,基本上是可以不用掛上新的hook也是可以相容的。

而談到hook的核心概念,莫過於我們當初所說不要去更動到core的檔案,我們可能因為因為每一次更新或是程式變動,造成你原本修改的程式碼消失,不過我們可以利用Hook來做到變動,因為你想做的hook上都有,比如說admin_menu、footer、login hook之類的,而在這些眾多的功能中主要分成兩個類型,一個是action,而另一個是filter

在開始之前,我們先簡單的劃分action與filter的區別,雖然我們在前面已經多次提到了action不過我相信大家應該對這兩個是比較熟悉的,因為大家如果要基本改寫Wordpress的功能,一開始找到的資料就是這裡了,不過我覺得一開始就看action與filter滿不友善的,覺得是可以從action開始看即可,先別去看filter這樣會讓你對這個hook的概念更佳純熟些。

action 簡述

action主要是處理畫面流程上的hook,你想在哪一邊多加上一點畫面,就可以靠著action處理,像是wooCommerce所有的介面,都是可以藉由的action的串接來增加自己所需的頁面。

filter 簡述

而filter是會有回傳值的,反而言之action是不會有任何的回傳值得,而filter主要可以被拿來當計算值,比如大數運算,或者驗證資料等。

Actions 怎麼開始

我們的action的最主流的使用方式就是增加與使用,add_actiondo_action,但我相信你看見do_action的機率應該是add_action的十倍,沒辦法前方的路大神都幫你鋪好了,你只需要找到相對應的程式碼,放上相對應的程式碼,會產出相對應的結果,就是這麼差不多。

add_action

在這個add_action中,最重要的就是第三個priority,我相信不少寫wp的人不少不是學php出身的,像我是從前端來這邊勞作的,而我而言,優先順序就以由大到小,就像是z-index一樣,但在Wordpress中則是恰好相反,數字越小越早被執行,而且設定優先權是可以被允許設定成負數,反之,如果想在該hook全部都被執行結束在執行,使用PHP_INT_MAX來確保你的函式是要最後一個被執行。

而同一個hook是都可以被掛上好幾次funtions的,這就是為何add_action會有優先順序的問題,你可以在觀摩其他人的外掛之中,就會有同一個hook被增加了好幾次,而在寫作的部分,因為同一個hook中有不同的函式被執行,請確保$priority那邊是照著順序排序的,不然如果優先權這麼很亂的話,勢必閱讀性絕對會期差無比,現在我們也來做一個add_action

add_action( 'wp_footer', 'footer_bar', 10 );
 
function footer_bar() {
       echo 'This Page is powered by GOGO POWER RANGER.';
}

do_action

do_action,我認為是一個比較不容易理解的函式,這邊得牽扯到你的add_action第四個參數中設定了多少個參數,而設定好的的參數多寡再來決定他能放上多少參數,不過我是array派系,當初剛寫的時候覺得第二個$arg參數自己是都會轉成$args,但是閱讀性肯定會比較不好,這時候我們需要寫成強型別並且提供interface來,讓函式更加靈活,後來叫了解後,較常使用do_action_ref_array來做那種多個參數的配置。

do_action_ref_array開始使用的時候,其實解決了需要寫很多&$this然後指到自己的class中的mehtod方便很多,不過拉整個instance過去總不是辦法,所以do_action有更容易一點的方式,method自己去bind自身,已做到可以連接到物件,廢話不多說,我們連簡單的使用do_aciton做點應用吧。



add_action( 'wp_footer', 'footer_bar', 10 );
add_action( 'admin_menu', 'add_menu' );

function footer_bar() {
       echo 'This Page is powered by GOGO POWER RANGER.';
}

function add_menu(){
  add_menu(
    'Show footer Page',
    'Show footer',
    'manage_options',
    'show-footer-page',
    'menu_page_displayed'
  );
}

function menu_page_displayed(){
  do_action('wp_footer');
}

我們點進後就可以看見,我們的頁面出現了原本的footer以及我們後來加的powered字樣,我們也可以使用style樣式將它弄得好看一點,這就看個人的口味了。

remove_action

而在主要的action後,你可以藉由remove_action來保證他不會出怪問題,不過要加在哪裡還你得要先有一定的認知,假如你同時有兩個外掛都要remove_action的話,是否衝突呢?又是否要先找到hook的流程在前一個先把原本的刪除掉?這邊會再配合者has_hook來確定是否這個action已經被註冊了才進行刪除。

而如果要臨摹高人是如何寫這些hook,大部分的hook,都在wp-includes/default-filters.php中,可以手動的去研究哪一個action是你需要掛的,而我相信在觀看這些的過程中,你會對於wp的設計有更近一步的了解,hook之間是怎麼運算與他的生命週期,而我們底下的範例程式碼,只要加在上述的menu_page_displayed中,我們所增加的程式碼就不會顯示,當然包含著原生的程式碼也跟著被解除註冊。

remove_action( 'wp_footer', 'footer_bar', 10 );

has_action

這一個hook看字面上的意思,就是來檢查actoin是否被執行過了,我們大部分的設定都可以使用這個功能,來確保remove_action的執行,他就是個比較單純確保你是否有,特別好用可以顯示bool,可以讓邏輯比較一致,而第二個參數平常是false,但如果你有設定函式,回傳的值有機率不是bool,所以務必在接值得部分使用 === 以免因型態問題造成錯誤的結果,不熟悉的話建議不要使用第二個參數。

此外有個與has_action很相近,但是功能是來判斷hook是否被執行過的did_hook,而他的功能很多人會誤以為是判斷hook是否已經執行,更正確的說法是已經執行完畢,不過她比較特別他並不會回傳bool,如果還沒執行它會回傳0,這個使用就要比較小心些,主要會被用在載入結束後的判斷。

if ( has_action( 'wp_footer' ) ) {
       echo '有設定啦';
} else {
       echo '還沒設定過';
}

主流的action

先來說說plugins_loaded這個hook會是主要外掛載入完全後會呼叫的,主要的時程是在wordpress載入所有外掛後,他就會立刻執行,我認為是最適合讓大家都練手的hook了,而在市面上可以看到九成的外掛,都會使用到這個hook來執行自己的設置確保自己的初始化是在正確的生命週期上執行。

而我們第二天提到的regist_activation_hookregist_deactivation_hook現在看來是否更加親切了呢?現在也更能了解在何時該如何加入正確的程式碼,再啟動,與每次開啟外掛的初始化以及停用,讓外掛的正確性更加準確,而放對地方也讓效能會有顯著的提升,不會因為掛太多hook造成變慢。

而最後一個我們講到的事wp_head這個hook,這個是每個頁面渲染前的開始,是在init之後,而這一個hook主要被SEO的外掛拿來放meta-tag,有興趣可以翻翻yoast SEO是怎麼實作加入meta-tag與description的這一塊,我們用個wp_head來做個結尾吧。

<?php
add_action( 'wp_head', 'meta_description' );
 
function meta_description() {
       $description = '';
       if ( is_front_page() ) {
             $description = get_bloginfo( 'description', true );
       } elseif ( is_singular() ) {
             $post = get_queried_object();
             if ( $post->post_excerpt ) {
                    $description = $post->post_excerpt;
             }
       }
       if ( $description ) {
             printf(
                    '<meta name="description" content="%s"/>',
                    esc_attr( wp_strip_all_tags( $description ) )
             );
       }
}

最後提醒到,init其實被很多theme與外掛用得非常的氾濫,如果有比較獨一性的hook的話,建議別使用init,你不知道下一步,有沒有很雷的作者會把init的其他函式給刪除掉,而wp_head還有個會有些人會犯錯,比如說一開始剛學的我,把它拿來call JS,wp有提供更好的方式來引入程式碼,像是wp_enquere_script()是個更好的載入js的hook,如果懶得去看includes的人,Adam R Brown有整理好的hook,可以進他的網站點開來研究。

reference

Wordpress - do_action
WordPress - add_action
WordPress - has_action
Codex - Plugin API/Action Reference
What is: Action
鐵人賽 - 艾瑞克講解 action
How To Use Action Hooks in WordPress


上一篇
「Wordpress 外掛開發」效能調整 Cache Api/Transient API
下一篇
「Wordpress 外掛開發」己也造個hook吧 add_action/add_filter
系列文
Wordpress 外掛開發30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言