コアファイルの処理フロー

コアファイルの処理フローから、WordPress本体の処理がどのようになっているのか確認します。ソースコードを適宜抜粋して説明します。(2015年時点の処理フローです。)

エントリポイント

index.php

まずWordPressで構築されたWebサイトを呼び出すと、/index.php から処理が始まります。

define('WP_USE_THEMES', true);
require( dirname( __FILE__ ) . '/wp-blog-header.php' );

/index.php では /wp-blog-header.php を読み込みます。

wp-blog-header.php

if ( !isset($wp_did_header) ) {
    $wp_did_header = true;
    require_once( dirname(__FILE__) . '/wp-load.php' );         // 1
    wp();                                                       // 2
    require_once( ABSPATH . WPINC . '/template-loader.php' );   // 3
}

/wp-blog-header.php では次の3つの処理を行います。

1.「/wp-load.php」の読み込み

様々なファイルを読み込み実行環境の準備がされます。主な処理は以下の通りです。

  • DB情報を設定してDB接続
  • テーマディレクトリ登録
  • 有効にしているプラグインをロード
  • 適用されているテーマのfunctions.phpを子テーマ、親テーマの順にロード
  • 投稿タイプ、タクソノミーの登録
  • ウィジェットの初期化処理

2. wp()関数を起動

  • リクエストに基づいてWPクエリを生成
  • WPクエリに基づいてSQLクエリを生成
  • DBからデータを取得してpostsやpostに設定

3. 「/template-loader.php」の読み込み

「/wp-load.php」の読み込み
( 実行環境の準備 )

/wp-load.php

define( 'ABSPATH', dirname(__FILE__) . '/' );
 
if ( file_exists( ABSPATH . 'wp-config.php') ) {
    require_once( ABSPATH . 'wp-config.php' );
} elseif ( file_exists( dirname(ABSPATH) . '/wp-config.php' ) && ! file_exists( dirname(ABSPATH) . '/wp-settings.php' ) ) {
    require_once( dirname(ABSPATH) . '/wp-config.php' );
} else {
}

__FILE__ は、PHPで自動定義される定数でPHPファイルのフルパスとファイル名が設定されています。
dirname関数でファイルパスからディレクトリを取り出し、ABSPATH定数を定義してます。

その後、if文で設定ファイル( wp-config.php )の有無を確認してます。

  • 同じ階層にある
    /wp-config.php の読み込み
  • 1つ上の階層にある
    /wp-config.php の読み込み
  • 存在しない
    ⇒ インストール処理の実行

/wp-config.php

define('DB_NAME', 'XXXXXXXXXX');
define('DB_USER', 'XXXXX');
define('DB_PASSWORD', 'XXXXXXXXX');
define('DB_HOST', 'localhost');
/** データベースのテーブルを作成する際のデータベースの文字セット */
define('DB_CHARSET', 'utf8mb4');
/** データベースの照合順序 (ほとんどの場合変更する必要はありません) */
define('DB_COLLATE', '');
 
/*
 * 認証用ユニークキー
 * {@link https://api.wordpress.org/secret-key/1.1/salt/ WordPress.org の秘密鍵サービス} で自動生成することもできます。
 * 後でいつでも変更して、既存のすべての cookie を無効にできます。これにより、すべてのユーザーを強制的に再ログインさせることになります。
 */
