WordPressのコアファイルを読みながら、PHPを学習してみることにしました(query.phpなどなど編)

photo credit: ope via photopin cc
photo credit: ope via photopin cc
Update Web制作メモ >

前々回前回に引き続き、WordPressのコアファイルを読んで、テンプレートタグで使用されるWordPress関数がどのように定義されているかを見てみます。

is_home関数などはquery.phpで定義されているけれど

前にも例として挙げたis_home()関数はquery.phpでこのように書かれています。

function is_home() {
	global $wp_query;
	if ( ! isset( $wp_query ) ) {
		//省略
	}
	return $wp_query->is_home();
}

知らない用語をPHP公式リファレンスで調べます。

  • global – PHP では、グローバル変数は、関数の内部で使用す る場合、関数の内部でグローバルとして宣言する必要があります。(中略)関数の内部で $a、$b をグローバル宣言を行うことにより、両変数への参照は、グローバル変数 の方を参照することになります。ある関数により操作できるグローバル変 数の数は無制限です。
  • return – 関数内で呼び出されると、return文は即座に その関数の実行を停止し、引数を関数の値として返します。

6行目の矢印みたいなもの(->)はリファレンスで探せませんでしたのでぐぐりました。アロー演算子っていうみたいです。

定義したクラスから、プロパティやメソッドにアクセスするときに使うものです。

たい焼きコードを書いてPHPのクラス、オブジェクトをちょっと学ぶ

どうやらPHPにはクラスとかオブジェクトというものがあって、これを理解しないとこの先を読み進めるのは難しいようです。

WordPressのお話から離れてしまいますが…先日(@donuzium)さんにこのクラスとかオブジェクトとかを、たい焼きのレシピ・型・中身…などに例えて教えていただきました。

教わったことを元に、たい焼きクラスを定義して、「なかみはカスタード」と表示されるかんたんなコードを書いて、添削していただきました。いつもほんとにありがとうございます…!

たい焼きコード

<?php
class Taiyaki{
    var $nakami;

    function taiyakiinfo () {
    echo("なかみは".$this->nakami);
    }

    function love( $nakamiinfo ){
    $this -> nakami = $nakamiinfo;
    $this -> taiyakiinfo();
    }
}

$taiyaki = new Taiyaki();
$taiyaki -> love("カスタード");

?>

今回もおそらくたくさんのファイルを追っていくことになると思いますので、必要なところを読み拾いながら、このくらいのシンプルなかたちにまとめてみることにします。

ここまでのまとめ

  • class Taiyaki{}のように、wp_queryクラスを定義しているところ(class wp_query{}みたいなもの)がどこかにあるはずなので探す。
  • $taiyaki = new Taiyaki();のように、$wp_query = new wp_query();みたいなものもどこかにあるはずなので探す。

WP_Queryクラスはquery.phpで定義されているみたい

CodexのWP_Queryの役割というページを読んでみました。

WP_Query は wp-includes/query.php に定義されているクラスで、WordPress ブログへの複雑なリクエストを取り扱います。 wp-blog-header.php (バージョン 2.0 では WP クラス) が $wp_query オブジェクトに現在のリクエストを定義する情報を与えることで、$wp_query はどのタイプのクエリを扱っているのか (カテゴリーアーカイブ、年月別アーカイブ、フィード、検索など) を確定し、要求された投稿を取り出します。$wp_query はリクエスト上の情報を多く保持していて、後からでも利用することができます。

ここまでのまとめ

  • query.phpWP_Queryクラス(class wp_query{}みたいなもの)があることがわかった。
  • でもそれより前に、wp-blog-header.php が、$wp_queryオブジェクトに何かをぽいっと入れるみたい。こちらを先に読むことにする。

wp-blog-header.phpに戻って、WP()関数を確認する

前々回にのぞいてみたwp-blog-header.phpで実行されるwp()という関数がやっぱり重要みたいです。もういちどCodexのクエリ概要というページを読んでみます。「WordPressがブログページを構築する仕組み」について、以下のように解説されていました。

  • ユーザーがURLを入力したり、リンクをクリックしたりすると、WordPressはいくつかのコアファイルを起動させる
  • すべてのプラグインを読み込んで初期化する
  • テキスト・ドメイン と、現在有効になっているテーマのfunctions.phpを読み込む

