WP-CLI
Foundation WP-CLI provides a command base class and a shared provider for registering commands during WP-CLI bootstrap. Application services remain injectable, command prefixes remain configurable, and feature providers can contribute commands without loading WP-CLI classes during normal WordPress requests.
Installation
Section titled “Installation”Install the runtime package
Section titled “Install the runtime package”Install WP-CLI support as a production dependency when the plugin ships commands:
WP-CLI supplies the WP_CLI and WP_CLI_Command runtime classes. Applications running commands through WP-CLI do not normally need to install wp-cli/wp-cli separately.
Install the generator separately
Section titled “Install the generator separately”Install the developer CLI only when the team wants to generate command classes:
The generator is development tooling and does not need to ship in a standalone plugin archive.
Prepare the application
Section titled “Prepare the application”WP-CLI commands use the same container, configuration, and provider graph as the rest of the application:
Configuration
Section titled “Configuration”Choose the command prefix
Section titled “Choose the command prefix”In the root config.php, configure a stable application prefix for a distributable plugin:
With the example’s default prefix, commands will be registered beneath wp your-plugin. Complete WordPress applications that own the full installation can keep the zero-configuration nx default.
Set FOUNDATION_WPCLI_COMMAND_PREFIX only when WP-CLI should intentionally use a different prefix. In the same root config.php, add the package-specific setting when that environment variable is present:
When the override is absent, WP-CLI uses foundation.prefix.
Generate a command
Section titled “Generate a command”Generate the initial class from the project root:
The generator uses Composer’s PSR-4 mapping to write src/Catalog/Cli/Sync_Catalog_Command.php. It creates a Snake_Case class with examples of a positional argument, associative option, and flag.
Projects using Strauss receive the configured namespace prefix on generated Foundation imports. With update_call_sites=false, handwritten provider imports may also need the project’s Strauss prefix.
Project-specific command stubs can override the default at foundation/stubs/wpcli/command.stub.
Implement the command
Section titled “Implement the command”Keep the command focused on input, output, and selecting the application operation. Inject the service that owns the business behavior rather than resolving it from the container.
In src/Catalog/Cli/Sync_Catalog_Command.php:
The three synopsis types map to WP-CLI input as follows:
| Type | Declaration | Invocation |
|---|---|---|
| Positional | source |
staging |
| Associative | batch-size |
--batch-size=50 |
| Flag | dry-run |
--dry-run |
The command constructor contains only its business dependencies. Foundation supplies the configured prefix later, when WPCliProvider registers the command during cli_init.
Contribute a command from its feature provider
Section titled “Contribute a command from its feature provider”WPCliProvider creates the command registration context from configuration. Feature providers only add their commands to the shared collection.
In src/Catalog/Provider.php:
Add more commands to the same returned array or contribute them from other feature providers. WPCliProvider validates the complete collection before registering any command.
Register the WP-CLI provider
Section titled “Register the WP-CLI provider”In src/App.php, register WPCliProvider before feature providers that contribute commands:
WPCliProvider listens to cli_init and resolves the command collection only when WP-CLI is active. Feature providers should contribute commands to that collection instead of registering their own cli_init hooks.
Register a custom command implementation
Section titled “Register a custom command implementation”Extend Command for Foundation’s synopsis, prompting, and exit-status behavior. A different command abstraction can instead implement StellarWP\Foundation\WPCli\Contracts\RegistrableCommand; its register( CommandContext $context ) method can use $context->name( 'catalog:sync' ) to build the configured command name before calling WP_CLI::add_command().
Run the command
Section titled “Run the command”With the your-plugin application prefix, run:
Inspect the generated synopsis and description with:
Testing
Section titled “Testing”Test business behavior outside the command
Section titled “Test business behavior outside the command”Keep most tests on Catalog_Synchronizer and its collaborators. The command should contain only input normalization, application service invocation, and WP-CLI output behavior.
Execute the registered command
Section titled “Execute the registered command”Use the Codeception wpcli suite for one end-to-end test that proves the provider contribution, command prefix, arguments, output, and exit code work together.
In tests/wpcli/Catalog/SyncCatalogCest.php:
Run the suite through SLIC:
One real command test is more valuable than duplicating the Foundation command wrapper’s generic registration tests throughout the application.
Upgrading to 2.0
Section titled “Upgrading to 2.0”The 1.x Command constructor accepted the Foundation Container and a CommandPrefix. Remove both arguments and the corresponding parent::__construct() call. Command constructors should contain only their application dependencies. If a command previously called $this->container->get(), inject that resolved service directly instead.
WPCliProvider now supplies a CommandContext when it registers contributed commands. Let the provider register commands through WPCliProvider::COMMANDS; direct calls to register() would need to supply the context themselves. If an application command overrides the protected command() method, either remove that override or update it to command( CommandContext $context ): string and use the context to build the configured name.
Custom command abstractions contributed to WPCliProvider::COMMANDS must implement RegistrableCommand instead of being required to extend Foundation’s base Command.