WordPressの起動2 – WordPress起動時に読み込まれるPHPファイルの順番

WordPressの起動時には、コアモジュールがブラウザに入力されたURLをパース(プログラムのソースコードやXML文書など、一定の文法に従って記述されたテキスト文書を解析し、プログラムで扱えるようなデータ構造の集合体に変換すること)して、確定したクエリに基づいてSQLクエリに変換し、MySQLから投稿やページを取得しグローバル変数に格納するプロセスと、テンプレート階層をなぞりながらテーマテンプレートを確定するプロセスが走ります。

define()関数とconst()関数による定数定義方法の違い

PHPの定数定義は、クラス外からグローバル関数として使用するdefine()関数が使われてきましたが、PHP5.3からはクラス内で使用するconst()が使えるようになっています。

読み込まれるPHPファイルの順番

WordPressは、6つのファイルとwp関数が、順番に呼び出されて起動します。

  1. -index.php(WordPressのエントリーポイント)
  2. —–wp-blog-header.php
  3. ———wp-load.php(環境設定)
  4. ————-wp-config.php(DB接続情報)
  5. —————–wp-settings.php(WordPress初期設定のコア)
  6. ———wp関数(WordPressメイン関数実行)
  7. ———template-loader.php(テンプレート選択)

1. index.php

仮にWordPressを別ディレクトリにインストール(WordPressのアドレスが違う場合)する際でも、index.phpはWordPressのエントリーポイントなので、必ずドメインルートに置く必要があり、2行目で/blog/wp-blog-header.phpみたいに、インストールディレクトリにあるファイルをインクルードするように修正します。

これはエントリーポイントをドメインルートに置くだけで、インストールディレクトリは自由に選択できるという柔軟性を実現しています。

dirname関数はファイルである自分が入っているディレクトリ、つまり親ディレクトリを示すのでカレントディレクトリになりますが、カレントディレクトリをさらにdirname関数の引数にすると、カレントディレクトリが入っているディレクトリ、すなわち1個親のディレクトリを指します。

__FILE__はPHP定義済み定数で自分自身のファイルまでのパス、dirname(__FILE__)自分自身がいるディレクトリ、つまり親ディレクトリまでのパスとなり、dirname(dirname(__FILE__))になると祖父ディレクトリまでのパスとなります。

2. wp-blog-header.php

  • 2行目:以降は変数$wp_did_headerが空の場合の処理であり、まずtureをセットする。この$wp_did_headerが何なのかイマイチはっきりしませんが、php.iniのregister_globalディレクティブがONだと、仮にURLのクエリストリングで「index.php?wp_did_header=dummy」とかやられたら、コード上で$wp_did_header変数にdummyという値が格納されてしまうのでマズイらしい。よって$wp_did_headerが空であることを前提として処理を継続させます。
  • 3行目:wp-load.phpを1回だけインクルード
  • 4行目:wp関数が実行される。
  • 5行目:wp-includes/template-loader.phpを1回だけインクルード

3. wp-load.php

  • 1行目:ABSPATHにwp-load.phpのカレントディレクトリまでのパスに末尾スラッシュをつけたもの、すなわちWordPressルートをセット
  • 2行目:error_reporting() 関数で出力する PHP エラーの種類を設定する。
  • 4行目:WordPressルートにwp-config.phpがある場合。wp-config.phpはWordPressのインストール時にDB名、ユーザー名、パスワードなどパラメータを設定することで自動生成されます。つまりwp-config.phpがあるということはWordPressのインストールが完了しているということです。
  • 5行目:WordPressルートのwp-config.phpを1回だけインクルード
  • 6行目:WordPressルートの1個上の親ディレクトリ、通常はドキュメントルートにwp-config.phpがありwp-setting.phpがない場合(関数の前に@があるのでエラーログを出力しない)
  • 7行目:ドキュメントルートのwp-config.phpを1回だけインクルード

以下はwp-config.phpがない場合、つまりwp-load.phpは存在するがwp-config.phpがないということは、インストールはしたもののパラメータが未設定で自動生成されていない状態で、この場合以下が1回だけ実行されます。