ここまでは、前々回前回にのぞいたファイルについての解説かと思います。続きを読みます。

  • WordPressはwp()関数を起動する。すると、$wp->main()($wp はWPクラスのインスタンス。wp-includes/classes.php参照)が呼び出される。これによりWordPressに対して以下の命令が発行される:
  • WP->parse_request()を使ってURLをパースし、クエリを特定せよ
  • $wp_query->parse_query()を使い($wp_queryはWP_Queryクラスのインスタンス。wp-includes/query.php参照)、条件分岐タグで使用されるすべてのis_変数を設定せよ
  • 特定したクエリをMySQLのデータベースクエリに変換し、WP_Query->get_posts()関数によって投稿のリストを取得するデータベースクエリを発行せよ。そして、WordPressループ内で使用される$wp_queryオブジェクトの中に保存せよ

この部分がwp()という関数についての解説のようです。

WordPressはテンプレートを読み込み、テンプレート階層に従ってどのテンプレートファイルを使用するかを特定する。(中略)テンプレートやフィードファイルは、WordPressに組み込まれた関数を使って、カテゴリーやアーカイブへのパーマリンクを出力する

前にも参照した実行フローによると、この部分はおそらくまた別のファイルtemplate-loader.phpあたりの役割かなと思います。

WP()関数はfunctions.php

さて、wp()関数はfunctions.phpにあるようなので見てみます(Codex参照)。

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;
}

ここまでのまとめ

  • どうやら、アクセスされたURLに応じてこのwp()関数が何かをして、$wp_queryオブジェクトの中に何かをぽいっと入れることでページが表示される!というのがざっくりとした流れみたい。
  • $wp = new WP()がどこかにあるはず。探す。class WP(){}も。
  • function love(){}と同じようにfunction main(){}があるはず。これはclasses.phpにあるらしい。
  • そのfunction main(){}に、parse_request()というものについて何か書いてあるはず。

class-wp.php

function main(){}が書いてあるはずのclasses.phpというファイルが見当たらなかったのですが…前回見たwp-settings.phpの中で、クラスという名前のついたファイルを読み込んでいたのを思い出しました。class-wp.phpというファイルです。これを見てみます。

class WP{
 //たくさん省略
	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));
	}
//たくさん省略

main()メソッドが見つかりました。parse_request($query_args)にアクセスしています。

parse_request()

	/**
	 * 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.
	 */
	function parse_request($extra_query_vars = '') {
        //なかみは省略
        }

とっても長いのでなかみを省略していますが、冒頭に「リクエストを解析して、正しいクエリを特定する。それをもとにクエリ変数をセットアップする」というようなコメントがありました。

また、Codexでは「それぞれのクエリ変数に対し、WordPressはそれがパラーマリンクの解析によって得られたのか、それともPOSTやGETからなのかを判断し、クエリ特定のための配列($wp->query_varsはWP クラスのインスタンス。wp-includes/classes.php参照)に格納する」と解説されていました。

それから、さきほどのwp-settings.phpをもういちどちゃんと見てみたら、こんなのもありました!

$wp_the_query = new WP_Query();
$wp_query = $wp_the_query;
$wp = new WP();

ここまでのまとめ

  • $query_varsに何かをぽいっと入れてるみたい。
  • $wp_the_query = new WP_Query();$wp_query = new WP_Query();)があった。

query.php

WP()関数のふたつめの役割について、先ほどのCodexの解説を再度引用します。

$wp_query->parse_query()を使い($wp_queryはWP_Queryクラスのインスタンス。wp-includes/query.php参照)、条件分岐タグで使用されるすべてのis_変数を設定せよ。

なので、query.phpを読んでみます。WP_Queryクラスもここに書いてあるはず(先述)。

class WP_Query {
        var $query;
	var $query_vars = array();
        //省略
	var $request;
	var $posts;

