結論
フロントエンド(サイトの表示)の大まかな実行順は次のとおりです。
muplugins_loaded→plugins_loadedsetup_theme→after_setup_themeinitwp_loadedparse_request→wp(クエリ確定後)template_redirectwp_head(この中でwp_enqueue_scriptsが優先度1で動く)- 本文の出力(テンプレート)
wp_footershutdown
「どのフックに書くか」は、必要な情報がそろう最初のフックを選ぶのが原則です。例:投稿タイプの登録は init、テーマ機能の宣言は after_setup_theme、CSS・JS の読み込みは wp_enqueue_scripts、リダイレクトは template_redirect。
原因・仕組み
WordPress は wp-settings.php の中で、プラグイン、テーマの順に読み込みながら、決まった場所で do_action() を実行します。実際にコアのソースを確認すると、wp-settings.php には muplugins_loaded → plugins_loaded → sanitize_comment_cookies → setup_theme → after_setup_theme → init → wp_loaded の順で並んでいます。その後、テンプレート読み込み(template-loader.php)で template_redirect が実行されます。
つまり、順番が違うフックに書くと、「まだ関数が使えない」「条件分岐タグが正しく動かない」といった問題が起きます。たとえば is_single() は、クエリが確定する wp 以降(実用上は template_redirect や wp_enqueue_scripts)でないと、正しい値を返しません。
手順(サンプルコード)
1. どの時点で何が済んでいるか確認する
foreach ( array( 'plugins_loaded', 'after_setup_theme', 'init', 'wp_loaded' ) as $h ) {
echo $h . '=' . did_action( $h ) . ' ';
}
did_action() は、そのフックが何回実行済みかを返します。init に書いたコードなら、plugins_loaded と after_setup_theme は 1 になっています。
2. フロントのフックの順番を記録する
$order = array();
$track = array( 'template_redirect', 'wp_enqueue_scripts', 'wp_head', 'wp_footer' );
foreach ( $track as $h ) {
add_action( $h, function () use ( &$order, $h ) { $order[] = $h; }, -9999 );
}
do_action( 'template_redirect' );
ob_start(); wp_head(); ob_get_clean();
ob_start(); wp_footer(); ob_get_clean();
echo implode( ' > ', $order );
3. 用途別の書き場所
| やりたいこと | 書くフック |
|---|---|
| 投稿タイプ・タクソノミーの登録 | init |
add_theme_support、メニュー場所の登録 |
after_setup_theme |
| CSS・JS の読み込み | wp_enqueue_scripts |
| 条件に応じたリダイレクト | template_redirect |
<head> への出力 |
wp_head |
| 管理画面の初期化 | admin_init |
動作確認(検証環境と結果)
WordPress 7.1.2(ja)、PHP 8.2.12 の CLI 環境で確認しました。
- スニペットは
initとwp_loadedの後に実行されるため、did_actionはplugins_loaded=1 after_setup_theme=1 init=1 wp_loaded=1。 - 記録の結果:
template_redirect > wp_head > wp_enqueue_scripts > wp_footer。wp_head自体に優先度 -9999 で登録したため先に記録され、その後にwp_enqueue_scriptsが実行された。これは、コア(default-filters.php)にadd_action( 'wp_head', 'wp_enqueue_scripts', 1 )があるためで、has_action( 'wp_head', 'wp_enqueue_scripts' )は1を返した。 wp-settings.phpのdo_actionの並びも目視で確認した。
ブラウザでの表示は、この環境では行えないため、template_redirect と wp_head などはスニペットから手動で実行した結果です。実際のリクエストでの完全な順序は、公式のアクションリファレンスで確認してください。
WordPressのフックの実行順の注意点
wp_headに直接<link>を出力するより、wp_enqueue_scriptsでキューに入れるのが基本です。initの時点では、is_page()のようなクエリ依存の条件分岐タグは正しく動きません。クエリが確定するwp以降のフックを選びます。- 管理画面では
admin_init、Ajax ではwp_ajax_*など、リクエストの種類で流れが違います。 - プラグインから
after_setup_themeのフックを使う場合、テーマ側の処理との前後に注意が必要です。
WordPressのフックの実行順でよくあるミス
functions.phpの直下でregister_post_type()を呼び、initを待たない。after_setup_themeより前に、add_theme_supportを呼んで反映されない。wp_enqueue_scriptsの中で、まだ確定していない情報に依存する。plugins_loadedの時点で、$wp_queryやis_single()を使う。
WordPressのフックの実行順のチェックリスト
- 使いたい関数・情報が、そのフックの時点で使えるか公式で確認したか
did_action()で、先に実行済みのフックを確認したか- 優先度の指定が、他のコードとの前後関係に合っているか
- フロントと管理画面で、必要なフックを分けているか
- 実行順をログに出して確認したか
WordPressのフックの実行順のFAQ(よくある質問)
Q. init と wp_loaded の違いは?
A. wp_loaded は init の後、WordPress が完全に読み込まれた時点です。クエリ関連の処理は、さらに後の wp 以降です。
Q. wp_enqueue_scripts が wp_head の中で動くのは、なぜ問題にならないのですか?
A. コアが wp_head の優先度1で呼ぶ仕様のためです。wp_head で出力する前に、キューが整います。
Q. 実行順を自分の環境で見るには?
A. 先頭で add_action( 'all', ... ) を登録して、current_filter() を記録する方法があります。ただし出力が多いため、本番では使いません。
筆者の見解(WordPressのフックの実行順)
フックの順番は、暗記するより「コアのソースに当たる」習慣を持つ方が、結局は早いと考えます。wp-settings.php と default-filters.php を一度読むと、なぜ init に書くのかが腑に落ちます。迷ったときに、did_action() で状態を確かめる癖をつけるのがおすすめです。
WordPressのフックの実行順の関連項目
- init フックの使い方|説明・引数・注意点
- after_setup_theme フックの使い方|説明・引数・注意点
- wp_head フックの使い方|説明・引数・注意点
- did_action() の使い方|説明・引数・注意点
- current_filter() の使い方|説明・引数・注意点
