ホームページ制作でWordPressのテーマを作っていると、functions.phpadd_actionadd_filter を使うことがよくあると思います。テーマをよりカスタマイズしたりプラグインを制作したりすると、このあたりをしっかり理解するというのは避けて通れません。言い方を変えると、アクションフックやフィルターフックを使いこなせるようになると WordPress のカスタマイズの幅が劇的に広がります。ということでここではアクションフックとフィルターフックについてみていきます。

主要なアクションフック

テンプレート表示時に有用なアクションフック

テーマのテンプレートが表示されるページで主に使用されるアクションフックの一覧です。およそ実行される順番になっていますが、テンプレート内でのループの場所や get_sidebar 関数の呼び出し場所によっては若干前後します。
アクションフックとフックする関数がもつ引数 説明
muplugins_loaded コアプラグインとネットワークで有効化されたプラグインが読み込まれた後に呼び出される
plugins_loaded 有効化されているプラグインがすべて読み込まれた直後に呼び出されるプラグインが制御できるアクションフックの中で最初に使用できるフック のため、プラグインのフィルターセットアップやプラグインの上書きに使用される。
setup_theme テーマが読み込まれる前に呼び出される。テーマの functions.php が読み込まれる前なので、まだテーマからは制御できない。
after_setup_theme テーマが読み込まれた後に呼び出されるテーマが利用できる最初のアクションフックとなり、テーマの functions.php が読み込まれた直後に呼び出される。 add_theme_support はここで呼ばれるべき。
registered_post_type post, page, attachment, revision などWordPress内で使用できる投稿タイプが登録された後に呼び出される
registered_taxonomy
@param string $taxonomy
@param array/string $object_type
@param array/string $args
categorypost_tag などのタクソノミーが登録された後に呼び出される
wp_default_scripts スクリプトを登録するコアクラス WP_Scripts がインスタンス化されると呼び出される
init WordPress の読み込みが完了すると呼び出される。この段階でユーザーに対する認証は完了している。WP を含めすべてのプラグインとテーマはまだ完全には読み込まれていないため、wp_loaded の方がより使いやすい。
wp_loaded WordPress本体とすべてのプラグイン、使用中のテーマが読み込まれて初期化された後に呼び出される
parse_request
$param WP $query
現在のリクエストに対してすべてのクエリ変数がパースされた後に呼び出される
send_headers WordPressのメイン関数 wp基本的な HTTP ヘッダーが送られた後に呼び出される。HTTP レスポンスにヘッダーを追加する場合に利用することができる。
parse_query
@param WP_Query $wp_query
メインクエリのパースが完了したときに呼び出される。メインクエリをはじめ、WP_Query クラスのインスタンスを生成した際にも呼び出される。
pre_get_posts
@param WP_Query $query
クエリ変数オブジェクトが生成されたときに呼び出される。クエリ変数は用意されているのでその中身を見ることはできるが、実際にクエリは実行されていないので、投稿情報はもっていない。
posts_selection
@param string $query
データベースから投稿を取得するための選択クエリが準備できたときに呼び出される。投稿情報はまだ取得されていないため、グローバル変数 $post はまだセットされていない。
wp
@param WP $wp
WP オブジェクトがセットアップされた後に呼び出されるWP オブジェクトがセットアップされた、つまり投稿情報が取得された後なので、グローバル変数である $post にオブジェクトがセットされている。そのため、is_page()is_front_page() などの関数をはじめ、$post->ID からあらゆる投稿情報を取得できる状態になっている。 テンプレートを表示する前に投稿情報に応じて何か処理をする必要がある場合は、この wp アクションフックを利用する。
template_redirect どのテンプレートを読み込むかを決定する前に呼び出される
get_header
@param string $name
テンプレート内で get_header 関数でヘッダーテンプレートを読み込む前に実行される
wp_enqueue_scripts テンプレート内で wp_head 関数が呼び出されるときに実行されるwp-includes/default-filters.php 内で wp_headフックに優先度 1 として登録されている。
wp_print_styles テンプレート内で wp_head 関数が呼び出されるときに実行されるWordPress 3.3以降は非推奨とされ、代わりに wp_enqueue_scripts が推奨されているwp-includes/default-filters.php 内で wp_headフックに優先度 8 として登録されている。
wp_print_scripts テンプレート内で wp_head 関数が呼び出されるときに実行されるWordPress 3.3以降は非推奨とされ、代わりに wp_enqueue_scripts が推奨されているwp-includes/default-filters.php 内で wp_headフックに優先度 9 として登録されている
wp_head テンプレート内でwp_head 関数が呼び出されるときに実行される。一般的に wp_headhead 要素内で呼び出されるため、head 要素に何か出力する際に使われる。
loop_start WordPressのループの最初の投稿が処理される前、つまり while ( have_post() ) ループ内の the_post が最初の投稿に対して実行される前に呼び出される
the_post
@param WP_Post $post
ループ内でthe_post 関数が呼び出されたときに実行される
loop_end WordPressのループの最後の投稿が処理された後に呼び出される
get_sidebar テンプレート内でget_sidebar 関数でサイドバーテンプレートを読み込む前に実行される
get_footer
@param string $name
テンプレート内でget_footer 関数でフッターテンプレートを読み込む前に実行される
wp_footer テンプレート内でwp_footer 関数が呼び出されるときに実行される
wp_print_footer_scripts テンプレート内で wp_footer 関数が呼び出されるときに実行されるwp-includes/default-filters.phpwp_footer フックに優先度 20 として登録されている。footer にスタイル/スクリプトを注入する場合に使用される。
shutdown PHPの実行が終わる直前に実行される
アクションフックを時系列に見ていくと、WordPressが
  1. 有効化されたプラグインの読み込み
  2. 現在のテーマの読み込み
  3. クエリ生成
  4. データベースから投稿情報を取得
  5. テンプレートファイルの読み込み
