WordPressのquery.phpを読む(2)wp-blog-header.phpの役割とwp()関数、$postsの生成

query2

前回は、query.phpのファイルのコメント、定義されている関数とクラス、クラスがインスタンス化されるタイミング、コデックスについて見てみました。

そこで、分かったことは以下のこと。

  • WP_Queryクラスが重要で、WordPressの基本的な働きである、URLや引数などの条件に従って必要なコンテンツを読み込む役割を果たしているらしい。
  • WordPressの実行の早いタイミングで呼び出されてる
  • その呼びだされ方の詳細は、wp-blog-header.phpにあるらしい

そこで今回は、wp-blog-header.php、特にwp();関数について見ていきたいと思います。
(参考:WordPressの実行フローを視覚化してみるの図)。

WordPressの実行フローの図からの抜粋

上記の大曲さんの作った図のwp-blog-header.phpの箇所です。

  1. wp-load.phpの読み込み
  2. wp関数の実行
    1. アクセスURLを元にクエリー条件の設定
    2. DBからの記事データ取得
    3. リクエスト条件のグローバル変数設定
  3. template-loader.phpの読み込み

1のwp-load.phpでは、順繰りに色んなファイルが読み込まれて、定数が決まったりDBに接続したり、たくさんの関数を読み込んだりしています。

それを受けて、2のwp関数の実行というところがポイントになりそうです。特に、2−1「アクセスURLを元にクエリー条件の設定」というところが気になります。

3では、template-loader.phpが読み込まれていますが、このファイルを見ると、どのテンプレートファイルを読み込むのかをis_single()などの条件分岐タグを元に決める処理をしています。

wp-blog-header.phpの全文

<?php
/**
 * Loads the WordPress environment and template.
 *
 * @package WordPress
 */

if ( !isset($wp_did_header) ) {

	$wp_did_header = true;

	require_once( dirname(__FILE__) . '/wp-load.php' );

	wp();

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

}

?>

従って、各種関数の読み込みと、テンプレートファイルの読み込みの間にある、wp()関数がとても大事そうであることが推測できます。

wp()関数

コデックス

コデックス > Function Reference/wpを見ると、

Setup the WordPress query.

とあります。

定義ファイル

この関数は、wp-includs/functions.phpで定義されています。

/**
 * Set up the WordPress query.
 *
 * @since 2.0.0
 *
 * @param string $query_vars Default WP_Query arguments.
 */
function wp( $query_vars = '' ) {
	global $wp, $wp_query, $wp_the_query;
	$wp->main( $query_vars );

	if ( !isset($wp_the_query) )
		$wp_the_query = $wp_query;
}

が、まだまだ追いかけないとダメで、1570行目で、$wp->main()が呼び出されています。

WPクラス

WPクラスみたいなものがどこかにあるはずで、wp()のコール以前に読み込まれているファイルの中から探してみると、wp-includes/wp-class.phpというのがありました。

main()メソッドは下記のようになっていて、WPクラスの他のメソッドを呼び出していますorz…

/**
 * Sets up all of the variables required by the WordPress environment.
 *
 * The action 'wp' has one parameter that references the WP object. It
 * allows for accessing the properties and methods to further manipulate the
 * object.
 *
 * @since 2.0.0
 *
 * @param string|array $query_args Passed to {@link parse_request()}
 */
function main($query_args = '') {
	$this->init();
	$this->parse_request($query_args);
	$this->send_headers();
	$this->query_posts();
	$this->handle_404();
	$this->register_globals();
	do_action_ref_array('wp', array(&$this));
}

WPクラスのmain()メソッド

上記でハイライトされているメソッドを簡単に見てみると、

  1. init()wp_get_current_user()しています。表示中のユーザーの、WP_Userオブジェクトを返してきます。WP_Userオブジェクトは、プロパティにユーザIDやcaps, rolesなどの権限系、first_name, last_nameを持っています。
  2. parse_request():重要。まず、main()メソッドが$query_args = ''という引数を受け付けていてこのparse_request()に渡されています。リライトルールを持ってきて何かしていたり、$post_type, $taxonomyなどの文字も見えます。メソッド直前のコメントには”Parse request to find correct WordPress query.Sets up the query variables based on the request. There are also many filters and actions that can be used to further manipulate the result.”とあり、「リクエストをパースして、正しいWordPressクエリを知る。リクエストを基に、クエリ変数をセットアップする。フィルターやアクションがたくさんあるので、のちのち結果を操作できるよ。」です。$query_varプロパティに色々入れています。
  3. send_headers():HTTPヘッダー情報関連に見えます。
  4. query_posts():これも重要。コメントは、”Set up the Loop based on the query variables.”で、「クエリ変数に基づいてループをセットアップ。」下記の2つの処理をしています。前述のparse_queryでセットされた$query_varを使ってループをセットアップするようです。
    1. $this->build_query_string();:build_query_string()メソッドは、コメントが”Sets the query string property based off of the query variable property.”となっていて、「クエリ変数プロパティから情報を引っ張りだして、query stringプロパティを組み立てる。」です。key1=value1&key2=value2という文字列、つまりquery_stringを作ります。
    2. $wp_the_query->query($this->query_vars);:$wp_the_queryはWP_Queryのもう一つのインスタンスなので、wp-includes/query.phpの、WP_Query定義の、query()メソッドを見に行くと、その中で以下の3つの処理をしています。
      1. $this->init();:query系変数($posts, $queryとか)をunsetしたりしてる。改めてちゃんとセットするために、まっさらな状態から始めたいということでしょう。
      2. $this->query = $this->query_vars = wp_parse_args( $query );wp_parse_args()が、与えられた引数、及び、key1=value1&key2=value2の形で渡されたもの(=query_stringのこと。4-1のbuild_query_string)を連想配列にしたものを、デフォルトの値とマージします。$args = array('category' => 1, 'posts_per_page' => '3', 'post_type' => 'myposttype');としてからxxx( $args );とコールして$postを取得する系の関数で、元々のデフォルトから上書きできるのはこれのおかげのようです。これと、URLから取得した情報(query_var、及びquery_varから作ったquery_string)をマージしているのです。
      3. return $this->get_posts();:ものすごく長いメソッドですが、クエリを見てSQL文(とはいえ$wpdbに渡すものだけど)を作成、実行し$this->postsを返します。実際に取得しているのはこれになります。ここまでで、必要な情報がDBから引き出されていることになります。コメントは、”Retrieve the posts based on query variables.”で、「クエリ変数に基づいてpostsを取得」です。グローバル変数として使われる$postsがここでめでたく完成します。

