仕事でWordPressを使用する機会が多くなってきた。 しばらく触っていなかったので、復習を兼ねてWordPressがリクエストを処理するフローをまとめる。

概要

<?php
define( 'WP_USE_THEMES', true );

$_GET['p'] = 1;

$_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.1';
$_SERVER['REQUEST_METHOD']  = 'GET';
$_SERVER['REQUEST_URI']     = '/?p=1';
$_SERVER['HTTP_HOST']       = 'example.com';

require_once 'wp-load.php';

wp();

require_once( ABSPATH . WPINC . '/template-loader.php' );

WordPressのオプションを管理画面で確認する

http://example.com/wp-admin/options.php

すべてのオプション(wp_optionsテーブルの内容)を一覧できる隠しページ。通常のメニューには表示されないが、直接URLを入力すればアクセスできる。

詳細

WordPressはリクエストを、フロントコントローラーindex.phpで受けて、wp-blog-header.phpを呼び出す。

wp-blog-header.phpのソースコードは以下の通り。

<?php
if ( ! isset( $wp_did_header ) ) {

	$wp_did_header = true;

	// Load the WordPress library.
	require_once( dirname( __FILE__ ) . '/wp-load.php' ); // 著者注 --- (1)

	// Set up the WordPress query.
	wp(); // 著者注 --- (2)

	// Load the theme template.
	require_once( ABSPATH . WPINC . '/template-loader.php' ); // 著者注 --- (3)

}

wp-blog-header.phpの(1)〜(3)が、WordPressがリクエストを処理する流れを表している。 (1)〜(3)を順番に見ていく。

(1) WordPress初期化

wp-load.phpは、WordPressの初期化処理を実行する。 内部でwp-config.phpを読み込み、さらにwp-config.phpがwp-settings.phpを読み込む。

wp-settings.phpでは、具体的に以下のような処理が実行される。

  1. コアファイルを読み込み(wp-includes/**)
  2. データベースへ接続
  3. デフォルトフィルター(イベントハンドラ)を登録
  4. プラグインを読み込み
  5. グローバル変数(wp_the_query = wp_query、wp_rewrite、wpなど)を作成(例: $GLOBALS['wp_the_query'] = new WP_Query())
  6. 有効化されているテーマのfunctions.phpを読み込み(読み込み直後にafter_setup_themeアクションを実行)
  7. initアクションを実行
  8. wp_loadedアクションを実行

(2) wp関数実行 - メインクエリ(WP_Query)構築

wp()関数は、パーマリンクからWordPressクエリを取得してSQLを実行し、投稿(WP_Postの配列)をメインクエリ(WP_Queryのインスタンスであるグローバル変数wp_query)のpostsプロパティに格納する。

発行したクエリ情報はWP_Query::query_varsに格納される。

wp()関数はWP::main()を呼び出す。WP::main()の処理は以下の通り。

// 著者注: コメント等は一部省略
class WP {
    // ...
    public function main( $query_args = '' ) {
        $this->init();
        $this->parse_request( $query_args ); // 著者注 --- (a)
        $this->send_headers();
        $this->query_posts(); // 著者注 --- (b)
        $this->handle_404();
        $this->register_globals();

        do_action_ref_array( 'wp', array( &$this ) );
    }
    // ...
}

(a) WP::parse_request()

リクエストをパースして、WordPressクエリ変数(query vars)をWP_Query::query_varsへ設定する。

(b) WP::query_posts()

WP::query_posts()はWP_Query::get_posts()を呼び出す。 WP_Query::get_posts()はWP_Query::query_varsからSQLを作成・実行し、結果(WP_Postの配列)をメインクエリWP_Queryのpostsプロパティに格納する。

(3) 表示テンプレートの選択

template-loader.phpは、メインクエリの内容に応じて表示するテンプレートファイルを選択する。

備考

投稿タイプの条件分岐を使用できる最初のフック

クエリタイプ(is_page()、is_single()、is_category()など)を判別可能な最初のアクションフックはparse_query。

WP_Query::get_posts()は内部でWP_Query::parse_query()を呼び出し、parse_query()がクエリタイプをセットする。

class WP_Query {
    // ...

    // 著者注: コメント等は一部省略
    public function get_posts() {
        global $wpdb;

        $this->parse_query(); // 著者注: parse_queryメソッド内で発火するparse_queryアクションが、投稿クエリタイプを判別可能な最初のアクション

        do_action_ref_array( 'pre_get_posts', array( &$this ) ); // 著者注: pre_get_postsアクション内では投稿クエリタイプを判別可能

        // ...
    }

    // ...
}