という流れで動いていることが分かると思います。WordPress ではページが表示されるまでに様々なアクションがトリガーされるため、それらのアクションをフックすることで適切なタイミングに任意の処理を追加することができます。

管理画面で有用なアクションフック

次は主に管理画面で有用なアクションフックです。まずは画面が表示されるまでを時系列に並べたものです。テンプレート側と共通なものは説明を省いています。
アクションフックとフックする関数がもつ引数 説明
plugins_loaded
setup_theme
after_setup_theme
registered_post_type
registered_taxonomy
wp_default_scripts
init
wp_loaded
admin_menu 管理メニューが読み込まれる前に呼び出される。サブメニューの追加などに使われる。
current_screen
@param WP_Screen $current_screen
現在の画面がセットされた後で呼び出される。管理画面のどのページが読み込まれるかの情報にアクセスできるようになる。
parse_request
send_headers
parse_query
pre_get_posts
posts_selection
wp
add_meta_boxes
@param string $post_type
@param Post $post
投稿の編集ページでビルトインのすべてのメタボックスが追加された後に呼び出されるadd_meta_box 関数を使用した meta box の登録に使用される。
add_meta_boxes_{post_type}
@param Post $post
add_meta_boxes を投稿タイプで限定したもの
admin_enqueue_scripts
@param string $hook_suffix
管理画面に CSS/JavaScript を注入するために使用されます
admin_print_styles 非推奨。代わりに admin_enqueue_scripts を使う。
admin_print_scripts 非推奨。代わりに admin_enqueue_scripts を使う。
manage_posts_custom_column
@param string $column_name
@param int $post_id
投稿一覧のテーブルの各カラムで呼び出されるmanage_{$post_type}_posts_columns フィルターと同時に使用することで、投稿一覧のテーブルにカラムを追加・削除することができる。
manage_${post_type}_posts_custom_column
@param string $column_name
@param int $post_id
カスタム投稿一覧のテーブルのカスタムカラムで出力させる値がある場合に呼び出されるmanage_{$post_type}_posts_columns フィルターと同時に使用することで、カスタム投稿一覧のテーブルにカラムを追加・削除することができる。
上記以外にもこのようなアクションフックがあります:
アクションフックとフックする関数がもつ引数 説明
activate_PLUGINNAME プラグインが有効化されたときに呼び出される。同じ処理を行う register_activation_hook 関数を利用することが推奨されている。 
switch_theme
@param string $new_name
@param WP_Theme $new_theme
@param WP_Theme $old_theme
テーマが切り替えられた直後に呼び出される。無効化されたテーマでフック可能になる。テーマが無効化された場合に行う処理はこのアクションにフックさせる。
after_switch_theme
@param string $old_name
@param WP_Theme $old_theme
テーマが切り替えられた直後に呼び出される。有効化されたテーマとその子テーマでフック可能になる。
wp_restore_post_revision
@param int $post_id
@param int $revision_id
投稿のリビジョンが復元された後に呼び出される
wp_insert_post
@param int $post_ID
@param WP_Post $post
@param bool $update
投稿が保存されると呼び出される。投稿編集画面や wp_insert_post 関数の呼び出しでもアクションがトリガーされる
updated_{$meta_type}_meta
@param int $meta_id
@param int $object_id
@param string $meta_key
@param mixed $meta_value
投稿のメタデータが更新された直後に呼び出される
rest_api_init
@param WP_REST_Server $wp_rest_server
WP_REST_Server インスタンスの生成後に呼び出される。REST エンドポイントオブジェクトが生成されているため、エンドポイントの追加などを行う際にフックされる。
すべてのアクションフックのリストはここで確認できます。

