Adjusting a plugin, to user’s needs is one of the main agendas every plugin owner has to follow. For a front-page slider that means more color-pickers, fonts and similar visual options. However, if you’re catering to developers, admins, and other power-users sooner or later, they’ll want CLI support. They’ll want to ditch the mouse and work only with the keyboard. Thanks to the WP-CLI project adding CLI support to your plugin is a piece of cake.

The eternal GUI vs CLI battle

Let’s get something out of the way: GUI (Graphical User Interface) is not better than CLI (Command Line Interface) and vice-versa: CLI is not better than GUI. People prefer one over the other. It’s a matter of personal preference or habit. “Are they the same, are they interchangeable?” With some compromises, yes they can be but, nobody likes to pick colors in a black&white command line interface. That’s simply counterproductive. They each serve a specialized purpose.

“So why do we need both? Isn’t WP more GUI oriented?” It is, WP is more GUI oriented. But not for all users. Some people use WP in a way that’s more suited for CLI, and it enables them to work much faster with it. Moreover, why not have both? It doesn’t bloat anything or get in the way.

So, WP-CLI is a plugin, right?

No, it’s not a plugin. You don’t need to add anything to a WordPress installation for WP-CLI to work. You only need WP-CLI on your OS. WP-CLI is written in PHP and packed in a phar. It’s a way to put an entire PHP application into a single file, a “phar” (PHP Archive) for easy distribution and installation across various OS-es. Installation process depends on your operating system, but it’s easy and well documented in the WP-CLI handbook – or if you’re more into videos here’s one of WP-CLI installation on Windows.

I’m not going to repeat any of the material above. It’s detailed enough and should get you going with WP-CLI in a matter of minutes. When you have it running, change your working directory to the WP installation you plan on working with and run wp option get home to make sure you’re on the right WP installation and that WP-CLI works.

Working with WP-CLI on Windows 10 – Output for our custom “site-info” commands

It’s simpler than it looks

First, we need a function to tell us if the user is interacting with WP via CLI or not. It’s useful for many things such as not sending any HTTP headers while in CLI and for not including CLI functions on “regular” calls. It also gives us an opportunity to reuse old functions originally written for GUI with just some minor changes.

function is_cli_running() {
  return defined( 'WP_CLI' ) && WP_CLI;
}

Next step is to figure out a name for your CLI command. There are around 40 built-in commands. So you can’t use any of those names, and you should stay clear of any brand names such as “google” as you probably don’t own Google. Ideally, it should be the name of your plugin or an umbrella name for a set of functions it does so that you can put all commands under that one in an effort not to pollute the main namespace. It’s common sense, like with any piece of code. Let’s use site-info and we’ll make a few functions that return various information about the site.

To keep things neat and tidy put all WP-CLI related code into a new file – custom-wp-cli-commands.php. We’ll only include that file when it’s needed and when all CLI related code is available. For that, we’ll use the function we just built. For the sake of testing and learning put the file in your active theme’s folder and then add this to theme’s functions.php file.

if ( is_cli_running() ) {
  require_once 'custom-wp-cli-commands.php';
}

Then, put this in custom-wp-cli-commands.php;

/**
 * Just a few sample commands to learn how WP-CLI works
 */
class cli_site_info extends WP_CLI_Command {
  /**
   * Display version information.
   * ## OPTIONS
   *
   * [--wponly]
   * : Shows only WP version info, omitting the plugin one.
   */
  function version( $args, $assoc_args ) {
    if ( !empty( $assoc_args['wponly'] ) ) {
      WP_CLI::line( 'Version of WordPress is ' . get_bloginfo( 'version' ) . '.' );
    } else {
      WP_CLI::line( 'Version of this plugin is 0.1-beta, and version of WordPress ' . get_bloginfo( 'version' ) . '.' );
    }
  }
    
    
  /**
   * Display the number of plugins.
   */
  function plugins() {
    WP_CLI::line( 'There are a total of ' . sizeof( get_plugins() ) . ' plugins on this site.' );
  }
}

WP_CLI::add_command( 'site-info', 'cli_site_info' );

If you open the site, homepage or admin, in a browser nothing will happen. That’s good. To test the new CLI command go back to your command line window, run wp site-info version and you’ll get the plugin and site version. Or run wp site-info plugins and you’ll get the total number of plugins on the site. Easy, right? Let’s go over the code.

As easy as extending a PHP class

Our class cli_site_info extends the WP_CLI_Command class; nothing fancy there. You can call the class whatever you like. What’s important is the code on the last line of the file – WP_CLI::add_command( 'site-info', 'cli_site_info' ). It registers our top-level command and ties our class to it. If you want to change the site-info command to something else, this is the place to do it.

Every public method (function) in the class is a subcommand in WP-CLI. Be sure to check out the anatomy of a command to learn the proper WP-CLI lingo. There’s no need to “register” the method anywhere or do anything extra. Like we did for plugins() and version() – create a standard function, and that’s it. WP-CLI will know what to do with it.

Once you’re in the method, you can run any code you need. Interacting with the CLI, however, will require some custom functions as things like echo won’t work as expected. Instead of echo there’s WP_CLI::line(). The internal WP-CLI API covers everything you need and all functions are well documented as well as separated into the input, output, misc, system and other categories which makes them super-easy to find.

Besides printing text, you’ll probably want to use (associative) command arguments so you can call things like wp site-info version --wponly (try it out) which outputs only the WP version info. Associative arguments are stored in the method’s second function argument. In our case it’s called $assoc_args. The only thing that’s left is to test the array key for a specific value and adjust the code accordingly, as we did in function version( $args, $assoc_args ).

Documentation and in-CLI help

WP-CLI has a built-in help system. It’s quite handy. There’s never a need for any external documentation for a command if the developer invests a bit of time to describe the command in his code. The documentation won’t write itself (unfortunately) but if you invest the bare minimum while creating your commands users will be eternally grateful as you’ll put all the docs under one roof.

You write the docs in your class as comments, using the PHPDoc format. For digging deeper check out the CLI Handbook. By running wp help site-info you’ll get a list and description of our subcommands, and if you look in the code, you’ll see where it comes from. Very self-explanatory. For more details on the version subcommand run wp help site-info version and you’ll get details about options too.

Make your users happy

Sure, if you’re developing a weather widget adding WP-CLI support doesn’t sound like the right move. However, any tool used by die-hard devs and admins such as WP Reset will greatly benefit from WP-CLI. Users will be able to chain commands, write bash scripts and generally get more things done faster and easier. That leads to better reviews, happier users, more users and in the end more money for you, regardless of the monetization model you have in place.

  1. Using IF/ELSE for booleans is redundant:

    function is_cli_running() {
      if ( defined( 'WP_CLI' ) && WP_CLI ) {
        return true;
      } else {
        return false;
      }
    }
    

    Use:

    function is_cli_running() {
      return defined( 'WP_CLI' ) && WP_CLI;
    }
    

    Same result, less CPU cycles wasted, easier to read and understand.
    Even if you do want to use IF (no, you don’t), ELSE isn’t needed at all:

    function is_cli_running() {
      if ( defined( 'WP_CLI' ) && WP_CLI ) {
        return true;
      }
      return false;
    }
    
    1. Hi Ihor,
      True if() is not needed here. I’ve updated the code in the article.

      Is it easier to understand? Wouldn’t be so sure for people who are just starting out.


Leave a Reply

Your email address will not be published. Required fields are marked *