WordPressのプラグインやテーマは、コア本体(wp-includes / wp-admin 配下のファイル)を一切書き換えることなく、表示内容やデータの処理に割り込んで動作を変えている。これを可能にしているのが「フック」と呼ばれる仕組みで、大きく action と filter の2種類に分かれる。このブログ自身のテーマ wpmm-blog の functions.php がどちらも多用しているので、実際のコードを題材に整理する。
補足: フック(hook)とは、WordPressコアがあらかじめ用意している「処理の差し込み口」のこと。コア本体のソースコードの特定の位置に、あらかじめ
do_action()やapply_filters()という呼び出しが埋め込まれており、プラグイン・テーマ側はそこに自分の関数を「引っ掛ける(hook する)」ことで、コアの動作に割り込める。
action と filter の役割分担
2種類のフックは、戻り値の有無で役割がはっきり分かれている。
- action: 決まったタイミングで「何かの処理を実行する」。値を受け取っても返す必要はなく、副作用(ログを書く・データを保存する・外部にリクエストを送るなど)を起こすためのフック
- filter: コアが持っている値を「受け取って加工し、返す」。表示直前のデータを書き換えたいときに使う
一言でいえば、actionは「特定の瞬間に割り込んで何かする」、filterは「値そのものを書き換えて返す」という違いがある。名前も覚えやすく、add_action() で登録するか add_filter() で登録するかは、書きたい処理がこのどちらに該当するかで自然に決まる。
filter の実例: 抜粋の文字数と「続きを読む」表記
WordPressコアは記事一覧などで使う抜粋(excerpt)を、デフォルトで55単語に切り詰め、末尾に […] を付ける仕様になっている。この挙動を変えたいとき、コア本体の該当箇所を直接書き換えるのではなく、excerpt_length と excerpt_more という2つのfilterフックに、自分の関数を登録するだけで済む。
if (!function_exists('wpmm_blog_excerpt_length')) {
function wpmm_blog_excerpt_length($length) {
// 日本語環境では「文字数」ではなく「単語数」扱いだが、
// 全角でも適度な長さになるように60単語に設定
return 60;
}
}
add_filter('excerpt_length', 'wpmm_blog_excerpt_length');
if (!function_exists('wpmm_blog_excerpt_more')) {
function wpmm_blog_excerpt_more($more) {
return ' …';
}
}
add_filter('excerpt_more', 'wpmm_blog_excerpt_more');
ポイントは、これらの関数がコア側から渡された「デフォルトの値」を引数として受け取り、加工した値を return で返しているだけという点にある。wpmm_blog_excerpt_length($length) の $length はコアのデフォルト値(55)だが、この実装ではそれを使わずに固定値60を返している。コアの内部処理は、この関数が返した値をそのまま採用して抜粋の長さを決める。
action の実例: 投稿保存時にOGP画像を事前生成する
一方actionの実例として、このブログでは投稿を保存・公開したタイミングでOGP画像を事前生成しキャッシュしておく処理を、save_post というactionフックに登録している。
add_action('save_post', '_wpmm_blog_pregenerate_ogp_on_publish', 10, 3);
add_action() の引数は順に「フック名」「コールバック関数名」「優先度(priority)」「コールバックが受け取る引数の数」となっている。この例では優先度10(デフォルト値)・引数3個を指定している。
save_post は本来、コールバック関数に $post_ID(投稿ID)・$post(投稿オブジェクト)・$update(更新か新規作成かを示す真偽値)の3つを渡せる仕様になっているが、これは「渡せる」だけで、コールバック側で受け取る引数の数を明示しない限りデフォルトでは1つ目しか渡されない。この実装が第4引数に 3 を指定しているのは、コールバック内でこの3つすべてを使うためである。
優先度(priority)が必要な理由
save_post のような主要なフックには、コア自身の内部処理に加えて、有効化されている複数のプラグイン・テーマが同時にコールバックを登録することが珍しくない。すべてのコールバックが同じ優先度(デフォルト10)で登録された場合、実行順は登録された順になるが、「特定の処理の後に必ず実行したい」「他のプラグインより先に割り込みたい」といった要件が出てきたときのために、数値で明示的に順序を制御できるようになっている。数値が小さいほど早く、大きいほど遅く実行される。
プラグイン・テーマがコア本体を書き換えなくて済む理由
WordPress本体のソースコードには、要所要所に do_action('フック名', ...)(actionの発火)や apply_filters('フック名', $value, ...)(filterの適用)という呼び出しがあらかじめ多数埋め込まれている。プラグインやテーマは、この「あらかじめ用意された差し込み口」に対して add_action() / add_filter() でコールバックを登録するだけでよく、コア本体のファイルそのものには一切手を加えない。
これには実務上大きな利点がある。WordPress本体を自動更新・手動更新した際、コアのファイルはまるごと新しいバージョンのものに置き換わる。もし拡張のためにコア本体のファイルを直接編集していたら、その変更は次の更新で確実に上書きされて消える。フックに登録する方式であれば、拡張のコードは wp-content/themes/ や wp-content/plugins/ 配下の別ファイルに独立して存在するため、コアの更新とは無関係に動き続ける。
まとめ
| 種類 | 目的 | 戻り値 | このブログでの実例 |
|---|---|---|---|
| action | 決まったタイミングで処理を実行する | なし(副作用のみ) | save_post → OGP画像の事前生成 |
| filter | コアの値を受け取り加工して返す | 加工後の値 | excerpt_length → 抜粋の単語数を60に変更 |
action と filter という2つの仕組みだけで、WordPressのコア・プラグイン・テーマという3層は、互いのソースコードを直接編集することなく協調できている。新しくWordPressのコードを読むときは、まず「これはadd_actionかadd_filterか」「登録先のフック名は何か」を確認するだけで、そのコードがコアのどの処理に、どんな形で割り込んでいるのかを追いやすくなる。