そもそもwp-config.phpはダウンロード時のWordPressのコアファイルの中には存在せず、インストール時に自動生成されますが、設定が終わっていないと以下のエラーを出力します。

ファイルが見つかりません。インストールを開始するにはwp-config.php ファイルが必要です。お困りでしたら「wp-config.php の編集」を参照してください。ウィザード形式で wp-config.phpファイルを作成することもできますが、すべてのサーバーにおいて正常に動作するわけではありません。最も安全な方法は手動でファイルを作成することです。

4. wp-config.php

インストール時に接続情報やユーザー情報を入れることで自動生成された環境設定ファイルをWordPressの起動時に読み込む。

  • 12行目:ABSPATHが空の場合はWordPressルートをセットして、そこにあるwp-settings.phpを1回だけインクルード

5. wp-settings.php

WordPress全体で使うオブジェクトを生成し、スーパーグローバル変数に格納し、処理やクラス的なライブラリをインクルードする重要なファイルです。

  • 18行目:wp_initial_constants関数で、phpの実行メモリ上限をマルチサイトで64MB、シングルサイトで40MBに指定、ブログIDのデフォルトを1に指定、などなど。
  • 21行目:wp_check_php_mysql_versions関数で、PHPとMySQLがWordPressに対してバージョン不足の際にエラーを表示させる。
  • 24行目:php.iniのディレクティブであるマジッククォートはSQLインジェクション(SQL攻撃)防止のため、シングルクオート、ダブルクオート、バックスラッシュ、NULL文字を自動的にバックスラッシュでエスケープする機能ですが、副作用が多いためPHP5.4でデフォルトOFFされていますが、WordPress内でも無効化しています。
  • 31行目:php.iniのディレクティブであるregister_global=Onだと、GETかPOSTのクエリストリングで送信した値が、$_GET[‘変数’]や$_POST[‘変数’]で取得できるのはいいとしても、$変数自体にも値がセットされてしまっているため、もしプログラムで$変数の初期化を忘れてしまった場合に、URLの改ざんにより問題が起こる可能性があるため、Offと同じ状態にしましょうという関数がload.php内のwp_unregister_globals関数です。
PHP5.4からregister_globalディレクティブはデフォルトでOFFですが、WordPress内でもOffにします。スーパーグローバル変数$GLOBALSは連想配列です。
  • 272行目から294行目までは$wp_the_query, $wp_query, $wpという重要なインスタンスを生成し、スーパーグローバル変数$GROBALSに格納しているところです。
  • 272行目:WP_QUeryクラスから$wp_the_queryオブジェクトを生成し$GROBALSに格納
  • 280行目:WP_QUeryクラスから$wp_queryオブジェクトを生成し$GROBALSに格納
  • 294行目:WPクラスから$wpオブジェクトを生成し$GROBALSに格納

wp-settings.phpには、プラグイン開発で必要になるフックが以下の順に埋め込んであります。

  1. do_action( ‘muplugins_loaded’ );
  2. do_action( ‘plugins_loaded’ );
  3. do_action( ‘sanitize_comment_cookies’ );//setup_themeフックを点火しテーマを読み込む
  4. do_action( ‘setup_theme’ );//after_setup_themeフックを点火
  5. do_action( ‘after_setup_theme’ );//wp_loadedフックを点火しコアモジュール、プラグイン、テーマを起動する。
  6. do_action( ‘wp_loaded’ );

6. wp()関数を実行

wp-blog-header.phpでwp-load.php⇒wp-config.php⇒wp-settings.phpと読みこまれた後に、wp関数が実行されますが、やっていることは主に以下の3つです(Codex クエリ概要)。

  1. URLをパース(文法に従って分析)しクエリを特定
  2. 条件分岐タグで使用されるすべてのis_変数を設定
  3. クエリに基づき$wp_query->get_posts()関数で投稿データを$posts配列に格納

