iT邦幫忙

第 12 屆 iT 邦幫忙鐵人賽

DAY 9
1
自我挑戰組

Wordpress 外掛開發系列 第 9

「Wordpress 外掛開發」己也造個hook吧 add_action/add_filter

建立自己的filter

延續上一張沒有講完的,filter其實與action大同小異,但是filter在使用的時候,是會有值經過filtered,這也讓所有的filter在使用時,會將處理過的值回傳,而九成的filter使用方式與action大同小異,甚至是array那些的都是差不多的,所以我們就跳過apply_filteradd_filter,我們用一段示範如何使用add_filter來當快速的概論。

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

current_filter()

這個函式是可以回傳當下執行的filter名稱,如果你有遇到一個hook有掛上非常多的filter的話,這個很適合來確定現在的處理狀況,假設你想學學阿共把一些字眼消失掉的話,我們也可以使用使用這個功能來做到。

add_filter('the_content','ccp_like_nofrex');
add_filter('the_title','ccp_like_nofrex');
function ccp_like_nofrex( $text ) {
 
       $words = [];
 
       if ( 'the_content' === current_filter() ) {
             $words = ['free'];
       }else if( current_filter() === ' the_title')$words = ['ccp'];
 
       if ( $words ) {
             $text = str_replace( $words, 'none', $text );
       }
 
       return $text;
}

也是有一點語法糖

wordpress提供了這幾種的語法糖,不只是向其他能夠使用FIOE,他提供的是假設你今天是要清空預設的資料,像是非使用者要來要資料,你可以利用以下清單的來中家做回傳,而不在需要再多註冊一個新的function,讓程式碼看了更冗長,而下面的的選項你會發現有兩個底線,這是個wordpress的簡潔回傳的特別記號,很好讓去辨識,你也可以看到在core中有很多這種使用方式!

__return_true(): 回傳 bool true
__return_false(): 回傳 bool false
__return_zero(): 回傳Integer 0
__return_empty_array(): 回傳空陣列
__return_null(): 回傳null
__return_empty_string(): 回傳一個空字串 ""

add_filter( 'the_content', '__return_empty_string' );

私藏好用hook給大家 the_content

看了我們上面的範例,可以看到這個對--思想控制--過濾內容是特別好用的,想想看那些x週刊說要加入會員才能看見,不就可以藉由這個來製作,再搭配transients來確保他們沒有偷輕快取,做到一週只能看幾次,跟某xxxxtube一樣的高度呀!我們可以做一個簡單的應用,火傳媒的訂閱功能,不過沒有要鎖別人的內容就只是求訂閱而已,如果再加上cookie的設定,就可以變成會員限定了,至於email的部分,自己動手做一下就可以啦!

add_filter( 'the_content', 'gogo_power_ranger_content_subscription_form', PHP_INT_MAX );
 
function gogo_power_ranger_content_subscription_form( $content ) {
       if ( is_singular( 'post' ) && in_the_loop() ) {
             $content .= '<div class="subscription">
                    <p>感謝閱讀火傳媒的文章,你的訂閱,讓新聞像火依樣,照耀著你的霧氣.</p>
                    <form method="post" action="自己寫">
                          <p>
                                 <label>
                                        Email:
                                        <input type="email" value=""/>
                                 </label>
                          </p>
                          <p>
                                 <input type="submit" value="Submit"/>
                          </p>
                    </form>
             </div>';
       }
       return $content;
}

template_include

這一個是能偵測模板是否已經被呼叫了,而且在registed了,怎麼用?看下來,我們假設有一個新的模板叫做protfolio,並且假設他已經被註冊了。

add_filter( 'template_include', 'portfolio_page_template', 99 );
function portfolio_page_template( $template ) {
    if ( is_page( 'portfolio' )  ) {
        $new_template = locate_template( array( 'portfolio-page-template.php' ) );
        if ( '' != $new_template ) {
            return $new_template ;
        }
    }
    return $template;
}

將Hook建立得OOP話,探討class

當你想要增加filter與action到你的class之中,與原本你只需要reference到你自己的function不同,你所需要使用的語法就不同,我們使用的參數會需要我們以下的帶入方式,來確保我們class中的method被執行,並且reference到你的class,而我們的規則就是用個陣列將其包起,這邊把add_action換成add_filter也是同理,而如果你有更多的參數,就是以[$class,$method]的方式繼續增加。

add_action($tag , [$class,$method]);

此例提示拿之前的boot來當例題,並且將class的method加入進filter裡頭,而就算你要在class中增加filter,也是一樣的方式,只是把class改成$this,讓在存取的當下指到正確的reference。

<?php
namespace gogo_power_ranger;
 
class Gym {
      public static function init(){
        add_filter('the_content',array($this,'gogo_power_ranger_content_subscription_form'))
      }
 
       public static function randomize( $query ) {
 
             if ( $query->is_main_query() && $query->is_home() ) {
                    $query->set( 'orderby', 'rand' );
             }
       }

