WP-CLI allows you to add your own command. To achieve that, just write your command handler and use add_command()
to register it to WP-CLI. In the following content, you’ll get to know how to add a single custom command or a group of custom commands to WP-CLI.
Example 1: Add a single custom WP-CLI command
If you are intending to add just a single simple command, you may just write a function handler. If you need to add a group of commands, see the second example.
Step 1: Write your custom command handler
The command handler accepts two parameters. Both of them are the parameters passed to the command.
$args
, an array of positional arguments that does not start with--
.$assoc_args
, an array of associative arguments that starts with--
.
For example the command wp post update
.
$ wp post update 26 --post_name=wp-cli-command-examples --post_category=25,33
In the above example, the values of $args
and $assoc_args
will be:
$args = array( "id" );
$argv = array(
"post_name" => "wp-cli-command-exmples",
"post_category" => "25,33"
);
Note:
In the above example, the value of
post_category
parameter is a string instead of an array. It is up to the handler to parse the value to an array.
If you want to update a post’s author, you need to pass an user ID to wp post update
command instead of the user name. Therefore we implement a custom command that allows using user name.
In the example we name the custom command wp update-post-author
. You may write it in a single file or just write it in your theme’s function.php
file. Here we create a new file named wpc-cli-update-post-author.php
in the current theme directory.
wp-cli-update-post-author.php:
/**
* WP-CLI custom command: Update the author of a post
* Syntax: wp update-post-author <id> <author name|author id>
* Examples:
* 1. Update author by name for post 123: wp update-post-author 123 john
* 2. Update author by id for post 123: wp udpate-post-author 123 2
*/
function wp_cli_update_post_author( $args, $assoc_args ) {
if ( empty( $args ) || count( $args ) < 2 ) {
WP_CLI::error( 'ID or post author is not specified.' );
}
// Get post_author ID if it is a name
$post_author = $args[1];
$post_author_id;
if ( ! is_numeric( $post_author ) ) {
$post_author_id = username_exists( $post_author );
if ( $post_author_id === false ) {
WP_CLI::error( "Post author '$post_author' not exist." );
}
} else {
$post_author_id = intval( $post_author );
}
$params = array (
'ID' => intval( $args[0] ),
'post_author' => $post_author_id
);
$response = wp_update_post( $params, true );
if ( is_wp_error( $response ) ) {
WP_CLI::error( $response->get_error_message() );
} else {
WP_CLI::success( 'Updated!' );
}
}
WP-CLI provides some functions for outputting to the command interface from the handler.
WP_CLI::line( $message )
, display informational message without prefix to STDOUT. Note it ignores--quiet
. NewWP_CLI::log()
is typically recommended instead ofWP_CLI::line()
.WP_CLI::log( $message )
, display informational message without prefix to STDOUT. Note it discard message when--quiet
flag is supplied.WP_CLI::debug( $message, $group=false)
, display debug message prefixed with “Debug: ” to STDERR when--debug
is used. Note it also output script execution time.WP_CLI::warning( $message)
, display warning message prefixed with “Warning: ” to STRERR.WP_CLI::success( $message )
, display success message prefixed with “Success: ” to STDOUTWP_CLI::error( $message, $exit=true)
, display error message prefixed with “Error: ” to STDERR and exit script.WP_CLI::error_multi_line( array $message_lines )
, display a multi-line error message in a red box to STDERR. Note it doesn’t exit script.WP_CLI::confirm()
,WP_CLI::read_value()
, etc. See more on WP-CLI internal apis.
Note:
Make sure your command name in unique.
Step 2: Register your custom command to WP-CLI
Registering a command is simple, just add below code to your theme’s function.php
.
if ( defined( 'WP_CLI' ) && WP_CLI ) {
wp_require_once ( "wp-cli-update-post-author.php" );
WP_CLI::add_command( 'update-post-author', 'wp_cli_update_post_author' );
}
Step 3: Test your custom command
Make sure your WordPress is started. Below is the output when running wp get-post-cats
.
# Get the original author
$ wp post get 123 --field=post_author
1
$ wp update-post-author 123 john
Success: Updated!
# Check the result
$ wp post get 123 --field=post_author
2
Note:
If you gets some notice information besides the normal output, see how to supress WP-CLI notices.
Example 2: Add a group of custom WP-CLI commands
The process of adding a custom command with multiple subcommands is similar to that adding one. The difference is you need to extending WP_CLI_Command
class and implement subcommands in it. WP_CLI::add_command()
will automatically infer those subcommands inside it.
In the below example, we implement a command named wp post-category
,it has two sub commands wp post-category add
and wp post-category remove
which adds or removes categories of a post.
<?php
/**
* WP-CLI custom command: post-category
* Subcommand:
* - add
* - remove
*/
class Post_Category_Command extends WP_CLI_Command {
private function add_or_remove_category( $action, $args, $assoc_args ) {
if ( empty( $args ) || count( $args ) < 2 ) {
WP_CLI::error( 'ID or author is not specified.' );
}
$id = intval( $args[0] );
$original_cats = get_the_category( $id );
$original_cat_ids = array();
foreach( $original_cats as $c ) {
$original_cat_ids[$c->term_id] = $c->name;
}
array_shift( $args );
$cats = $args;
$updated_cats = array();
foreach( $cats as $cat ) {
$cat_id = null;
if ( ! is_numeric( $cat ) ) {
$cat_id = category_exists( $cat );
if ( $cat_id === false ) {
WP_CLI::warning( "No such post category '$cat'." );
continue;
}
} else {
$cat_id = intval( $cat );
}
if ( $action === 'add' ) {
if ( ! array_key_exists( $cat_id, $original_cat_ids ) ) {
$original_cat_ids[$cat_id] = $cat_id;
$updated_cats[] = $cat;
} else {
WP_CLI::warning( "Post category '$cat' already exists for the post." );
}
} else {
if ( array_key_exists( $cat_id, $original_cat_ids ) ) {
unset( $original_cat_ids[ $cat_id ] );
$updated_cats[] = $cat;
} else {
WP_CLI::warning( "Post category '$cat' does not exist for the post." );
}
}
}
$params = array (
'ID' => $id,
'post_category' => array_keys( $original_cat_ids )
);
$response = wp_update_post( $params, true );
if ( is_wp_error( $response ) ) {
WP_CLI::error( $response->get_error_message() );
} else {
$msg = ( $action === 'add' ) ? 'Added categories: ' : 'Removed categories: ';
WP_CLI::success( $msg . implode( ',', $updated_cats ) );
}
}
/**
* Subcommand: Add one or multiple categories to a post.
* Syntax: post-category add <id> <category_name|category_id> [category_name|category_id...]
* Examples:
* 1. Add categories of php and wordpress to post 123:
* "wp post-category add 123 php wordpress"
* 2. Add category 2 to post 123:
* "wp post-category add 123 2"
*/
public function add( $args, $assoc_args ) {
$this->add_or_remove_category( 'add', $args, $assoc_args );
}
/**
* Subcommand: Remove one or multiple categories from a post.
* Syntax: post-category add <id> <category_name|category_id> [category_name|category_id...]
* Examples:
* 1. Remove category wordpress from post 123: "wp post-category remove 123 wordpress"
* 2. Remove category 2 from post 123: "wp post-category remove 123 2"
*/
public function remove( $args, $assoc_args ) {
$this->add_or_remove_category( 'remove', $args, $assoc_args );
}
}
Add below code to your theme’s function.php
.
if ( defined( 'WP_CLI' ) && WP_CLI ) {
WP_CLI::add_command( 'post-category', 'Post_Category_Command' );
}
Now you are ready to run these custom commands like below:
# Add category 'php' and 'wordpress' for post with ID '123'.
$ wp post-category add 123 php wordpress
Success: Removed categories: php
# Remove category 'php' for post with ID '123'.
$ wp post-category remove 123 php
Success: Removed categories: php
# Remove category 'php' for post with ID '123' again.
# Because the post has not belong to 'php', it gives warning for that information.
$ wp post-category remove 123 php
Warning: Post category 'php' does not exist for the post.
Success: Removed categories: