フィルターフック、アクションフックの利用方法

フックとは何か

WordPress のプラグインAPI は、固定で出力される部分をユーザーが自由に変更できる仕組み(フィルター)と、特定のタイミングで独自の処理をさせる事ができる仕組み(アクション)の2通りの機能を持っています。
しかも、この仕組みは本体を改変することはありませんのでアップグレードをした時に施したカスタマイズが消えてしまうということはありません。

例えば記事タイトルを表示する処理に、ユーザーが作成した処理を割り込ませてタイトルを書き換えてしまったり、記事がデータベースに保存されるタイミングで別の処理を実行させたりと、いろいろな事ができるようになっています。

前もって作った関数を、本体の特定の位置(フック)に引っ掛けておきます。
そこへ処理が流れてきた時にその関数が実行されるという仕組みになっているのです。


2つのフック

  • フィルター・フック apply_filters()・・・・ htmlなどテキストを修正して返すフック
  • アクション・フック do_action() ・・・・ 処理を実行するのみで値は返さないフック



下記のコードは、ベストセラー・ウィジェットのリストを生成しているテンプレートタグusces_list_bestseller() のコードの一部で、フィルター・フックの例です。
このコードは本体に書かれているもので、これを変更してはいけません。

	$htm = "";
	for($i=0; $i<$num; $i++){
		if(isset($ids[$i])){
			$post = get_post($ids[$i]);
			if( !is_object($post) )
				continue;
 
			$disp_text = apply_filters('usces_widget_bestseller_auto_text', esc_html($post->post_title), $ids[$i]);
			$list = "<li><a href='" . get_permalink($ids[$i]) . "'>" . $disp_text . "</a></li>\n";
			$htm .= apply_filters('usces_filter_bestseller', $list, $ids[$i], $i);
		}
	}

apply_filters() の第1引数はフック名です。
この場合 usces_filter_bestseller という名前のフックということになります。
第2引数は、何もなければ表示される内容です。
第3引数以降は任意で、カスタマイズに必要だろうと思われるデータが格納されています。

この apply_filters() は、ユーザー関数がなければ第2引数をそのまま返し、あればユーザー関数の返り値を返すという動きをします。




どうやってフックに引っ掛けるか

フックがあってユーザー関数がある。
では、ユーザー関数はどの様にしてフックに紐付け(フックに引っ掛け)られるのでしょうか。

2つの紐付け関数

  • add_filter() ・・・・ ユーザー関数をフィルター・フックに紐付ける
  • add_action() ・・・・ ユーザー関数をアクション・フックに紐付ける



下記のコードは、ベストセラー・ウィジェットのリストを整形するためのコードです。
このコードは、利用中のテーマのフォルダ内にある functions.php などに記述します。

add_filter('usces_filter_bestseller', 'my_bestseller_func', 10, 3);
function my_bestseller_func() {
	$args = func_get_args();
	list($html, $post_id, $index) = $args;
	$list = '<li>第' . ($index+1) . '位<a href="' . get_permalink($post_id) . '">' . get_the_title($post_id) . '</a></li>';
	return $list;
}

add_filter() が紐付け関数です。

第1引数が引っ掛けるフックの名前です。

第2引数はユーザー関数名です。自由に名前をつけられます。バッティングしないように気をつけてください。

第3引数は優先度です。 このフックを利用するユーザー関数が複数有った場合の優先度です。とりあえず10にしておきましょう。

第4引数はフックから取得できる変数の数です。この引数の必要性があまり感じられないのですが、省略すると1つしか取得できなくなります。ここではフックが3つのデータをユーザーに渡していますので3として全てを受け取れるようにします。


ユーザー関数

フックからのデータを受け取る

$args = func_get_args(); ← 重要!

func_get_args() はフックから送ってくる引数を取得する関数です。

一つしか取得する変数が無い場合はこの様にしてもOKです。

 function my_bestseller_func( $html ) {

受け取ったデータを下にhtml を生成して、最後に return で返します。

このフックがループ内に存在する場合は、global $post; と宣言することでpost オブジェクトが利用できます。
ユーザー関数内で $post->post_title として記事タイトルを取得できます。
get_the_title() でタイトルを取得してもいいですね。
しかし、ここで the_title() は使えません。the_title() はテンプレートタグであり、echo してしまいます。
WP関数 get_the_title() を使うのが正解です。




例)タイトルに飾り付けを

WordPress 本体に、’the_title’ というフィルター・フックが有ります。
これを使って記事タイトルに飾りを付けてみましょう。
ただし、一覧表示のページ(カテゴリーページなど)のタイトルは変更しないこととします。

add_filter('the_title', 'my_title');
function my_title( $title ){
	if( is_singular() && in_the_loop() ){
		$title = '★' . $title;
	}
	return $title;
}

フィルター・フック ‘the_title’ は、テンプレートタグ the_title() に設置されているフックです。
従って、このテンプレートタグでタイトルを表示している部分全てに影響を与えてしまいます。

そのため、is_singular() という条件分岐タグで単体ページだった場合といった条件をつけます。
それでもヘッダーやサイドバーのメニューに★が付いてしまいますので、in_the_loop() で条件をきります。
これで単体ページの記事タイトルだけに★マークが付きます。

条件をつけなかった時にどうなるか実際に確認してみてください。




カスタマイズのコツ

この様に、フックをうまく利用することで自分の思い通りの出力ができるわけですが、使い方は理解しても実際にカスタマイズとなると、何からどう手を付けていいのかピンと来ないかもしれません。
そんな時は次のように整理してみると良いかもしれません。

1. カスタマイズしたい部分はどこに書かれているか
まずはどのファイルのどこに書かれているかを知らなくては始まりません。予想されるキーワードでマルチ検索してコードを探してみましょう。
どうしてもわからない場合は「開発フォーラム」で質問してください。

2. 該当箇所にフックがあるか
フックがあった場合はどんな引数を持っているを確認して、その引数やグローバル変数で自分のやりたい事ができるかどうかを判断しましょう。
フックがない場合は「開発フォーラム」に提案してみましょう。

3. ユーザー関数をどこに設置するか
設置する場所はテーマフォルダ内のfunctions.php になります。
ここでは説明しませんでしたが、カスタマイズの規模が大きい場合は拡張プラグインを作成するほうが管理しやすいでしょう。
プラグインの作成方法はWordPress Codex を参照してください。



カスタマイズは、原則的にフックを利用して行われるべきです。
本体は必ずアップグレードされます。
その中には脆弱性の修正が含まれているかもしれません。
本体を変更することはブランチを作り出すことであり、今後アップグレードができなくなることをクライアントに明確に説明しなくてはいけないでしょう。



参考資料

今回は主にフィルター・フックを例に挙げて説明いたしましたが、アクション・フックもとても便利です。
例えば、アクション・フックを使うと注文完了時に自前のデータベース(テーブル)に独自のデータを記録する、なんてこともできるでしょう。

また紐付け関数も、上に挙げたもの以外に紐付け関係を解消するためのものなどがあります。
興味が有りましたらWordPress Codex プラグインAPI をご覧ください。