define('AUTH_KEY',         'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX');
define('SECURE_AUTH_KEY',  'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX');
define('LOGGED_IN_KEY',    'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX');
define('NONCE_KEY',        'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX');
define('AUTH_SALT',        'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX');
define('SECURE_AUTH_SALT', 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX');
define('LOGGED_IN_SALT',   'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX');
define('NONCE_SALT',       'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX');
 
$table_prefix  = 'wp_';
define('WP_DEBUG', false);
require_once(ABSPATH . 'wp-settings.php');

DB情報、認証用ユニークキー、デバッグモードなどを設定して /wp-settings.php を読み込みます。

/wp-settings.php

require( ABSPATH . WPINC . '/load.php' );
require( ABSPATH . WPINC . '/default-constants.php' );
require( ABSPATH . WPINC . '/version.php' );
require( ABSPATH . WPINC . '/compat.php' );
require( ABSPATH . WPINC . '/functions.php' );
require( ABSPATH . WPINC . '/class-wp.php' );
require( ABSPATH . WPINC . '/class-wp-error.php' );
require( ABSPATH . WPINC . '/plugin.php' );
require( ABSPATH . WPINC . '/pomo/mo.php' );
 
require_wp_db();
 
$GLOBALS['table_prefix'] = $table_prefix;
wp_set_wpdb_vars();

様々なコアファイルが読み込まれています。

その後、require_wp_db を実行するなかでwpdbオブジェクトを生成するときにDB接続してます。

function require_wp_db() {
    global $wpdb;
 
    require_once( ABSPATH . WPINC . '/wp-db.php' );
    if ( file_exists( WP_CONTENT_DIR . '/db.php' ) )
        require_once( WP_CONTENT_DIR . '/db.php' );
 
    if ( isset( $wpdb ) )
        return;
 
    $wpdb = new wpdb( DB_USER, DB_PASSWORD, DB_NAME, DB_HOST );
}

/wp-settings.php の続きを見ます。

require( ABSPATH . WPINC . '/default-filters.php' );
register_shutdown_function( 'shutdown_action_hook' );
 
// Load most of WordPress.
require( ABSPATH . WPINC . '/class-wp-walker.php' );
require( ABSPATH . WPINC . '/class-wp-ajax-response.php' );
     /* 略 */
require( ABSPATH . WPINC . '/nav-menu-template.php' );
require( ABSPATH . WPINC . '/admin-bar.php' );

また大量のコアファイルが読み込まれています。default-filters.phpでは、大量のフィルターフック、アクションフックが登録されます。

// Define constants after multisite is loaded.
wp_cookie_constants();
 
// Define and enforce our SSL constants
wp_ssl_constants();
 
// Make taxonomies and posts available to plugins and themes.
// @plugin authors: warning: these get registered again on the init hook.
create_initial_taxonomies();
create_initial_post_types();
 
// Register the default theme directory root
register_theme_directory( get_theme_root() );
 
// Load active plugins.
foreach ( wp_get_active_and_valid_plugins() as $plugin ) {
    wp_register_plugin_realpath( $plugin );
    include_once( $plugin );
}
unset( $plugin );
 
// Load pluggable functions.
require( ABSPATH . WPINC . '/pluggable.php' );
require( ABSPATH . WPINC . '/pluggable-deprecated.php' );
 
// Set internal encoding.
wp_set_internal_encoding();
 
do_action( 'plugins_loaded' );

テーマディレクトリの設定、有効化されたプラグインの読み込みなどが行われます。

$GLOBALS['wp_the_query'] = new WP_Query();
$GLOBALS['wp_query'] = $GLOBALS['wp_the_query'];
$GLOBALS['wp_rewrite'] = new WP_Rewrite();
$GLOBALS['wp'] = new WP();
$GLOBALS['wp_widget_factory'] = new WP_Widget_Factory();
$GLOBALS['wp_roles'] = new WP_Roles();
 
$locale = get_locale();
$locale_file = WP_LANG_DIR . "/$locale.php";
if ( ( 0 === validate_file( $locale ) ) && is_readable( $locale_file ) )
    require( $locale_file );
unset( $locale_file );
 
// Pull in locale data after loading text domain.
require_once( ABSPATH . WPINC . '/locale.php' );
 
$GLOBALS['wp_locale'] = new WP_Locale();
 
// Load the functions for the active theme, for both parent and child theme if applicable.
if ( ! defined( 'WP_INSTALLING' ) || 'wp-activate.php' === $pagenow ) {
    if ( TEMPLATEPATH !== STYLESHEETPATH && file_exists( STYLESHEETPATH . '/functions.php' ) )
        include( STYLESHEETPATH . '/functions.php' );
    if ( file_exists( TEMPLATEPATH . '/functions.php' ) )
        include( TEMPLATEPATH . '/functions.php' );
}
 
do_action( 'after_setup_theme' );
 
// Set up current user.
$GLOBALS['wp']->init();
 
do_action( 'init' );
 
do_action( 'wp_loaded' );

いろいろとオブジェクトを生成しています。WP_Queryオブジェクトも生成されてますが、引数なしなのでクエリは実行されません。

適用テーマのfunctions.phpを子テーマ、親テーマの順にロードします。

$current_userWP_Userオブジェクトを設定します。

initアクションでは、default-filters.phpでフックした処理(投稿タイプ・タクソノミーの登録、ウィジェットの初期化処理など)が実行されます。

wp()関数を起動
( クエリに基づいてDBからデータ取得 )

/wp-includes/functions.php

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

WPクラスのオブジェクトである$wpのmainメソッドを実行すると、$wp_queryにDBから取得した投稿データなどが設定されます。

/wp-includes/class-wp.php

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

parse_requestメソッド内ではリクエストに基づいてWPオブジェクトが持つクエリ変数($query_vars)を設定します。

query_postsメソッドでは、WPクエリを基にSQLクエリを生成して投稿データを取得します。投稿データはWP_Queryオブジェクトである$wp_queryのプロパティである posts配列やpostに設定されます。posts配列の要素やpostはWP_POSTオブジェクトです。

public function query_posts() {
    global $wp_the_query;
    $this->build_query_string();
    $wp_the_query->query($this->query_vars);
}

queryメソッド/wp-includes/query.php(後でとりあげます)で実行されます。

public function register_globals() {
    global $wp_query;
    $GLOBALS['posts'] = & $wp_query->posts;
    $GLOBALS['post'] = isset( $wp_query->post ) ? $wp_query->post : null;
    $GLOBALS['request'] = $wp_query->request;
 
    if ( $wp_query->is_author() && isset( $wp_query->post ) )
        $GLOBALS['authordata'] = get_userdata( $wp_query->post->post_author );
}

register_globalsメソッドでグローバル変数の設定がされます。

/wp-includes/query.php

public function query( $query ) {
    $this->init();
    $this->query = $this->query_vars = wp_parse_args( $query );
    return $this->get_posts();
}
public function get_posts() {
    global $wpdb;
 
 
    $this->request = $old_request = "SELECT $found_rows $distinct $fields FROM $wpdb->posts $join WHERE 1=1 $where $groupby $orderby $limits";
 
 
    if ( !$q['suppress_filters'] ) {
        $this->request = apply_filters_ref_array( 'posts_request', array( $this->request, &$this ) );
    }
 
 
        $this->posts = $wpdb->get_results( $this->request );
        $this->set_found_posts( $q, $limits );
 
 
        $this->posts = array_map( 'get_post', $this->posts );
        $this->post = reset( $this->posts );

$this->postsにDBから取得した投稿データがセットされます。

「/template-loader.php」の読み込み
( 適切なテンプレート読み込み )

/wp-includes/template-loader.php

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_front_page()     && $template = get_front_page_template()     ) :
    elseif ( is_home()           && $template = get_home_template()           ) :
    elseif ( is_post_type_archive() && $template = get_post_type_archive_template() ) :
    elseif ( is_tax()            && $template = get_taxonomy_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;

リクエストされたURLに基づいてテンプレートファイルが選択され読み込まれます。