サードパーティのプラグインの機能を補完するプラグインを書いていて、そのプラグインがある特定のイベントにコールバックが登録されているかどうかを判定する必要があり、そのためのコードを書いた。
登録したコールバックの重複
WordPress では、イベントへのコールバックの登録は、add_action()
もしくは add_filter()
を使う。実は、普通の関数やスタティックのメソッドを登録する場合、既に同じ関数・スタティックメソッドが同プライオリティで登録されている場合は、上書きされ、重複して呼び出されることはない。例えば、
1 2 3 4 5 |
add_action( 'init', 'do_my_stuff' ); add_action( 'init', 'do_my_stuff' ); function do_my_stuff() { // do something } |
としても、do_my_stuff()
は一度しか呼ばれない。しかし、次のように、同じ関数でも、プライオリティが違うと、2度呼ばれる。
1 2 3 4 5 |
add_action( 'init', 'do_my_stuff', 10 ); add_action( 'init', 'do_my_stuff', 20 ); function do_my_stuff() { // do something } |
また、同じメソッドでも、オブジェクトが別インスタンスだと、別メソッド扱いされる。次の例では2回呼ばれる。
1 2 3 4 5 6 7 8 9 10 11 |
class HookTest { public function doMyStuff() { // do something } } $_oHookTest1 = new HookTest; $_oHookTest2 = new HookTest; add_action( 'init', array( $_oHookTest1, 'doMyStuff' ) ); add_action( 'init', array( $_oHookTest2, 'doMyStuff' ) ); |
判定のメソッド
で、そのサードパーティプラグインが、ある特定のフックをかけていないときはかけてね、ということがしたかったので次のクラスを書いた。ユーティリティとしてポータブルに使えればと、スタティックにしてある。
クラス
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
class WPHook_Utility { /** * @param $sHookName * @param callable $cCallable * @param int $iPriority * @return bool */ static public function hasCallback( $sHookName, $cCallable, $iPriority=0 ) { if ( ! is_callable( $cCallable ) ) { return false; } $_oWPHook = self::___getWPHookObject( $sHookName ); if ( ! isset( $_oWPHook->callbacks ) || ( ! $_oWPHook instanceof WP_Hook ) ) { return false; } if ( $iPriority ) { return self::___hasCallbackByPriority( $_oWPHook, $iPriority, $cCallable ); } foreach( $_oWPHook as $_iPriority => $_aCallbacks ) { if ( self::___hasCallbackByPriority( $_oWPHook, $_iPriority, $cCallable ) ) { return true; } } return false; } /** * @param WP_Hook $oWPHook * @param $iPriority * @param callable $cCallable * * @return bool */ static private function ___hasCallbackByPriority( WP_Hook $oWPHook, $iPriority, $cCallable ) { if ( ! isset( $oWPHook->callbacks[ $iPriority ] ) ) { return false; } foreach( $oWPHook->callbacks[ $iPriority ] as $_sName => $_aCallback ) { if ( $_aCallback[ 'function' ] === $cCallable ) { return true; } } return false; } /** * @param $sHookName * * @return bool|WP_Hook */ static private function ___getWPHookObject( $sHookName ) { $_aWPFilters = isset( $GLOBALS[ 'wp_filter' ] ) ? $GLOBALS[ 'wp_filter' ] : array(); return isset( $_aWPFilters[ $sHookName ] ) ? $_aWPFilters[ $sHookName ] : false; } } |
使い方
使い方は、hasCallback()
メソッドにアクション/フィルターフック名、コーラブル、プライオリティを与える。戻り値はブーリアンの true/false
で、判定に使える。プライオリティが省略された場合、プライオリティ毎に登録されているコールバックを順にチェックしていくというデザインにしてある。以下のような感じで使う。クラス名とか適当に変えて使えばよろし。
1 2 3 |
if ( ! WPHook_Utility::hasCallback( 'update_post', 'SomeClass:doSomething' ) ) { add_action( 'update_post', 'SomeClass::doSomething' ); } |
スタティックメソッドだったら、重複しないのだからチェックいらないのでは、という疑問がわくかも知れないが、サードパーティ側でプライオリティに変更を加えた場合に、重複することになるので、それに備えて保険としてチェックはあったほうが良い。
使用条件
- WP_Hook クラスが導入された WordPress 4.7 以降でのみ動作可能。