wordpressのフックをマスターしてカスタマイズの幅を広げる

wordpressはもともとCMSですが、フックを理解して使いこなせればプラグインを自分仕様にカスタマイズしたり、オリジナルのプラグインを作成して、CMSに留まらないウェブアプリケーション、例を挙げると不動産の検索サイト、SNS、ホテルや美容室などの予約システム、マッチングシステムといったものまで作ることができちゃいます。

つまりwordpressのフックを制すものが世界を制すといっても過言ではないのです!

すいませんそれはさすがに過言ですが、フックを理解して使えるようになれば初級者から中級者にジャンプアップできることは間違いないので、この記事でしっかりフックについて学んでください!

wordpressのフックの種類

wordpressをインストールしてみた方はわかると思うんですが、インストールした直後からもう立派なCMSに仕上がっていてちゃんと動きますよね。そうです、もう出来上がっちゃってるわけです。なのでこの完成品をそのまま使うことももちろんOKなのですが、wordpressはデフォルトの動作を自由にカスタマイズできるポイントをたくさん残してくれています。そうしたカスタマイズポイントがフックだと思ってください。

wordpressのフックには2種類あります。それがフィルターフックとアクションフックです。この違いについて、まずは本家プラグイン API - WordPress Codex 日本語版から引用してみます。

  1. アクション: アクションは、実行中の特定のポイントもしくは特定のイベント発生時に WordPress のコアが起動させるフックです。アクション API を使用して、これらのポイントで実行中の PHP 関数を一つ以上指定することができます。
  2. フィルター: フィルターは、データベースに追加する前やブラウザのスクリーンに送り出す前にさまざまなタイプのテキストを改造するために WordPress が起動させるフックです。プラグインは、フィルター API を使用して、これらのタイミングで特定のタイプのテキストを改造するために一つ以上の PHP 関数の実行を指定することがきます。

今はまだよく分からなくても大丈夫です。現時点で押さえておくべきことは、

  • 共通点:フック(カスタマイズポイント)で実行する関数(コールバック)を用意する
  • 相違点:アクションフックは追加の処理を実行するためのポイント、フィルターフックはテキストを改造するためのポイント

ということです。

フィルターフックとは

フィルターフックとは、デフォルトの動作の途中でテキストを改造するためコールバックを実行するポイントになります。用意されているフィルターフックの探し方は、apply_filters()またはapply_filters_ref_array()がコールされている場所を見付けることです。

例えば、wordpressのテンプレートタグthe_content()を例に見てみましょう。

<?php
// wp-includes/post-template.php
//////  中略 ///////
function the_content( $more_link_text = null, $strip_teaser = false ) {
        $content = get_the_content( $more_link_text, $strip_teaser );

        /**
         * Filters the post content.
         *
         * @since 0.71
         *
         * @param string $content Content of the current post.
         */
        $content = apply_filters( 'the_content', $content );
        $content = str_replace( ']]>', ']]&gt;', $content );
        echo $content;
}

$content = apply_filters( 'the_content', $content )という部分を注目してください。の第一引数'the_content'がフィルターフック名となります。

apply_filters()は、第一引数のフィルターフック名に登録されているコールバック(あとで出てくるadd_filter()で追加された関数)を探し、登録があればそのコールバックを実行し、コールバックが返す値をreturnします。apply_filters()の第二引数(この場合だと$content)が、コールバックに改造を許すテキストです。

フックに関数が登録されていない場合、$contentは改造されずそのままreturnされます。

フックを利用してこの$contentを改造したい場合は以下のようにします。

<?php
add_filter('the_content', 'add_cta_text', 10, 1);
function add_cta_text($content) {
 $content = $content . '文末にCTAを追加してみる';
 return $content;
}

// こう無名関数を使って書いてもいい
add_filter('the_content', function($content) {
 $content = $content . '文末にCTAを追加してみる';
 return $content;
}, 10, 1);

?>

このように、add_filter()という関数を、テーマ内のfunctions.phpとかプラグインとかの適切な場所に書きます。第一引数にはその関数を登録したいフック名を記述し、第二引数には実行させたい関数(コールバック)を与えます。

第二引数のコールバックの引数には、apply_filters()側の第二引数(と、第三引数以降があればそれら)が与えられます。フィルターフックの目的はテキストを改造することと説明しました。なので、上の例のとおり、コールバックは改造後のテキストをreturnする必要があることに注意してください。

このようにしてフィルターフックにコールバックを登録しておくと、apply_filters()が呼ばれた時に登録された関数されます。コールバックはいくつでも登録可能で、複数のコールバックが登録されている場合、add_filter()の第3引数の数字を優先順位にして、順次実行され値が改造されていきます。詳しくはリファレンスをご確認ください。

アクションフックとは

アクションフックとは、任意のコールバックを実行させられるポイントでフィルターフックとよく似た動きをします。用意されているアクションフックの探し方は、do_action()またはdo_action_ref_array()がコールされている場所を見付けることです。

代表的なアクションフック'wp_head'を例にその使い方を見ていきましょう。

wordpressでテーマ開発をやり始めると、

header.phpにはwp_head()を必ず書きましょう

という説明を頻繁に見ると思います。

wp_head()はwp-includes/general-template.phpに定義されていて、その中身はdo_action()をコールするだけです。

