Title: Write custom WP-CLI commands
Author: WordPress VIP Documentation
Published: December 29, 2020
Last modified: September 17, 2025

---

 1. [VIP-CLI](https://docs.wpvip.com/vip-cli/)
 2. [WP-CLI with VIP-CLI](https://docs.wpvip.com/vip-cli/wp-cli-with-vip-cli/)
 3. Write custom WP-CLI commands

#  Write custom WP-CLI commands

WP-CLI commands can be created and run using VIP-CLI on the VIP platform. The best
practices outlined here are an extension of the developer documentation in the [WP-CLI Handbook](https://make.wordpress.org/cli/handbook/)
and the [Commands Cookbook](https://make.wordpress.org/cli/handbook/guides/commands-cookbook/).

A custom WP-CLI command is registered using `[WP_CLI::add_command()](https://make.wordpress.org/cli/handbook/references/internal-api/wp-cli-add-command/)`,
which accepts 3 parameters.

 * The first argument `$name` is the name of the command to call inside the `wp`
   CLI namespace.
   For example, to build a command `wp sample` the command would 
   be registered with the the `$name` `'sample'`.
 * The second argument `$callable` is a callable item, like a function, closure,
   callable class or anonymous function.
 * The optional third argument `$args` is used to define other characteristics of
   the command.

## Write a function based command

This example shows a basic registration for a custom command `wp sample`.

    ```lang-php
    <?php
    function sample_command( $args ) {
        WP_CLI::success( 'Thank you for running the sample command.' );
    }
    WP_CLI::add_command( 'sample', 'sample_command' );
    ```

More examples and guidance for custom WP-CLI commands can be found in the [WP-CLI Commands Cookbook](https://make.wordpress.org/cli/handbook/guides/commands-cookbook/#required-registration-arguments).

## Write class-based commands

Registering a PHP class as the `$callable` second argument for `[WP_CLI::add_command()](https://make.wordpress.org/cli/handbook/references/internal-api/wp-cli-add-command/)`
can be done in a variety of ways.

The PHP Magic Method `__invoke()` can be used to pass either the class name or an
instance of the class. Both examples of registering the command below are functionally
equivalent methods to register the command `wp env-check`.

    ```lang-php
    <?php
    class Example_Command {
        protected $environment;

        public function __construct( ) {
            $this->environment = wp_get_environment_type();
        }

        public function __invoke( $args ) {
            WP_CLI::log( sprintf( 'The current environment is: %s', $this->environment ) );
        }
    }
    // 1. Register the instance for the callable parameter.
    $instance = new Example_Command();
    WP_CLI::add_command( 'env-check', $instance );

    // 2. Register object as a function for the callable parameter.
    WP_CLI::add_command( 'env-check', 'Example_Command' );
    ```

### Subcommand support

To register a command that supports multiple subcommands, use a class with methods
that match the subcommand names. The following is an example that implements subcommands:`
wp example environment` and `wp example subcommand`.

    ```lang-php
    <?php
    class Example_Command {

    	// Usage: wp example environment
    	public function environment( $args ) {
            WP_CLI::log( sprintf( 'Environment: %s', wp_get_environment_type() ) );
    	}

    	// Usage: wp example subcommand
    	public function subcommand() {
            WP_CLI::log( sprintf( 'You have run a subcommand' ) );
    	}
    }
    WP_CLI::add_command( 'example', 'Example_Command' );
    ```

## Handle CLI arguments

When run, a WP-CLI command passes 2 arguments to the callable handler, `$args` and`
$assoc_args`. Both are iterators, or arrays, of parameters that are passed to the
WP-CLI command. `$args` is an iterator of the unnamed, or positional arguments and`
$assoc_args` is an iterator of named, or associative arguments. Associative arguments
are sometimes referred to as “flags”.

By using the `[wp_parse_args()](https://developer.wordpress.org/reference/functions/wp_parse_args/)`
function the default values for optional parameters in a command’s function can 
be set.

    ```lang-php
    function example_command( $args,  $assoc_args ) {
    	$assoc_args = wp_parse_args(
    		$assoc_args,
    		array(
    			'dry-run'   => true,
    			'format'    => 'table'
    			'post-meta' => 'some_default_post_meta'
    		)
    	);
    }
    ```

## WP-CLI output functions

The WP-CLI natively supports a variety of methods for outputting to the screen while
running a WP-CLI command.

The most commonly used output methods are `[WP_CLI::success()](https://make.wordpress.org/cli/handbook/references/internal-api/wp-cli-success/)`
and `[WP_CLI::error()](https://make.wordpress.org/cli/handbook/references/internal-api/wp-cli-error/)`
to indicate the final result of an action, and `[WP_CLI::log()](https://make.wordpress.org/cli/handbook/references/internal-api/wp-cli-log/)`
for informational output while the command is running.

Using `[WP_CLI::error()](https://make.wordpress.org/cli/handbook/references/internal-api/wp-cli-error/)`
will interrupt the command by causing the script to `exit` , and will prevent the
rest of the command from continuing.  If only the error-like condition that the 
script encountered without stopping the command is needed, use `[WP_CLI::log()](https://make.wordpress.org/cli/handbook/references/internal-api/wp-cli-log/)`
or `[WP_CLI::warning()](https://make.wordpress.org/cli/handbook/references/internal-api/wp-cli-warning/)`.

| Command | Description | 
| `[WP_CLI::log()](https://make.wordpress.org/cli/handbook/references/internal-api/wp-cli-log/)` | Display informational message without prefix, or discarded when `--quiet` argument is supplied | 
| `[WP_CLI::line()](https://make.wordpress.org/cli/handbook/references/internal-api/wp-cli-line/)` | Display informational message without prefix, and ignores `--quiet` argument
_Note: Using `WP\_CLI::log()` is typically recommended;`WP\_CLI::line()` is included for historical compatibility. | 
| `[WP\_CLI::debug()](https://make.wordpress.org/cli/handbook/references/internal-api/wp-cli-debug/)` | Display debug message prefixed with “Debug: ” when `--debug` argument is supplied | 
| `[WP\_CLI::warning(](https://make.wordpress.org/cli/handbook/references/internal-api/wp-cli-warning/))` | Display warning message prefixed with “Warning: “ | 
| `[WP\_CLI::success()](https://make.wordpress.org/cli/handbook/references/internal-api/wp-cli-success/)` | Display success message prefixed with “Success: “ | 
| `[WP\_CLI::error()](https://make.wordpress.org/cli/handbook/references/internal-api/wp-cli-error/)` | Display error message prefixed with “Error: “, and exits script |

## Include only when the WP-CLI is being used

It is important that `[WP_CLI::add_command()](https://make.wordpress.org/cli/handbook/references/internal-api/wp-cli-add-command/)`
be wrapped inside a check that the constant `WP_CLI` is defined, and evaluates to`
true`, in order to prevent fatal errors. This check is also the best way to identify
if the code is being executed via the WP-CLI.

If the custom WP-CLI command is part of a theme, the check can be added to the theme’s`
functions.php` file like this example:

    ```lang-php
    <?php
    if ( defined( 'WP_CLI' ) && WP_CLI ) {
    	include_once MY_THEME_DIR . '/inc/class-mycommand-cli.php';
    }
    ```

If the custom WP-CLI command is included in a plugin or as part of a Must Use script,
this snippet may be more appropriate:

    ```lang-php
    <?php
    if ( defined( 'WP_CLI' ) && WP_CLI ) {
    	include_once __DIR__ . '/inc/class-mycommand-cli.php';
    }
    ```

Both of the above examples assume both the `[WP_CLI::add_command()](https://make.wordpress.org/cli/handbook/references/internal-api/wp-cli-add-command/)`
to register the command and the associated function or class would be defined in
the `class-mycommand.cli.php` file.

Optionally, this check can be wrapped around the `[WP_CLI::add_command()](https://make.wordpress.org/cli/handbook/references/internal-api/wp-cli-add-command/)`
function to make the class or function available but only register the command when
the WP-CLI is being used.

    ```lang-php
    <?php
    if ( defined( 'WP_CLI' ) && WP_CLI ) {
    	WP_CLI::add_command( 'my-command', 'MyCommand' );
    }
    ```

Last updated: September 17, 2025