WPクラスからWP_Queryクラスに関数が以下のように呼ばれて繋がっていきます。

  1. wp()
  2. —$wp->main()
  3. ——–$wp->parse_request():URLパースとクエリ特定
  4. ——–$wp->query_posts()
  5. ————$wp_query->query()
  6. —————-$wp_query->get_posts():投稿データ取得
  7. ——————–$wp_query->parse_query():is_変数を設定

まずwp-settings.phpで生成したグローバル変数$wp, $wp_query, $wp_the_queryを関数内で使用するためにグローバル宣言しています。

wp-includes/functions.phpの中にwp関数が定義されており、ここでWPクラスのmainメソッドに引数$query_varsを渡して実行します。

WPクラス自体はwp-includes/class-wp.phpに定義されており、ここにmainメソッドがあります。

URLをパース(文法に従って分析)しクエリを特定

wp-includes/class-wp.phpのWPクラス内のparse_requestメソッドでパース処理を行ない、URLにマッチしたクエリを特定します。

条件分岐タグで使用されるすべてのis_変数を設定

query.phpのWP_Queryクラスにparse_queryメソッドがありますが、名前にparseがついているにもかかわらず、パース処理はすでにparse_requestメソッドで完了しており、ここではパース処理は行なわれず、条件分岐タグで使用するis_変数への値をセットします。

クエリに基づき$wp_query->get_posts関数で投稿データを$posts配列に格納

$wp->mainメソッドの中で6個のWPクラス自身のメソッドを実行していますが、実際にクエリのタイプを確定し投稿を取得し、$wp_query->postsに格納しているのは$wp->query_postsメソッドです。

wp-settings.phpでWP_Queryクラスから生成したグローバル変数$wp_the_queryを、関数内で使用するためにグローバル宣言し$wp_the_query->queryメソッドを実行します。

ここがWPクラスとWP_Queryクラスが連結するところで、WPクラスの$wpオブジェクトからWP_Queryクラスのメソッドを$wp_queryオブジェクトを通して実行しています。

wp-includes/query.phpにあるWP_Queryクラスのget_postsメソッドで、要求された投稿をデータベースから取得し、グローバル変数$postsに格納しています。

 

7. template_loader.php

WordPressのテンプレート階層とは、テンプレートファイルを表示するルールであり、それを実現するのがtemplate_loader.phpです。

  • 8行目:HTTP通信メソッドのGETはページや画像などのデータにアクセスしたときで、POSTはフォームでデータを送信したとき であり、HEADはウェブ巡回ツールが ページの更新日付などの情報だけを取得したときのメソッドになります。

apply_filters( ‘exit_on_http_head’, true )がよく分かっていないのですが、exit_on_http_headはHEADメソッドに対してコンテンツを生成を認めるかどうかというフックのようです。要はHEADメソッドならExit終了ということ。

■exit_on_http_head
Hook: Filter whether to allow ‘HEAD’ requests to generate content.
■apply_filters ( ‘exit_on_http_head’, bool $exit );
Filter whether to allow ‘HEAD’ requests to generate content.
Provides a significant performance bump by exiting before the page content loads for ‘HEAD’ requests.
  • 61行目: apply_filters( ‘template_include’, $template )

8. テンプレートファイル

WordPressループの中のthe_postsテンプレートタグにより、$wp_query->postsから現在の投稿を順次に読み込んでいきます。

まずはいつものWordPressループの中で何気なく実行される関数・・・

このhave_posts()関数やthe_post()関数を実行する$wp_queryオブジェクトは、wp-includes/query.phpの中に定義されているWP_Queryクラスから生成されており、このメソッドを実行しています。

WP_Queryクラスの中にhave_post()やthe_post()やis_home()などのメソッドが定義されています。

つまりWordPressループはWP_Queryクラスからオブジェクトを生成することにより、いくつものバリエーションのループを生成することができます。

これでメインクエリのhave_posts関数でデータの有無を判断し、the_post関数でグローバル変数$postに格納された投稿を取得することがわかりました。