Where to put the code



Make a folder called /mu-plugins (stands for must-use plugins) and put it in wp-content.

mkdir /public_html/wp-content/mu_plugins

Your code will go in here.

Make sure you have WP CLI installed



Run `$wp`. You should see something like this:

NAME wp DESCRIPTION Manage WordPress through the command-line. SYNOPSIS wp SUBCOMMANDS cache Manage the object cache. cap Manage user capabilities. [truncated]

It comes installed already on some hosts, but if not, you’ll have to install it yourself. Follow the directions here, and prepare for a small war with your computer: the installation process is not as flawless as it could be. https://github.com/wp-cli/wp-cli

Make a “Hello World”



Create a file for it.

$vim vip_hello_world.php

Since code in /mu-plugins will run automatically (no need to attach it to a hook or whatever), you need to make sure that command line tools don’t accidentally run when a user visits your website – only when they’re called from the command line.

Open the file like so:

<?php if ( ! defined( 'WP_CLI' ) && WP_CLI ) { return; }

WP_CLI_Command is the base class for WP-CLI commands. If you’re an Automattician, you probably have this directory synced up somewhere on your computer: https://vip-svn.wordpress.com/plugins/

In that directory, find the file vip-wp-cli.php, which extends WP_CLI_Command. Include that file in your script. In my case:

require_once( '~/klunydekluns.dev.dfw.wordpress.com/wp-content/themes/vip/plugins/vip-do-not-include-on-wpcom/vip-wp-cli.php' );

If you’re not an Automattician, those instructions will make no sense to you. Instead you should find the local path to this file in the package you downloaded during the WP CLI install process:

https://github.com/wp-cli/wp-cli/blob/master/php/class-wp-cli-command.php

And `require_once path/to/wp-cli/wp-cli/blob/master/php/class-wp-cli-command.php`.

Create a new class extending that file:

class VIP_Hello_World extends WPCOM_VIP_CLI_Command {

And write your hello function.

public function hello() { echo "Hello World!"; }

Finally, register the command as “hello” so that you can run it.

WP_CLI::add_command( 'hello', 'VIP_Hello_World' );

Here’s the complete code:

<?php if ( ! defined( 'WP_CLI' ) && WP_CLI ) { return; } require_once( '/Users/shannon/Sandbox/klunydekluns.dev.dfw.wordpress.com/wp-content/themes/vip/plugins/vip-do-not-include-on-wpcom/vip-wp-cli.php' ); class VIP_Hello_World extends WPCOM_VIP_CLI_Command { public function hello() { echo "Hello World!"; } } WP_CLI::add_command( 'hello', 'VIP_Hello_World' );

Now try to run it.

$wp hello usage: wp hello hello See 'wp help hello <command>' for more information on a specific command. $wp hello hello Hello World!$

See the error? The add_command line registers the class as a command, and the methods within the class are subcommands. `$wp hello hello` spits out your hello world. Let’s change it to “hippo” and see what happens.

WP_CLI::add_command( 'hippo', 'VIP_Hello_World' );

$wp hippo hello Hello World!$

Ok, so value in add_command() is the first part of the command, let’s make sure we know about the second part of the command. We’ll change it to “potamus”.

public function potamus() { echo "Hello World!"; }

$wp hippo potamus Hello World!$

As expected. What if you want it to work as just “wp hello” though? If you make a method called `__invoke()`, that will run automatically.

public function __invoke() { echo "Hello World!"; }

$wp hello Hello World!$

Nice. Ok, there are other things we can do with the WP CLI. We can pass in arguments and options. We can ask the user for input and change the logic flow based on it. We can notify when something happens, and we can show a progress bar during a long-running operation.

Arguments, options, input

Let’s try accepting some arguments.

public function __invoke( $args, $assoc_args ) { print_r($args); echo "Hello World!"; }

$wp hello o hai what now Array ( [0] => o [1] => hai [2] => what [3] => now ) Hello World!

Cool. So anything after the command arrives in $args as an element in an indexed array. What about $assoc_args?

public function __invoke( $args, $assoc_args ) { print_r($assoc_args); echo "Hello World!"; }

$wp hello --name="Shannon" --age=27 --location=Denmark Array ( [name] => Shannon [age] => 27 [location] => Denmark ) Hello World!

Cool, named arguments arrive as associative elements in $assoc_args. Let’s try that again. I’ve also added some documentation to help our future users. To see the doc, run `$wp hello –help`.

/** * Hello World * * ## OPTIONS * * --name=<name> * : Your name. * * --age=<age> * : Your age. * * [--location=<location>] * : Your location. Default: Earth. * * ## EXAMPLES * * wp hello --name=Shannon --age=27 * wp hello --name="Joe Snow" --age=100 --location=Vancouver */ public function __invoke( $args, $assoc_args ) { WP_CLI::confirm("Are you sure you want to proceed?"); if(empty($assoc_args['location'])){ $assoc_args['location'] = "Earth"; } print_f("You are %s, %s old, and located in %s", $assoc_args['name'], $assoc_args['age'], $assoc_args['location']); }

$wp hello --name="Shannon" --age=27 --location=Denmark Are you sure you want to proceed? [y/n] y You are Shannon, 27 old, and located in Denmark$ $ $wp hello --name="Shannon" --age=27 --location=Denmark Are you sure you want to proceed? [y/n] n $ $wp hello --name="Shannon" --age=27 Are you sure you want to proceed? [y/n] y You are Shannon, 27 old, and located in Earth

You can get a lot done with just that. But what if you’re cooking up a script that sorts through millions of records and does some complicated processing? A progress bar to show something happening is really helpful. I’ll change the program to simulate some heavy processing with a sleep() command and tell us how long it took.

Progress Bars

/** * Hello World * * ## OPTIONS * * [--wait=<wait>] * : How long do you want to wait? * * ## EXAMPLES * * wp hello --wait=30 * */ public function __invoke( $args, $assoc_args ) { WP_CLI::confirm("Are you sure you want to proceed? y/n"); $total_iterations = 10; $notify = \WP_CLI\Utils\make_progress_bar( "Sleeping...", $total_iterations ); $time_start = time(); for($i = 0; $i < $total_iterations; $i++) { $notify->tick(); if(isset($assoc_args['wait'])) { sleep($assoc_args['wait']); } } $notify->finish(); $time_end = time(); WP_CLI::success( sprintf("Finished in %d seconds.", ($time_end - $time_start) ) ); }

$wp hello Are you sure you want to proceed? [y/n] y Removing 0 post(s) 100% [============================================================================] 0:00 / 0:00 Success: Finished in 0 seconds.

$wp hello --wait=2 Are you sure you want to proceed? [y/n] y Sleeping... 100% [===================================================================================] 0:20 / 0:20 Success: Finished in 20 seconds.

It’s fun, like watching paint dry!

Hope this helps you get started with making WP CLI commands.

I borrowed a lot of code from this example, which you will only be able to view if you’re a member of the repository: https://github.com/Automattic/vip-go-mu-plugins/pull/615/files