WebサイトをWordPress(プラグインやテーマの開発も含めて)で作成している人なら、フック、アクションフック、フィルターフックといった言葉を見かけたことがあるかもしれません。これらはすべて、WordPressが使うEvent-driven Architecture Pattern(EDAパターン)の一部です。
WordPressを使ってサイトを作成したことがない、WordPressの基本コンセプトが難しくてわからないといった場合、Simon Codringtonが書いた記事「Introduction to WordPress Plugin Development tutorial」を一度ご覧になることを強くおすすめします。彼はアクションフックやフィルターフックを非常にうまく説明しています。
この記事では、WordPressのフックのすべてを解説します。前置きはこれくらいにして、さっそくはじめましょう。
フック、アクションフック、フィルターフックとは何か?
「フック」はWordPressのコア、テーマ、プラグイン、PHPによる実行または解釈のさまざまな段階における基本的なイベントトリガーです。トリガーによりイベントが発生したとき、すべての関数、またはクラスメソッド、もしくはその両方が、正しい順序で実行されてフックまたはアタッチされます。
フックには、アクションフックとフィルターフックという2通りのフォームがあります。アクションフックはプロセス実行のさまざまな場面で機能を追加したり削除したりするもので、フィルターフックはさまざまな機能や手段の反応を修正します。この段階でまだ理解できなくても心配いりません。これから実際のコード事例を見れば理解できますよ。
WordPressにおけるフックの重要性
WordPressにおけるフックの重要性は、純粋にその拡張性にあります。機能を足したり削除したりできるとともに、WordPressのコア、プラグイン、テーマの機能を実行する際に微調整または修正ができます。
後々拡張できるプラグインやテーマを書いたときに、他の開発者がコアソースコードまで編集することなく、改善したり拡張したりできるようになります。
具体例を見てみましょう。ほとんどの決済システムと違って、私が作成した2Checkout Payment Gateway for WooCommerceプラグインは、使用可能なクレジットカードのアイコンを表示しません。なぜなら、そういうものは不要だと考えたからです。しかし、ユーザーがアイコンを表示したいと思う場合に備えて、filterを付けました。
アイコンを表示してほしいという利用者からの要望がきっかけでした。表示を希望する利用者がフィルターにフックしてアイコンを表示できるようなコードのスニペットを足せるのです。
WordPressのフックシステムをもっと知ろう
WordPressを使用する際の多様なステップで、大部分の一般的なイベントは、do_action()とapply_filters()というPHPの関数でトリガーします。イベントはadd_action() と add_filter()経由で登録、またはフックできます。
ここで、「一般的には」という言葉を用いたところに注意してください。というのも、他にもイベントをトリガーする方法があるからです。第2回では、そのあたりを探ってみましょう。
下に示したのは、プラグインのaction例です。ProfilePressのユーザー登録プラグインでユーザー登録が成功した後、このactionは消去されます。
/**
* Fires after a user registration is completed.
*
* @param int $form_id ID of the registration form.
* @param mixed $user_data array of registered user info.
* @param int $user_id ID of the registered user.
*/
do_action( 'pp_after_registration', $form_id, $user_data, $user_id );
WordPress実行中に、このアクションにフックされた関数はすべて実行されます。
フィルターフックの一例として、WordPressコアのthe_contentが挙げられます。これは投稿されたコンテンツをすべてフィルターするものです。
/**
* Filter the post content.
*
* @since 0.71
*
* @param string $content Content of the current post.
*/
$content = apply_filters( 'the_content', $content );
留意点
do_action()の最初の引数はアクションフックの名称であり、それ以降の引数はアクションをフックさせる変数です。
apply_filters()の最初の引数はフィルターフックの名称で、それ以降の引数は、フィルターにフックされた関数が修正されたり適用されたりする際に使われるデータや値です。続く引数が、フィルターにフックできる関数に使える変数と値です。
心配しないでください。これからコード例を見ていくうちに、すべての意味が分かってきますから。
アクションフックの例
例1
それでは試しに、私が作成したProfilePressプラグインの中のpp_after_registrationというアクションフックを取り上げてみましょう。たとえば、ユーザーがWebサイトに登録した直後にSMSで歓迎のメッセージを送るという関数を追加したいとします(Dolioという所定のメッセージングサービスを経由します)。この関数のフックは、以下のフォームになります。
add_action( 'pp_after_registration', 'send_users_welcome_sms', 20, 3 );
function send_users_welcome_sms( $form_id, $user_data, $user_id ) {
global $service_locator;
$username = $user_data['username'];
$firstName = $user_data['first_name'];
$lastName = $user_data['last_name'];
$phoneNumber = $user_data['phone_number'];
$text = <<<SMS_CONTENT
Hello $firstName $lastName, Welcome to SitePoint. "\r\n"
User ID: $user_id "\r\n"
Username: $username "\r\n"
Password: The password you sign up with "\r\n"
SMS_CONTENT;
$dolio = $service_locator->get( 'dolio_sdk' );
$dolio->phone_number( $phoneNumber );
$dolio->sms_content( $text );
$dolio->send();
}
上記のコード内にあるadd_actionの第3引数で、フックの優先順位を決めます。これによりpp_after_registrationにフックされたアクションが実行される順番が決定されるわけです。この引数が空の場合、デフォルトは10になります。また、第4引数はその関数のフックが受け入れる引数の数を決定します。空の場合のデフォルトは1になります。
第4引数に関しては補足があります。デフォルトを1にしているので、$user_dataと$user_idの変数はnullになります。この関数には、1つの引数のみ受け入れるようにプログラムしてあるからです。
例2
WordPressには、wp_headとwp_footerというactionフックが含まれています。この2つは、フロントエンドのヘッドタグとボディタグの終わる直前をトリガーとします。
これらのフックは、重要な場所でスクリプトとデータを表示するために使われます。
コードの例をいくつか見てみましょう。
下記のコードは、WordPressのフロントエンドのヘッダーに、Googleサイト認証のメタタグを埋め込むためにwp_headを使っている例です。
add_action( 'wp_head', 'google_site_verification' );
function google_site_verification() {
echo '<meta name="google-site-verification" content="ytl89rlFsAzH7dWLs_U2mdlivbrr_jgV4Gq7wClHDUJ8" />';
}
フック関数はすべて、関数名の無駄な繰り返しを避けるために空欄を使います。たとえば、上記のGoogleサイト認証のメタタグは、この後からは以下のように空欄になります。
add_action( 'wp_head', function () {
echo '<meta name="google-site-verification" content="ytl89rlFsAzH7dWLs_U2mdlivbrr_jgV4Gq7wClHDUJ8" />';
});
下記のコードでは、WordPressのフロントエンドのフッターエリアにJavaScriptを付け足すためにwp_footerが使われています。
add_action( 'wp_footer', function () {
echo '<script type="text/javascript" src="http://example.com/wp-content/plugins/site-specific-plugin/hello-bar.js"></script>';
});
アクションフックコードの例はこれくらいで十分でしょう。次にフィルターフックを見てみましょう。
フィルターフックの例
例1
たとえば、すべての投稿コンテンツの前後に自動的に広告を挿入するad inserterプラグインを使う場合、the_contentフィルターが必要になります。
以下のコードでは、すべての投稿コンテンツの始めと終わりに、’We love SitePoint’という文字が足されます。
add_filter( 'the_content',
function ( $content ) {
$text = sprintf( '<div class="notice alert">%s</div>', __( 'We love SitePoint', 'sp' ) );
$content = $text . $content . $text;
return $content;
});
コードの説明:$text変数のコンテンツは、<div class="notice alert">We love SitePoint</div>と同じになります。グローバライズされてはいますが、それは後でローカライズできるようにするためです。混乱した場合は、私の記事WordPress i18nとl10nを参照してください。
念のために書きますが、関数の引数である$contentは、投稿コンテンツをアップするための変数です。投稿コンテンツの前後に固有の文字列を追加し、そのデータを$contentに保存してから戻します。
メモ:すべてのfilterフック関数は、操作や修正の後、変数パラメーターを戻す必要があります。
例2
続いてもう1つのフィルターの例は、the_titleです。下のコードはwp-includes/post-template.phpの158行目でどのように定義されているかを示しています。
/**
* Filter the post title.
*
* @since 0.71
*
* @param string $title The post title.
* @param int $id The post ID.
*/
return apply_filters( 'the_title', $title, $id );
次のコードは、ID 5978の投稿タイトルだけに、- WeLoveSitePointを足すためのものです。これができるのは、$id引数のおかげです。
add_filter( 'the_title', function ( $title, $id ) {
if ( $id == '5978' ) {
$title .= ' - WeLoveSitePoint';
}
return $title;
}, 10, 2
);
まとめ
WordPressが、最高のコンテンツマネジメントシステムであリ続けている理由は、その拡張性にあります。
WordPressは、フックのおかげで、パワフルなWebアプリケーションに大変身しました。WooCommerceを使ったEコマースストアであろうと、bbPressを使ったフォーラムであろうと、はたまたBuddyPressを使ったソーシャルネットワーキングサイトですら、このフックシステムのおかげなのです。
この記事の第2部では、WordPressのフックに関する、クールなのにあまり知られていないことを取り上げたいと思います。たとえば、クラスの中でフックを使うためのアクションフックやフィルターフックの、静的または動的なメソッドについてです。それから、名前空間、注意事項、解決策その他諸々です。続けてお付き合いいただき、コーディングを楽しみましょう。
(原文:Demystifying the WordPress Hook System)
[翻訳:島田理彩]
[編集:Livit]