<?php
// wp-includes/general-template.php
function wp_head() {
 /**
 * Prints scripts or data in the head tag on the front end.
 *
 * @since 1.5.0
 */
 do_action( 'wp_head' );
}

do_action()の第一引数'wp_head'がアクションフック名です。このアクションフックに、あとで説明するadd_action()で実行させたいコールバックを登録させます。

wordpressはデフォルトでこの'wp_head'に色々なコールバックを登録しているので、テンプレート内でwp_head()を実行しないと登録済みのコールバックたちが実行されず、デフォルトで予定された結果が得られません。なので必ずwp_head()をheader.php(の<head></head>の中)に書きましょうと言われているのです。

ではこのアクションフックに適当なコールバックを登録してみましょう。

<?php
// functions.php
add_action('wp_head', 'add_custom_styles');
function add_custom_styles() {
 echo "<meta name='robots' content='noindex,follow' />\n";
}

// 無名関数を使ってこう書いてもいい
add_action('wp_head', function() {
 echo "<meta name='robots' content='noindex,follow' />\n";
});

add_custom_stylesというコールバックは、noindex, followのメタタグを出力します。このコールバックはwp_head()を実行した場所で、do_action('wp_head')によって実行されます。

フィルターフックとアクションフックの違い

フィルターフックもアクションフックも、コールバックを登録できるポイントという点で非常によく似ています。

実は、add_action()は内部でadd_filter()を呼んでいるだけなので、コールバックの登録に関してはほぼ、どころか完全に一緒なのです!

<?php
// wp-includes/plugin.php#405
function add_action( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) {
 return add_filter( $tag, $function_to_add, $priority, $accepted_args );
}

二つのフックの違いは、コールバックを実行する側apply_filters()do_action()だけです。そしてその違いも単純で、

  • apply_filters()は値をreturnする
  • do_action()returnしない

という違いしかありません。

適切なフックの探し方

wordpressにはこうしたアクションフック、フィルターフックが覚えきれないぐらい用意されています。また、プラグインも独自のフックを用意してくれています。

フックが多いということは、それだけ処理をカスタマイズしてオレオレ仕様にできるということです。どうです、wordpressのカスタマイズ欲が沸いてきましたか?

しかしながら、これだけフックあるとどのフックを使えばいいか迷う時もあります。そんな時に、適切なフックを探す方法をいくつかお知らせします。

ドキュメントを見る

まずは公式を読みましょう。

めちゃくちゃ沢山あるので全部を今理解する必要はありません。逆引き的な感じ使うといいと思います。

関数から辿る

フィルターフックを探す時メインのtipsです。フィルターフックを探すということは何らかの関数の出力を変更したい、というニーズがあるはずです。たとえばthe_content()で本文の内容を変更したい、とか。そうした時は怖がらずthe_content()の定義を確認しに行きましょう。

<?php
// wp-includes/post-template.php#237
function the_content( $more_link_text = null, $strip_teaser = false ) {
 $content = get_the_content( $more_link_text, $strip_teaser );
    
 /**
 * Filters the post content.
 *
 * @since 0.71
 *
 * @param string $content Content of the current post.
 */
 $content = apply_filters( 'the_content', $content );
 $content = str_replace( ']]>', ']]&gt;', $content );
 echo $content;
}

ほらありました。wordpressのコアで用意されているフックには、このようにコメントでアノテーションを付けてくれているので、ぱっと見でどこにフックがあるか分かりやすいです。

アクションフックの実行順序から調べる

アクションフックはフィルターフックよりも当たりをつけるのが難しいです。何かやりたい処理をどこかで実行できればそれでいいので、フィルターフックのように「このフックを使わないとダメ」とは限らないからです。また、やりたい処理の内容によっては、そのアクションフックでは早すぎる、遅すぎる、ということも起こり得ます。

これを理解するにはwordpressのヘッダーがどういう順番で処理されるかを知っておく必要がありますが、かなりマニアックなので、取り合えず「アクションフック 順番」などと検索して、この記事のように誰かがまとめてくれた記事を見て、ここら辺かな、と当たりをつけるといいと思います。

フックでよくあるトラブル

最後に、フックを利用としてよくあるトラブルと確認ポイントをまとめておきます。他のもこんなトラブルがあるよ、という方がいればコメントください。

フィルターフックで値を変更したいけど反映されない!

以下の点を確認してみましょう。

自作のコールバック内でreturnを忘れてませんか?

フィルターフックでは、コールバックでreturnした値が返されます。

フィルターフックと思いきや、アクションフックにコールバックを登録してませんか?

アクションフックは値を返さないため、コールバックでreturnしても無駄です。周辺にapply_filters()がないか探してみましょう。

アクションフックに登録したコールバックが実行されない

コールバックが実行された後にコールバックを登録している

フックを利用するためには、①add_action()でコールバックを登録、②do_action()でコールバックを実行、順番になってないといけません。

しかし、例えばあるフックに登録したコールバックの中で、更にadd_action()する、みたいな処理を書くと、①と②の順番が逆になって実行されない、ということが起こり得ます。

まずは本当にコールバックが呼ばれていないか確認するため、コールバック内でdie('test')などと書いて動作確認してみるのが良いと思います。そして、やはり呼ばれていないということであればdo_action()が過ぎた後にadd_action()している可能性が高いので、アクションフックの実行順序を調べて、もう少し早い場所でadd_action()してみましょう。