Almost every major site I work on has at least one custom wp-cli command that I’ve built to manage or automate things. But I always run into the same problem, I don’t want my command to be a root command, I want it to live in a namespace of my own. But, I also don’t want to create a blank command that doesn’t do anything just for the sake of this namespace.
For instance, if I register a command using this:
WP_CLI::add_command('custom-command do-thing', DoThingCommand::class);
WordPress will show the below if I just type wp
:
cache Adds, removes, fetches, and flushes the WP Object Cache object.
cap Adds, removes, and lists capabilities of a user role.
cli Review current WP-CLI info, check for updates, or see defined aliases.
comment Creates, updates, deletes, and moderates comments.
config Generates and reads the wp-config.php file.
core Downloads, installs, updates, and manages a WordPress installation.
cron Tests, runs, and deletes WP-Cron events; manages WP-Cron schedules.
custom-command
db Performs basic database operations using credentials stored in wp-config.php.
embed Inspects oEmbed providers, clears embed cache, and more.
eval Executes arbitrary PHP code.
eval-file Loads and executes a PHP file.
If you don’t notice or are unable to see the problem, each command listed has an “intro” description except for my command which instead just has a blank space.
Instead of grepping all of wp-cli’s code, I luckily had Yoast installed, too, so I grepped their code and saw a special class from core that you can extend call CommandNamespace
which has the following comment:
Adds a command namespace without actual functionality.
This is meant to provide the means to attach meta information to a namespace when there’s no actual command needed.
In case a real command gets registered for the same name, it replaces the command namespace.
https://github.com/wp-cli/wp-cli/blob/bc37f66e25b9992813b0c50b933aefbf88718e6a/php/WP_CLI/Dispatcher/CommandNamespace.php#L8
So, just create a class that extends that (and probably make it final), register it like a normal command, and WordPress will do the rest for you.