New bootstrapping mechanism to load the WP-CLI framework

The upcoming 1.2.0 release of WP-CLI will include a refactored bootstrapping flow that provides a more flexible way of loading the framework itself and setting everything up. This refactoring is needed to allow for some of the expected functionality to work in conjunction with bundled commands being provided through external packages and the general use of autoloading (Issue #3850 | Pull Request #3872).

What does the term “bootstrapping” mean?

In general terms, bootstrapping code is code that is not part of the actual logic meant to solve the problem, but rather code that is needed to prepare the environment so that the actual logic is able to run.

This usually means locating files and folders, setting constants, reading configuration, etc…

What problem does this change solve?

The current stable release has all bundled commands be part of the wp-cli/wp-cli repository as a big monolithic package. This has several drawbacks, like having a huge testsuite be run for every single change to the framework (and waiting for 2 hours on feedback from the tests), and coupling the update frequency of these commands to the framework itself (making a quick hotfix to one single command difficult).

To get around these problems, we’ve extracted all of the commands into separate repositories that exist on their own, come with their own testsuites and have their own release cycles. To be able to profit from these decoupled release cycles, though, you need to be able to update a bundled command independently of the framework. This means that the act of loading the framework needs to be strictly separate to the act of loading the bundled commands.

The new bootstrapping mechanism separates the procedural list of load operations into a set of isolated steps for which the order can be freely defined.

General flow

After defining some constants to locate the needed files, WP-CLI will load the bootstrap component and call the WP_CLI\bootstrap() function (source).

This function defines a list of bootstrapping steps that will then be loaded and processed in the provided order (source).

The list of bootstrapping steps is a basic array of fully qualified class names (source). Each of the classes implements the WP_CLI\Bootstrap\BootstrapStep interface, meaning that it provides a process( BootstrapState $state ) method (source).

Bootstrap steps

When the process( BootstrapState $state ) method of a WP_CLI\Bootstrap\BootstrapStep object is being called, that object will execute its tasks to take care of its responsibilities and then return the (potentially modified) $state.

Each step works in isolation, so that they can be added/removed/rearranged as needed.

The current code does not allow for the list of steps to be modified from outside code yet, while we collect data and feedback about this new mechanism. However, if we feel confident about the reliability and usefulness, we might open up the array of steps for modification with a later release. If you feel you have a valid use case for such modifications to the bootstrapping process, please let us know!

Bootstrap state

The WP_CLI\Bootstrap\BootstrapState object that is being passed from one step to the next is a very basic key-value store. It currently only knows about one key, BootstrapState::IS_PROTECTED_COMMAND, which is used to skip certain steps when dealing with protected commands (source).

The only protected command right now is wp cli info (source). This protection means that loading of external command packages and --required files is skipped, so that the command can not be overridden. In this way, you can always be sure that the wp cli info command is indeed the one provided by the framework.

Split autoloader

The current implementation uses a custom Composer plugin to split the Composer autoloader provided by the wp-cli/wp-cli package into two separate autoloaders (source). This is needed to allow autoloaders from external command packages to take precedence over the bundled commands. Otherwise, you would not be able to update bundled commands through the built-in package manager.

This is only a workaround to get around the fact that the “WP-CLI Framework” would actually need to be a separate repository from the “bundled WP-CLI”. If the repositories themselves should be split at a later date, this custom Composer plugin will not be needed and removed again. So don’t rely on this plugin or the functionality it provides to be available.