WP_CLI::add_command()public staticWP-CLI 1.0

Register a command to WP-CLI.

WP-CLI supports using any callable class, function, or closure as a command. WP_CLI::add_command() is used for both internal and third-party command registration.

Command arguments are parsed from PHPDoc by default, but also can be supplied as an optional third argument during registration.

# Register a custom 'foo' command to output a supplied positional param.
#
# $ wp foo bar --append=qux
# Success: bar qux

/**
 * My awesome closure command
 *
 * <message>
 * : An awesome message to display
 *
 * --append=<message>
 * : An awesome message to append to the original message.
 *
 * @when before_wp_load
 *\/
$foo = function( $args, $assoc_args ) {
	WP_CLI::success( $args[0] . ' ' . $assoc_args['append'] );
};
WP_CLI::add_command( 'foo', $foo );

Method of the class: WP_CLI{}

No Hooks.

Return

true|false. True on success, false if deferred, hard error if registration failed.

Usage

$result = WP_CLI::add_command( $name, $callable, $args );
$name(string) (required)
Name for the command (e.g. "post list" or "site empty").
$callable(callable) (required)
Command implementation as a class, function or closure.
$args(array)

An associative array with additional registration parameters.

Default: []

  • before_invoke(callable)
    Callback to execute before invoking the command.

  • after_invoke(callable)
    Callback to execute after invoking the command.

  • shortdesc(string)
    Short description (80 char or less) for the command.

  • longdesc(string)
    Description of arbitrary length for examples, etc.

  • synopsis(string)
    The synopsis for the command (string or array).

  • when(string)
    Execute callback on a named WP-CLI hook (e.g. before_wp_load).

  • is_deferred(true|false)
    Whether the command addition had already been deferred.

WP_CLI::add_command() code WP-CLI 2.8.0-alpha

public static function add_command( $name, $callable, $args = [] ) {
	// Bail immediately if the WP-CLI executable has not been run.
	if ( ! defined( 'WP_CLI' ) ) {
		return false;
	}

	$valid = false;
	if ( is_callable( $callable ) ) {
		$valid = true;
	} elseif ( is_string( $callable ) && class_exists( (string) $callable ) ) {
		$valid = true;
	} elseif ( is_object( $callable ) ) {
		$valid = true;
	} elseif ( Utils\is_valid_class_and_method_pair( $callable ) ) {
		$valid = true;
	}
	if ( ! $valid ) {
		if ( is_array( $callable ) ) {
			$callable[0] = is_object( $callable[0] ) ? get_class( $callable[0] ) : $callable[0];
			$callable    = [ $callable[0], $callable[1] ];
		}
		self::error( sprintf( 'Callable %s does not exist, and cannot be registered as `wp %s`.', json_encode( $callable ), $name ) );
	}

	$addition = new CommandAddition();
	self::do_hook( "before_add_command:{$name}", $addition );

	if ( $addition->was_aborted() ) {
		self::warning( "Aborting the addition of the command '{$name}' with reason: {$addition->get_reason()}." );
		return false;
	}

	foreach ( [ 'before_invoke', 'after_invoke' ] as $when ) {
		if ( isset( $args[ $when ] ) ) {
			self::add_hook( "{$when}:{$name}", $args[ $when ] );
		}
	}

	$path = preg_split( '/\s+/', $name );

	$leaf_name = array_pop( $path );

	$command = self::get_root_command();

	while ( ! empty( $path ) ) {
		$subcommand_name = $path[0];
		$parent          = implode( ' ', $path );
		$subcommand      = $command->find_subcommand( $path );

		// Parent not found. Defer addition or create an empty container as
		// needed.
		if ( ! $subcommand ) {
			if ( isset( $args['is_deferred'] ) && $args['is_deferred'] ) {
				$subcommand = new CompositeCommand(
					$command,
					$subcommand_name,
					new DocParser( '' )
				);

				self::debug(
					"Adding empty container for deferred command: {$name}",
					'commands'
				);

				$command->add_subcommand( $subcommand_name, $subcommand );
			} else {
				self::debug( "Deferring command: {$name}", 'commands' );

				self::defer_command_addition(
					$name,
					$parent,
					$callable,
					$args
				);

				return false;
			}
		}

		$command = $subcommand;
	}

	$leaf_command = CommandFactory::create( $leaf_name, $callable, $command );

	// Only add a command namespace if the command itself does not exist yet.
	if ( $leaf_command instanceof CommandNamespace
		&& array_key_exists( $leaf_name, $command->get_subcommands() ) ) {
		return false;
	}

	// Reattach commands attached to namespace to real command.
	$subcommand_name  = (array) $leaf_name;
	$existing_command = $command->find_subcommand( $subcommand_name );
	if ( $existing_command instanceof CompositeCommand && $existing_command->can_have_subcommands() ) {
		if ( $leaf_command instanceof CommandNamespace || ! $leaf_command->can_have_subcommands() ) {
			$command_to_keep = $existing_command;
		} else {
			$command_to_keep = $leaf_command;
		}

		self::merge_sub_commands( $command_to_keep, $existing_command, $leaf_command );
	}

	/** @var Dispatcher\Subcommand|Dispatcher\CompositeCommand|Dispatcher\CommandNamespace $leaf_command */

	if ( ! $command->can_have_subcommands() ) {
		throw new Exception(
			sprintf(
				"'%s' can't have subcommands.",
				implode( ' ', Dispatcher\get_path( $command ) )
			)
		);
	}

	if ( isset( $args['shortdesc'] ) ) {
		$leaf_command->set_shortdesc( $args['shortdesc'] );
	}

	if ( isset( $args['longdesc'] ) ) {
		$leaf_command->set_longdesc( $args['longdesc'] );
	}

	if ( isset( $args['synopsis'] ) ) {
		if ( is_string( $args['synopsis'] ) ) {
			$leaf_command->set_synopsis( $args['synopsis'] );
		} elseif ( is_array( $args['synopsis'] ) ) {
			$synopsis = SynopsisParser::render( $args['synopsis'] );
			$leaf_command->set_synopsis( $synopsis );
			$long_desc = '';
			$bits      = explode( ' ', $synopsis );
			foreach ( $args['synopsis'] as $key => $arg ) {
				$long_desc .= $bits[ $key ] . "\n";
				if ( ! empty( $arg['description'] ) ) {
					$long_desc .= ': ' . $arg['description'] . "\n";
				}
				$yamlify = [];
				foreach ( [ 'default', 'options' ] as $key ) {
					if ( isset( $arg[ $key ] ) ) {
						$yamlify[ $key ] = $arg[ $key ];
					}
				}
				if ( ! empty( $yamlify ) ) {
					$long_desc .= Spyc::YAMLDump( $yamlify );
					$long_desc .= '---' . "\n";
				}
				$long_desc .= "\n";
			}
			if ( ! empty( $long_desc ) ) {
				$long_desc = rtrim( $long_desc, "\r\n" );
				$long_desc = '## OPTIONS' . "\n\n" . $long_desc;
				if ( ! empty( $args['longdesc'] ) ) {
					$long_desc .= "\n\n" . ltrim( $args['longdesc'], "\r\n" );
				}
				$leaf_command->set_longdesc( $long_desc );
			}
		}
	}

	if ( isset( $args['when'] ) ) {
		self::get_runner()->register_early_invoke( $args['when'], $leaf_command );
	}

	if ( ! empty( $parent ) ) {
		$sub_command = trim( str_replace( $parent, '', $name ) );
		self::debug( "Adding command: {$sub_command} in {$parent} Namespace", 'commands' );
	} else {
		self::debug( "Adding command: {$name}", 'commands' );
	}

	$command->add_subcommand( $leaf_name, $leaf_command );

	self::do_hook( "after_add_command:{$name}" );
	return true;
}