主要なフィルターフック

テンプレート表示で有用なフィルターフック

WordPress テーマを制作する際に必要になるであろうフィルターフックの一覧です。the_titlethe_content など、テーマのテンプレート内で使用する関数には大抵フィルターフックが用意されています。
フック名とフックする関数がもつ引数 説明
document_title_separator
@param string $sep
title要素で出力するタイトルのセパレーターをフィルターする
document_title_parts
@param array $title
title要素で出力するタイトルをフィルターする
wp_title
@param string $title
@param string $sep
@param string $seplocation
wp_title 関数でtitle要素に出力するページタイトルをフィルターする
body_class
@param array $classes
body要素に付与するクラスをフィルターするget_body_class 関数で呼ばれる。
the_title
@param string $title
@param int $id
投稿タイトルをフィルターする
get_the_excerpt
@param string $excerpt
get_the_excerpt 関数で取得できる抜粋をフィルターする
the_excerpt
@param string $excerpt
the_excerpt 関数で表示される抜粋をフィルターする
excerpt_length
@param int $length
抜粋の文字数をフィルターする
excerpt_more
@param string $more
抜粋の後に表示される「続きを読む」の文言をフィルターする
the_content
@param string $content
投稿本文をフィルターする
post_thumbnail_html
@param string $html
@param int $post_id
@param int $post_thumbnail_id
@param string/array $size
@param string $attr
投稿のアイキャッチ画像のHTMLをフィルターする
wp_list_pages
@param string $output
@param array $r
array $pages
wp_list_pages 関数で出力するページリストのHTMLをフィルターする
rest_allow_anonymous_comments
@param bool $allow_anonymous
ユーザー認証なしにコメントを残せるかをフィルターする
wp_mail_content_type
wp_mail_from_name
rest_pre_serve_request HTTP リクエストがすでに提供されているかどうかをフィルターする。HTTP リクエストを手動で送ることができる。wp-includes/rest-api.php では CORSヘッダーを送信するための rest_send_cors_headers 関数がフックされている。

管理画面で有用なフィルターフック

主に管理画面で使用するフィルターフックには次のようなものがあります。
フック名 説明
wp_insert_post_data wp_insert_post 関数で投稿がデータベースへ保存される直前のフィルター
content_save_pre
@param string $content
@param int $post_id
投稿内容をデータベースへする保存前にサニタイズすることができるフィルター。
image_send_to_editor
@param string $html
@param int $id
@param string $caption
@param string $title
@param string $align
@param string $url
@param string/array $size
@param string $alt
投稿編集時の「メディアを追加」で追加される画像のHTMLマークアップをフィルターする
manage_posts_columns
@param array $columns
投稿一覧のテーブルで表示されるカラムをフィルターする
manage_{$post_type}_posts_columns
@param array $columns
カスタム投稿一覧のテーブルで表示されるカラムをフィルターする
manage_{$this->screen->id}_sortable_columns 投稿一覧テーブルのソート可能なカラムをフィルターする。カスタムフィールドを一覧でソート可能にするために使用される。
show_admin_bar
@param bool $show_admin_bar
管理バーを表示するかどうかをフィルターする
rest_pre_serve_request
@param bool $served
@param WP_HTTP_Response $result
@param WP_REST_Request $request
@param WP_REST_Server $this
API へのリクエストがすでに送られたかどうかをフィルターする
user_can_richedit
@param bool $wp_rich_edit
ユーザーがヴィジュアルエディタを利用できるかどうかをフィルターする
template_include
@param string $template
テンプレート読み込み時のパスをフィルターする
is_protected_meta カスタムフィールドが保護されているか(編集画面に表示されるか)をフィルターする
すべてのフィルターフックのリストはここで確認できます。

