WordPressのフックの実行順|init・wp_head・wp_footer の流れ

結論

フロントエンド(サイトの表示)の大まかな実行順は次のとおりです。

  1. muplugins_loaded → plugins_loaded
  2. setup_theme → after_setup_theme
  3. init
  4. wp_loaded
  5. parse_request → wp(クエリ確定後)
  6. template_redirect
  7. wp_head(この中で wp_enqueue_scripts が優先度1で動く)
  8. 本文の出力(テンプレート)
  9. wp_footer
  10. shutdown

「どのフックに書くか」は、必要な情報がそろう最初のフックを選ぶのが原則です。例:投稿タイプの登録は 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のフックの実行順の関連項目

出典(一次情報)

PR当サイトはアフィリエイト広告を利用しています。掲載内容は広告主から依頼・指示を受けたものではなく、筆者の調査・体験にもとづきます。
タイトルとURLをコピーしました