Welcart のカスタマイズとフック

メンテナンス性の高いカスタマイズをするには、フック(hook)を使いましょう。
しかし、WordPress が提唱するプラグインAPIであるこのフックは結構(と言うかかなり)とっつき難いものです。
そこで、Welcartをカスタマイズされている方のために、カスタマイズの例などを挙げながらフックの使い方をお話したいと思います。

フックとは何か

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

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

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

2つのフック

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

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

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

apply_filters() の第1引数はフック名です。この場合 usces_filter_bestseller という名前のフックということになります。
第2引数は、何も無ければ表示されるデフォルトのテキストです。
第3引数以降は任意で、ユーザーが必要だろうと思われるデータが設置されています。

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

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

フックがあってユーザー関数がある。では、ユーザー関数はどのようにしてフックに紐付け(フックに引っ掛け)られるのかを見ていきます。

2つの紐付け関数

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


下記のコードは、ベストセラー・ウィジェットのリストを整形するためのコードです。
このコードは、ユーザーが利用中のテーマのフォルダ内にある functios.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;
	$post = get_post($post_id);
	$list = '<li>第' . ($index+1) . '位<a href="' . get_permalink($post_id) . '">' . $post->post_title . '</a></li>';
	return $list;
}

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

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

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

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

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

ユーザー関数

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

$args = func_get_args(); ← 重要!

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

1つしか取得する変数が無い場合はこのようにしても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', 10);
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 をご覧ください。