フィルター/アクション/フックについて

Codexにはこのように書いてあります:
WordPress はプラグインを WordPress 本体に “引っ張り込む (hook into)” ためのフックを提供しています。これはつまり、特定のタイミングでプラグインの関数を呼び出したり、それによってプラグインを作動させたりするためのものです。フックには次の2種類があります:
  1. アクション: アクションは、実行中の特定のポイントもしくは特定のイベント発生時に WordPress のコアが起動させるフックです。アクション API を使用して、これらのポイントで実行中の PHP 関数を一つ以上指定することができます。
  2. フィルター: フィルターは、データベースに追加する前やブラウザのスクリーンに送り出す前にさまざまなタイプのテキストを改造するために WordPress が起動させるフックです。プラグインは、フィルター API を使用して、これらのタイミングで特定のタイプのテキストを改造するために一つ以上の PHP 関数の実行を指定することがきます。

場合によっては、アクションとフィルターのどちらでも同じ目的を達成することができます。例えば、プラグインに投稿のテキストを変更させるには、publish_post にアクション関数を追加してもいいですし(これにより、この投稿はデータベース保存時に変更されます)、the_content にフィルター関数を追加してもかまいません(これにより、この投稿はブラウザに表示されるときに変更されます)。

フィルターは、実行中の特定のポイント、データに何かのアクション(データベースへの追加やブラウザスクリーンに送り出すなど)を行なう前にデータが通過する関数です。フィルターはデータベースとブラウザの間に位置し(WordPress がページを生成するとき)、ブラウザとデータベースの間にも位置します(WordPress が新しい投稿やコメントをデータベースに追加するとき)。WordPress のほとんど入力と出力は最低ひとつはフィルターを通過します。WordPress はデフォルトでいくつかのフィルタリングを行なっていて、プラグインで追加することができます。

アクションは、WordPress で発生する特定のイベント、例えば投稿の公開、テーマの変更、管理画面の表示などによって始動させらせます。プラグインは PHP 関数を実行することによってこのイベントに反応することができます。このイベントへの反応には次のようなものがあります:
・データベースのデータの変更
・メールメッセージの送信
・ブラウザ画面(管理画面もしくは読者が閲覧する画面)に表示する項目の変更

フィルターフック

フィルターはその名の通り、WordPress本体やプラグインが何かを出力したり何かを操作したりする際に、その出力や操作に手を加えることができるものです。wp-includeswp-adminapply_filters を検索すると
$content = apply_filters( 'the_content', get_the_content() );
の様なコードがたくさん見つかると思います。例えば上の例の場合は get_the_content 関数を実行した結果を、そのまま $content 変数に入れずにフィルターを通してから変数に代入しています。もし the_content フィルターにフックされている関数がなければ、これは
$content = get_the_content();
を実行しているのと同じになります。テーマの functions.phpadd_filter( 'the_content', 'my_function' ) のようにして関数を登録したりしますが、この my_functionapply_filters の中で呼び出されて実行される関数ということになります。フィルターにフックされている関数がない場合のコードをみてわかるように、add_filter で登録する関数では、引数と戻り値は同じ型でなければいけません。言い換えると、add_filter引数と同じ型の戻り値をもちます。

アクションフック

一方のアクションフックは少し違います。こちらも wp-includeswp-admindo_action を検索すると
do_action( 'wp_head' );
の様なコードが引っかかります。do_action は第2引数を持つこともあります。フィルターとの決定的な違いはその呼ばれ方です。apply_filters は必ず戻り値があってそれを変数に代入したりその値を return したりしますが、do_action の場合は戻り値が使われることはありません。 add_action で関数をフックさせると、同じフック名の do_action でその関数が実行されます。何かのイベント発生時に追加の処理を行うような場合にアクションフックが使われます。投稿を公開すると同時にSNSに投稿する場合などはこのアクションフックを利用しています。

