Implementation Details Edit

This page contains some history on various implementation details of WP-CLI.

Bootstrapping WordPress Bootstrapping WordPress

On a normal web request, your web server calls the index.php file in the root of the web directory to bootstrap the WordPress load process:

<?php
/**
 * Front to the WordPress application. This file doesn't do anything, but loads
 * wp-blog-header.php which does and tells WordPress to load the theme.
 *
 * @package WordPress
 */

/**
 * Tells WordPress to load the WordPress theme and output it.
 *
 * @var bool
 */
define('WP_USE_THEMES', true);

/** Loads the WordPress Environment and Template */
require( dirname( __FILE__ ) . '/wp-blog-header.php' );

You’ll notice index.php calls wp-blog-header.php, which then calls wp-load.php, which then calls wp-config.php, which then calls wp-settings.php.

This last file, wp-settings.php, is WordPress’ primary bootstrap file. It loads your plugins, active theme, and calls the init action.

On the command line, WP-CLI follows a similar process to bootstrap WordPress. However, instead of loading index.php, using the wp command starts with this:

<?php

// Can be used by plugins/themes to check if WP-CLI is running or not
define( 'WP_CLI', true );
define( 'WP_CLI_VERSION', trim( file_get_contents( WP_CLI_ROOT . '/VERSION' ) ) );
define( 'WP_CLI_START_MICROTIME', microtime( true ) );

// Set common headers, to prevent warnings from plugins
$_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.0';
$_SERVER['HTTP_USER_AGENT'] = '';
$_SERVER['REQUEST_METHOD'] = 'GET';
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';

include WP_CLI_ROOT . '/php/utils.php';
include WP_CLI_ROOT . '/php/dispatcher.php';
include WP_CLI_ROOT . '/php/class-wp-cli.php';
include WP_CLI_ROOT . '/php/class-wp-cli-command.php';

\WP_CLI\Utils\load_dependencies();

WP_CLI::get_runner()->start();

WP-CLI includes a good amount of setup code prior to calling wp-settings.php. Its bootstrapping process is different than a web request in a couple of notable ways.

wp-config.php is parsed, and then executed wp-config.php is parsed, and then executed

Rather than calling wp-config.php directly, WP-CLI gets the contents of wp-config.php, parses out the require_once ABSPATH . 'wp-settings.php'; statement, and loads the constants into scope with eval(). Read “How WP-CLI loads WordPress” for a narrative on the historical reasons. After that, WP-CLI used a custom wp-settings-cli.php until v0.24.0 [#2278], but parsing wp-config.php was kept for backwards compatibility purposes. See also #1631.

Top ↑

WordPress is loaded inside of a function WordPress is loaded inside of a function

WP-CLI loads WordPress with the WP_CLI::get_runner()->load_wordpress() method, meaning WordPress plugins and themes aren’t loaded in global scope. Any global variables used in plugins or themes need to be explicitly globalized. See #2089 for the history of this decision.

Once WP_CLI::get_runner()->load_wordpress() calls wp-settings.php, WordPress handles the rest of the bootstrap process.

Top ↑

Command Help Text Command Help Text

The wp help <command> has been through several incarnations.

Since WP-CLI 0.3, it invoked a static help() method in the command class, if it existed. (48a8887d)

Since WP-CLI 0.6, it looked for a <command>.1 ROFF file and displayed it using man. The ROFF file was compiled from a corresponding <command>.txt markdown file and from PHPDoc metadata. (#24).

Since WP-CLI 0.11, it generates the help text on the fly. (#548)

Top ↑

WP_ADMIN WP_ADMIN

Most WP-CLI commands perform administrative actions and they need access to code defined in wp-admin/includes. This code can be loaded on-demand or preemptively.

The question is: should the WP_ADMIN constant be set to true or false?

Initially, WP-CLI just loaded the wp-admin code and didn’t mess with the WP_ADMIN constant at all.

Then, it sort of pretended it was doing a front-end page load, for doing integration testing (#69). [1]

Then it pretended it was loading wp-admin, to side-step caching plugins (#164).

Then it stopped pretending it was loading wp-admin (#352), because we found a better way to side-step caching plugins. [2]


  • [1]: It turned out that the official WordPress testing suite had a better solution: the go_to() method.
  • [2]: The solution was rolling our own wp-settings.php file.