wp-blog-header.php、及び、wp()関数のまとめ

ここで、起きたことをまとめると、以下のようになります。

  1. WordPressルートのindex.phpから、wp-blog-header.phpが呼び出される。
  2. wp-load.phpという各種初期設定や関数、クラスを読み込むためのファイルが呼び出される。この段階でWordPressの動作に必要な主なクラス、関数、プラグイン、テーマのfunctions.phpの読み込みや、DB接続が完了する。
  3. wp()関数が実行される。ここでは、WPクラスが使われていてユーザ情報、リクエストURL、引数を基にquery_var, query_stringが作られ色々統合され、それをもとに$postsの中にDBから取得してきた投稿情報が入れられる。
  4. このあと、wp-includes/template-loader.phpが読み込まれる。この段階では、ウェブサイトを訪れたユーザが誰で、何を見たいと思っているのかが分かっていて、関数も実行できる状態になっているため、必要なテンプレートファイルも判別可能な状態になっている。

だいぶ、すっきりしました。

template-loader.php

僕が大好き、WordPressのテーマファイルのテンプレート階層がなぜ使えるのか。

それはこのtemplate-loader.phpのおかげです。

コメントは、”Loads the correct template based on the visitor’s url”で、「訪問者のURLに従って、正しいテンプレートを読み込もう」です。

前半では、ロボット、Feed、トラックバックについての処理を行います。
後半では、is_404(), is_home()などの条件分岐タグを使って読み込むテンプレートファイルを指定しています。

後半部分

if ( defined('WP_USE_THEMES') && WP_USE_THEMES ) :
	$template = false;
	if     ( is_404()            && $template = get_404_template()            ) :
	elseif ( is_search()         && $template = get_search_template()         ) :
	elseif ( is_tax()            && $template = get_taxonomy_template()       ) :
	elseif ( is_front_page()     && $template = get_front_page_template()     ) :
	elseif ( is_home()           && $template = get_home_template()           ) :
	elseif ( is_attachment()     && $template = get_attachment_template()     ) :
		remove_filter('the_content', 'prepend_attachment');
	elseif ( is_single()         && $template = get_single_template()         ) :
	elseif ( is_page()           && $template = get_page_template()           ) :
	elseif ( is_category()       && $template = get_category_template()       ) :
	elseif ( is_tag()            && $template = get_tag_template()            ) :
	elseif ( is_author()         && $template = get_author_template()         ) :
	elseif ( is_date()           && $template = get_date_template()           ) :
	elseif ( is_archive()        && $template = get_archive_template()        ) :
	elseif ( is_comments_popup() && $template = get_comments_popup_template() ) :
	elseif ( is_paged()          && $template = get_paged_template()          ) :
	else :
		$template = get_index_template();
	endif;
	if ( $template = apply_filters( 'template_include', $template ) )
		include( $template );
	return;
endif;

ここに書かれている順番が、どのテンプレートを利用するのかを司り、(恐らく)get_xxx_template()という関数が、恐らく無ければ次の優先順位ファイルにする、という部分を司っているのでしょう。

まとめと次回予告

WP_Queryクラスについて勉強するつもりが、WPクラスについて深く見ていった第二回となりました。その過程で、WordPressカスタマイズの過程でよく見かける$postsの正体と生成過程が明らかになりました。

次の回では、WPクラスの中で呼び出されているWP_Queryがどのような役割をしているのかを見ていきたいと思います。その中で、$wp_query, $wp_the_queryが何らかの役割を果たしているはずで、上記で見てきたなかでの$query_var, $query_stringと深く関わっているものと思われます。

そこを見ていくことにしたいと思います。

「WordPressのquery.phpを読む」シリーズ

  1. はじめに的な位置づけと定義ファイル概要
  2. 今回。wp-blog-header.phpおよび、wp()関数、WPクラス、$postsの生成過程

続く

↓ プラグインを作る方々への本、書きました。 ↓

“WordPressのquery.phpを読む(2)wp-blog-header.phpの役割とwp()関数、$postsの生成” への 2 件のフィードバック

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です