ソースコード上の違い

アクションフックに関数を登録する add_action ですが、実は中身は add_filter と同じです。これはCodexにも
この関数は add_filter() のエイリアスです。
と書かれており、wp-includes/plugins.php を見ると と、ただ add_filter の実行結果を返しているだけの関数になっています。add_filter 関数では のように WordPress のグローバル変数である $wp_filter 配列にフック名を index とした WP_Hook クラスのインスタンスを追加しています。つまり add_action でも add_filter でも、$wp_filter 配列に WP_Hook クラスのインスタンスを追加するということをしています。
登録/フックした関数を呼び出す do_actionapply_filters もほとんど同じです。do_action では最後に
$wp_filter[ $tag ]->do_action( $args );
のように $wp_filter 配列に登録したフックの do_action メソッドを実行しているだけですが、apply_filters では
$filtered = $wp_filter[ $tag ]->apply_filters( $value, $args );
...
return $filtered;
のように、WP_Hook クラスのメソッド apply_filters を実行して、返り値を return しています。ここでの違いは WP_Hook クラスのメソッド do_action を呼ぶか apply_filters を呼ぶか、呼んだ後に返り値を戻すかどうかになります。では次に do_action メソッドと apply_filters メソッドをみてみます。
WP_Hook クラスは wp-includes/class-wp-hook.php で定義されています。ここの do_action メソッドは となっていて、apply_filters メソッドを呼び出しています。追加でやっているのは apply_filters を実行中に doing_action というフラグを立てていることだけです。
apply_filters メソッドはこうなっています: フックされた関数がなければ第1引数を返し、関数がフックされて入れば add_actionadd_filter で指定したプライオリティの順番に登録された関数を実行して、最後に得られた値を return しています。add_action, add_filter, do_action, apply_filters に関するソースコードはこれだけです。

add_action と add_filter の使い分け

ソースコードを見てわかるのは、add_action で登録した関数は apply_filters で実行されることもあるし、add_filter で登録した関数は do_action されているところで実行することができる、ということです。 例えばWordPressによる自動タイトル出力をする際に、セパレーターを変更するために
add_filter( 'document_title_separator', function( $sep ) {
    return '|';
} );
のように document_title_separator フックに関数を登録することがあります(ここでは簡単のために無名関数を登録しています)。ほとんどのサイトでは add_filter で紹介していますが、これは
add_action( 'document_title_separator', function( $sep ) {
    return '|';
} );
でも同じ結果になります。
ではどのように add_actionadd_filter を使い分けるかですが、これは単純にフィルターフックの場合は add_filter で、アクションフックの場合は add_action ということでいいと思います。上記の例の document_title_separatorwp-includes/general-template.php の中で使われているフィルターフックです。そのため、add_action でフィルターする関数を登録するのではなく、add_filter で登録した方が、無意味な混乱を避けることができるので賢明です。同様に、wp_head で何かの要素を追加する場合は、あえて add_filter( 'wp_head', ... ); で登録するのではなく、add_action( 'wp_head', ... ) でアクションフックに登録する方が賢明です。add_filter はあくまでも『フィルター』させるもので、add_action は『アクション』に呼応して何かを実行する、と考えればいいと思います。

テーマの functions.php や プラグインファイルの書き方の鉄則

functions.php は after_setup_theme で読み込まれる一方、テンプレートの読み込みは wp-includes/template-loader.php の中の do_action( 'template_redirect' ) の後に行われます。そのため、例えばテーマの functions.php
echo 'hoge';
のようなコードを書くと、<!DOCTYPE html> 宣言よりも前に hoge が出力されます。これは HTML 文書として正しくありません。つまり、functions.php には直接何かを出力したりするコードを書くことはありませんテーマの functions.php やプラグインファイルでは基本的に add_actionadd_filter でアクションやフィルターにフックさせる関数を登録する、ということをします。コードで書くと
<?php
function my_function_1( ... ) {
  ...
}
add_action( 'some_action', 'my_function_1' );

function my_function_2( ... ) {
  ...
}
add_filter( 'some_filter', 'my_function_2' );

...
というように、add_action とそれに登録する関数、add_filter とそれに登録する関数がずらっと並んでいくのが基本となります。あとはこれに加えてショートコードの登録などを行います。