       public function gogo_power_ranger_content_subscription_form( $content ) {
       if ( is_singular( 'post' ) && in_the_loop() ) {
             $content .= '<div class="subscription">
                    <p>感謝閱讀火傳媒的文章,你的訂閱,讓新聞像火依樣,照耀著你的霧氣.</p>
                    <form method="post" action="自己寫">
                          <p>
                                 <label>
                                        Email:
                                        <input type="email" value=""/>
                                 </label>
                          </p>
                          <p>
                                 <input type="submit" value="Submit"/>
                          </p>
                    </form>
             </div>';
       }
       return $content;
      }
}
 
add_action( 'pre_get_posts', [ 'gogo_power_ranger\Gym', 'randomize' ] );

建立自己的虎克,就像woocommerce一樣

Wordpress中並沒有限制增加多少hooks,也沒有限制一個hook能夠接上多少個function,我們從上述的主要兩個之中,我們可以使用do_actionapply_filters來放入我們相對應的位置,就像core提供給我們一樣,我們也提供給其他要修改我們外掛的人更大的彈性,使用自己的hook好處多多,最大的好處是在hook這種外掛的生態系上,別人的開發邏輯都是掛上適當的hook來讓自己的外掛保有可變性,假如你是個開源軟體,你希望自己的外掛能夠讓更多的開發者去做開源,進而讓你的外掛像是以一灘活水的方式繼續在生態圈流淌,那麼你需要的是好好坐下來看看,評估哪一段程式碼該加入hook,讓其餘人直接使用就可以加上。

而適當的使用filter來做一些值得回傳,更可以讓使用者更容易地去理解,你的功能是否有很好的匹配性,去與其他的程式碼做支援,而這個議題也是個很重要的開源想法,你在開發自己的外掛時,哪些資料是可以被允許add_filter的,又有哪些是的算寫在action只有提取,避開讓人直接去修改的,是個大哉問!我們拿Wp的範例來說說,我們自己加了這一個filter。

add_action( 'init', 'hook_init' );
 
function hook_init() {
       do_action( 'gogo_power_ranger_init_before' );
       // Run setup code.
       do_action( 'gogo_power_ranger_init_after' );
}

do_action('gogo_power_ranger_init_before');
do_action('gogo_power_ranger_init_after');

造個飛機耍耍,找個戶可打打

我們有上面的基礎,現在我們要自己掛一個hook來使用,設定你要使用的位置,再來設計你該怎麼實作以及註冊,可以看見下方的用法,我們還要確保我們的獨一性加上自己的前綴。

function shown_text() {
       $text = apply_filters(
             'ranger_example_text',
             'ppap',
       );
       echo $text;
}

add_filter( 'ranger_example_text', 'gogo_power_ranger_replace_text',10,1);

function gogo_power_ranger_replace_text($text){
  return $text." powered by gogo power ranger";
}

變數掛進hook - Variable Hook

變數hook,這是個比較有趣也比較有效能的使用,但是加入的方式可能,這個範例使用了post_type來做到每個type有不同的hook,而這個其實對於reuse有很大的好處就可以由此可知,wordpress在core中也是有很多的varirable hook,這些可以讓使用在相對應的情況之下,使用到正確的hook,就如同我們下方的post來當作練手,可以針對不同的形態來做,而在不同的型別中,執行不同的hook與相對應的的資料做處理,也是一個在效能調校上,如果current_filter有太多太多的選擇項的最好替代方案。

do_action( "save_post_{$post->post_type}", $post->ID, $post, true );

Plugin Api 相信是最重要也是最容易的環節了,也是大家比較熟悉的部分,想想試著要去建立的pluigin不管內容複雜與否總是有hook牽扯上非常多的關係,不過既是最容易也就是難去精深的,多看多懂才是王道,source code這種東西,一定是重複看的次數多了,心得才多,就跟當時張無忌在悟得乾坤大挪移的時候,霹哩啪拉一頭熱的練功。

本來預計明天開始來講前端的資源要怎麼匯入到我們的外掛之中,那還有作用域之類的概念與polyfills,並且提到該怎麽處理前端頁面舊資料快取的問題,不過我思索了一下想先講一下Privacy在處理一些個人資料與訪客資料的利用,感覺更可以讓剛學玩hook有更好的發揮,此外,我在這邊也推薦找到了一個youtube 也是在講解程式的頻道,裡頭有一個playlist是講了60幾章,開發wordpress外掛的教學影片,有興趣可以點擊這裡觀看

reference

wordpress - template_include
wordpress - API/Action Reference
鐵人賽 - 艾瑞克講解 filter
Julio Potier
Using add_filter inside another class
WordPress Actions, Filters, and Hooks : A guide for non-developers


上一篇
「Wordpress 外掛開發」Worpdress 的核心鉤子 Hook - action
下一篇
「Wordpress 外掛開發」個人隱私
系列文
Wordpress 外掛開發30

尚未有邦友留言

立即登入留言