WordPressのフックシステム特集の第1回『もう開発で苦しまない!「フック」を理解したらWordPressは最強のCMSになる』では、いくつかの動作するコード例とともに、WordPressのフックシステムと2種類のフック(アクションフックとフィルターフック)について学びました。
第2回では、WordPressでイベントをトリガーし、静的クラスと非静的クラスメソッドをアクションフックやフィルターフックにフックさせる別の方法について学びます。
前回の記事ではこのように書きました。
WordPressを使用する際の多様なステップで、大部分の一般的なイベントは、do_action()とapply_filters()というPHPの関数でトリガーします。イベントはadd_action() と add_filter()経由で登録、フックできます。
ここで、「一般的には」という言葉を用いたところに注意してください。というのも、他にもイベントをトリガーする方法があるからです。第2回では、そのあたりを探ってみましょう。
イベントをトリガーする他の方法としては、アクションフック用のdo_action_ref_array()関数、フィルターフック用のapply_filters_ref_array()があります。
do_action()、do_action_ref_array()のペアと、apply_filters()、apply_filters_ref_array()ペアは特定のアクション、フィルターにフックされた関数を実行する点においては同じです。違っているのは引数の指定方法です。
do_action_ref_array()とapply_filters_ref_array()は、do_action()とapply_filters()とは異なり、引数を配列で受け取ります。
これらがどのように機能するのかを理解するために、コードサンプルをいくつか見てみましょう。
コードサンプル
user_profile_update_errorsは、ユーザープロフィール更新時にエラーが返され、プロフィールが更新される前にWordPressが発火するアクションです。
WordPressのユーザープロフィールにカスタムフィールドを加え、WordPressがデータをデータベースに保存する前に入力内容を検証するなら、このフックが最適でしょう。
user_profile_update_errorsは、WordPressコアではこのように定義されています。
/**
* Fires before user profile update errors are returned.
*
* @since 2.8.0
*
* @param WP_Error &$errors WP_Error object, passed by reference.
* @param bool $update Whether this is a user update.
* @param WP_User &$user WP_User object, passed by reference.
*/
do_action_ref_array( 'user_profile_update_errors', array( &$errors, $update, &$user ) );
次のコードは、「city」(ユーザーが現在住んでいる市の名前を書き込む欄)という名前のカスタムプロフィールフィールドが空ではないことを調べます。もし空の場合は、エラーが表示されます。
add_action( 'user_profile_update_errors', function ( $errors, $update, $user ) {
if ( empty( $_POST['city'] ) ) {
$errors->add( 'city_empty', __( 'City field cannot be left empty.' ) );
}
}, 10, 3 );
今度は、apply_filters_ref_array()のコードサンプルを見てみましょう。
下のコードはbbPress内のbp_activity_permalink_redirect_urlフィルターをフックし、シングルアクティビティアイテムに対してリダイレクトが発生する前に、リダイレクト先のURLをhttp://website.com/custom-page/に修正します。
add_filter( 'bp_activity_permalink_redirect_url', function ( $redirect, $activity ) {
$redirect = 'http://website.com/custom-page/';
return $redirect;
}, 10, 2 );
do_action_ref_array()とapply_filters_ref_array()をいつ使うか
他の開発者が拡張可能なプラグインまたはテーマを作るとき、フックされている関数に渡す追加の変数や値が多い場合には、do_action()やapply_filters()よりも、do_action_ref_array()やapply_filters_ref_array()がいいでしょう。
たとえば、ユーザー登録プラグインを作っているとして、ユーザーが有効なユーザー名、メールアドレス、名、姓、住所、市、県、国名を登録し、ユーザー登録が完了した後に発火するアクションフックを定義するとします。do_action()を使うと、コードは次のようになります。
do_action('after_user_registration_completed', $username, $email, $firstname, $lastname, $address, $city, $state, $country);
たくさんの要素のせいでコードが長くなってしまい、見た目が良くありません。上の例と下のdo_action_ref_array()を比べてみましょう。
do_action_ref_array(
'after_user_registration_completed',
array(
$username,
$email,
$firstname,
$lastname,
$address,
$city,
$state,
$country
)
);
アクションフィルターにクラスメソッドをフックするには?
これまでのコードサンプルは、匿名および名前付き関数をアクションフックやフィルターフックにフックする方法でした。
では、WordPressの実行中に処理するために、クラス内でadd_action()とadd_filter()を通じてフックをどう呼び出したり読み込んだりするか、クラスメソッド(静的、非静的)について見ていきましょう。
ほとんどのWordPress開発者は、add_action()とadd_filter()ファンクションコールを、インスタンス上で実行されるclassコンストラクタに含めています。
class DemoPlugin {
public function __construct() {
add_action( 'wp_head', array( $this, 'google_site_verification' ) );
add_filter( 'the_content', array( $this, 'we_love_sitepoint' ) );
}
/**
* Include Google site verification meta tag to WordPress header.
*/
public function google_site_verification() {
echo '<meta name="google-site-verification" content="ytl89rlFsAzH7dWLs_U2mdlivbrr_jgV4Gq7wClHDUJ8" />';
}
/**
* Append and prepend the text "We love SitePoint" to every post content.
*
* @param string $content
*
* @return string
*/
public function we_love_sitepoint( $content ) {
$text = sprintf( '<div class="notice alert">%s</div>', __( 'We love SitePoint', 'sp' ) );
$content = $text . $content . $text;
return $content;
}
}
new DemoPlugin();
上のコードスニペットを見ると、関数そしてクラスメソッドがアクションフックとフィルターフックにフックされる方法に違いがあることが分かります。クラスメソッドではadd_action()とadd_filter()の第2引数が$this(現在のオブジェクトを参照)とメソッド名になっています。
静的メソッドでは、$thisではなくクラス名が使われています。
class DemoPlugin {
public function __construct() {
add_action( 'wp_head', array( 'DemoPlugin', 'google_site_verification' ) );
}
/**
* Include Google site verification meta tag to WordPress header.
*/
public static function google_site_verification() {
echo '';
}
}
new DemoPlugin();
フィルターまたはアクションに対しフックしたいすべての静的メソッドのクラス名を含む上のアプローチは、「don’t repeat yourself (DRY)」原則に反しているのでリファクタリングがさらに大変になってしまいます。
その代わりに宣言されたクラス名を返す定数__CLASS__を使います。
class DemoPlugin {
public function __construct() {
add_action( 'wp_head', array( __CLASS__, 'google_site_verification' ) );
}
// ...
}
new DemoPlugin();
まったくおすすめはできないのですが、静的メソッドをフックに含むもう1つの方法を紹介します。
class DemoPlugin {
public function __construct() {
add_action( 'wp_head', 'DemoPlugin::google_site_verification' );
}
// ...
}
new DemoPlugin();
add_action()とadd_filter()のすべての関数コールをclassコンストラクターに含むのではなく、呼び出しがあったときに静的クラスを作成する開発者もいます。そうすることで、アクションフックまたはフィルターフックにフックされる静的メソッドを初期化あるいは実行します。
class DemoPlugin {
public static function init() {
add_action( 'wp_head', array( __CLASS__, 'google_site_verification' ) );
add_filter( 'the_content', array( __CLASS__, 'we_love_sitepoint' ) );
}
// ...
}
DemoPlugin::init();
この方法では、$thisは静的コンテクストではアクセスできないので、アクションフックとフィルタフックにフックされるすべてのメソッドは静的である必要があります。
最後に
WordPressフック特集の第2回では、アクショントリガーとイベントフィルタリングのもう1つの方法や使うタイミング、そして静的・非静的クラスメソッドをアクションフックやフィルターフックにフックする方法について説明しました。
では、コーディングを楽しんでください!
(原文:Alternative Ways of Triggering Events in WordPress)
[翻訳:加藤由佳]
[編集:Livit]