        //省略

function parse_query( $query =  '' ) {
	if ( ! empty( $query ) ) {
		$this->init();
		$this->query = $this->query_vars = wp_parse_args( $query );
		} 
        elseif ( ! isset( $this->query ) ) {
			$this->query = $this->query_vars;
		}
        //省略

		$qv['m'] = absint($qv['m']);}//省略
		if ( $qv['m'] ) {
		$this->is_date = true;//}省略
				
		if ( !( $this->is_singular || $this->is_archive || $this->is_search || $this->is_feed || $this->is_trackback || $this->is_404 || $this->is_admin || $this->is_comments_popup || $this->is_robots ) )

		$this->is_home = true;
        //省略
        }
        //省略		

ここまでのまとめ

  • query.phpWP_Queryクラスが定義されていて、function parse_query(){}があった。ここでis_変数を設定しているみたい。

query.phpつづき

WP()のみっつめの役割についても、Codexの解説を再度引用します。

特定したクエリをMySQLのデータベースクエリに変換し、WP_Query->get_posts()関数によって投稿のリストを取得するデータベースクエリを発行せよ。そして、WordPressループ内で使用される$wp_queryオブジェクトの中に保存せよ。

引き続きquery.phpを読みます。

class WP_Query {
//省略

/**
* Retrieve the posts based on query variables.
*/

function parse_query( $query =  '' ) { }
//省略
function get_posts() {
        global $wpdb, $user_ID, $_wp_using_ext_object_cache;
	$this->parse_query();
	//省略
	$q = &$this->query_vars;
        //省略

	if ( $this->is_home && (empty($this->query) || $q['preview'] == 'true') && ( 'page' == get_option('show_on_front') ) && get_option('page_on_front') ) {
		$this->is_page = true;
		$this->is_home = false;
		$q['page_id'] = get_option('page_on_front');
		}
        //省略
return $this->posts;
}

これもとっても長かったのですが…冒頭のコメントと最後の行をみると、最終的にはpostsという何かを取得したみたいです。

CodexのWP_Queryのページに、こんなことが書いてありました。

$posts – 要求された投稿をデータベースから取得したもの。

ここまでのまとめ

  • query.phpにWP_Queryクラスがあって、その中にfunction get_posts(){}があった。

全部のまとめ

WordPressでつくられたページのURLにアクセスがあると、

  • WordPressルートのindex.phpが読み込まれる。
  • wp-blog-header.phpが読み込まれる。
  • wp-blog-header.phpから、includerequireでたくさんのファイルが順に読み込まれる。
  • その過程で、あれこれ初期設定、関数、変数、定数、クラス、プラグイン、キャッシュ、データベースの設定…などなどが行われる。
  • wp-blog-header.phpwp-load.phpfunctions.phpWPクラスが定義され、WP()関数が実行される。
  • parse_request()はクエリを特定して、$query_varsに何かをぽいっと格納する。
  • parse_query() は$query_varsをもとにしてis_変数を設定する。
  • get_post() は設定されたis_変数をもとにしてデータベースから必要なものを取得し、結果を$postsに格納する。
  • template-loader.phpが読み込まれる。
  • template-loader.phpはテーマから正しいテンプレートファイルを選んでくれるみたい(これから見るところ)。
  • 正しい投稿が正しいテンプレートファイルで表示される!

wp-settings.php

$wp = new WP();

wp-settings.php

$wp_the_query = new WP_Query();
$wp_query = $wp_the_query;

class-wp.php

class WP{
    function main(){$this->parse_request();}
    function parse_request(){  }
}

functions.php

wp();

query.php

class WP_Query {
    var $query;
    var $query_vars = array();
    var $request;
    var $posts;

    function parse_query(){ }
    function get_posts(){
    return $this->posts
    }
}

function is_home() {
    global $wp_query;
    return $wp_query->is_home();
}

抜粋してみました。なーんとなく整理できてきたかな?という感じです。次はtemplate-loader.phpを中心に見てみようと思います。

ところで、たい焼きはカスタードがいちばんおいしいですよね。