Skip to content
On this page

Custom Commands

Sometimes you need to write custom terminal commands to be used within a project, either in production or locally. Laravel has a tool called Artisan, Symfony has Console, WordPress has WP-Cli, Rails has Rake, and so on. These can all usually be extended with custom commands.

Forme has Wrangle.

Writing Commands

Like other similar php framework tools, Wrangle is based on Symfony Console.

To create a custom command, you simply add a command class to the app/Commands/Wrangle directory in the corresponding namespace.

php
<?php
declare(strict_types=1);

namespace Foobar\MyAwesomePlugin\Commands\Wrangle;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputOption;

use function Laravel\Prompts\info;

class MyAwesomeCommand extends Command
{
   protected $defaultName = 'foobar';

  public function configure(): void
  {
    // see https://symfony.com/doc/current/console.html
    $this->addOption(name: 'foo',shortcut: 'f', mode: InputOption::VALUE_OPTIONAL, default: 'bar', description: 'Foo description');
    $this->setDescription('My Awesome Command');
    $this->setHelp('Help text for my awesome command');
  }

  protected function execute(InputInterface $input, OutputInterface $output): int
  {
    // grab user options/arguments (don't forget to validate!)
    $foo = $input->getOption('foo');
    // do/output stuff
    info($foo);

    // return exit code
    return Command::SUCCESS;
  }
}

You should then be able to go to the project root and run ./tools/wrangle foo to run your command and see the output.

Symfony Console

Since this is plain old Symfony Console app, you have access to all the usual Symfony Console functionality and helpers.

See here for a list of available helpers.

Laravel Prompts

Laravel prompts is also available and can be used alongside or instead of the Console helpers. It's a great library with some fantastic looking TUI components and interactions.

Symfony Process

Sometimes you need to run external commands from within your command, otherwise known as "shelling out". Maybe you need to call the globally installed WP Cli for example. You can do that with Symfony Process - see here for more information.

php
use Symfony\Component\Process\Process;

$pluginList = Process::fromShellCommandline('wp plugin list --format=json')->mustRun()->getOutput();

Symlinking in the project root

If you care about command line aesthetics, you can symlink ./tools/wrangle into your project root.

bash
ln -s ./tools/wrangle wrangle

This means you can now run

bash
./wrangle foo
#or
php wrangle foo

Code generation

You can use forme codegen to generate a new custom command.

bash
forme make command MyAwesomeCommand

As a library

Sometimes you want to be able to share a command across different projects and websites. You can do that by creating a composer/packagist library and putting your wrangle commands in there.

Just add your commands to the Commands\Wrangle namespace as you would for a plugin or theme, and then make sure you explicitly require each command file in your composer.json.

json
"autoload": {
  "files": [
    "src/Commands/Wrangle/MyAwesomeCommand.php",
    "src/Commands/Wrangle/MyOtherCommand.php"
  ]
}

After publishing it to a packagist repository, you can now require it like any other library.

How does Wrangle work under the hood?

Like WP Cli, Artisan, Forme codegen and the rest, Wrangle is based on Symfony Console.

Our latest theme and plugin starter boilerplate has a CommandRegistry class which naively globs the files in the theme or plugin's app/Commands/Wrangle directory and requires them as long as we're in a cli context.

Wrangle command libraries need to add each command class file to the autoload files array in their composer.json file so that they're automatically included.

When the wrangle bin script is run from project root, it simply checks - again, naively - for any loaded classes whose namespace contains Commands\Wrangle and adds them to a Symfony console application.

Made by Moussa Clarke @ Sanders Web Works with ❤️