Console Commands
Plugins and modules can add additional console commands
to Craft, which will be available via the craft
executable in the terminal.
Console commands are implemented very similarly to controllers, except that they should live within a console/controllers/
folder within your plugin or module’s base source folder, and they should extend craft5:craft\console\Controller (rather than craft5:craft\web\Controller).
For the most part, writing console commands for Craft is identical to writing console commands for Yii, so be sure to read the Yii documentation as a starting point.
Module Setup
Plugins are automatically configured to locate web and console controllers. Modules, on the other hand, must explicitly define their root controllerNamespace
for both request types:
namespace acme;
use Craft;
class Module extends \yii\base\Module
{
public function init()
{
// Define a custom alias named after the namespace:
Craft::setAlias('@acme', __DIR__);
// Set the controllerNamespace based on whether this is a console or web request:
if (Craft::$app->getRequest()->getIsConsoleRequest()) {
$this->controllerNamespace = 'acme\\console\\controllers';
} else {
$this->controllerNamespace = 'acme\\controllers';
}
// Call init() *after* setting the `controllerNamespace` so Yii doesn’t try and set it:
parent::init();
// Additional custom initialization code goes here...
}
}
You’ll also need to make sure your module is getting bootstrapped on every request from config/app.php
(or config/app.console.php
):
return [
'bootstrap' => ['acme'],
'modules' => [
'acme' => acme\Module::class,
],
];
Adding a Controller
Any classes within the folder corresponding to your controllerNamespace
setting will be automatically discovered when the console application initializes. Every controller has a default action (run when an action is not specified), and supports options.
Create GreetController.php
in modules/console/controllers/
, with this content:
namespace modules\console\controllers;
use craft\console\Controller;
use craft\helpers\Console;
use yii\console\ExitCode;
/**
* Greet Controller
*/
class GreetController extends Controller
{
public $defaultAction = 'developer';
/**
* @var string|null The name used when referring to the runner.
*/
public ?string $who = null;
public function options($actionID): array
{
$options = parent::options($actionID);
// Always allow a --who flag:
$options[] = 'who';
switch ($actionID) {
case 'developer':
// Action-specific arguments:
// $options[] = '...';
break;
}
return $options;
}
/**
* Issues a greeting to new Craft developers.
*/
public function actionDeveloper(): int
{
$who = $this->who ?? 'world';
$this->stdout("Hello, {$who}!", Console::FG_GREEN);
return ExitCode::OK;
}
}
Running Actions
Supposing your module ID or plugin handle was acme
, you would access your controller like this:
# Run the "default action":
php craft acme/greet
# -> Hello, world!
# Run the developer-specific greeting:
php craft acme/greet/developer
# -> Hello, world!
# Pass a name:
php craft acme/greet/developer --who="Marvin"
# -> Hello, Marvin!
Options
In the example, we’ve declared a public class property, and set up a mapping for the single action ID. Any option can be set using bash’s familiar --kebab-case-option-name
syntax.
Use the optionAliases()
method to define shorthand options like -m
.
Arguments
Actions can declare arguments that will be processed from the command’s input. Arguments are separated by spaces, and the values are processed according to their declared types:
public function actionDeveloper(string $emotion, ?int $days = null): int
{
$who = $this->who ?? 'world';
if ($days >= 500) {
$this->stderr("Sorry, I don’t remember you, {$who}!", Console::FG_YELLOW);
return ExitCode::TEMPFAIL;
}
$this->stdout("Hello, {$who}! I am {$emotion} to see you!", Console::FG_GREEN);
return ExitCode::OK;
}
Read more about passing arguments to console commands.
Help Text
To assist CLI users, Yii automatically parses docblocks from your controller’s action methods (as well as any public properties matching options you’ve registered) and displays them when running php craft help
.
php craft help acme/greet
# -> List of actions
php craft help acme/greet/developer
# -> Action description, list of available --options
php craft acme/greet --help
# This works the same way as the main `help` command!
Registering Custom Console Commands
You can register custom console commands on Craft’s own controllers, or plugin-supplied controllers, so long as they extend craft5:craft\console\Controller. For example, plugins that supply custom element types can add their own actions to the resave controller.
To do that, use the craft5:craft\console\Controller::EVENT_DEFINE_ACTIONS event.
use craft\events\DefineConsoleActionsEvent;
use craft\console\Controller;
use craft\console\controllers\ResaveController;
use yii\base\Event;
Event::on(
ResaveController::class,
Controller::EVENT_DEFINE_ACTIONS,
function(DefineConsoleActionsEvent $event) {
$event->actions['products'] = [
'options' => ['type'],
'helpSummary' => 'Re-saves products.',
'action' => function($params): int {
/** @var ResaveController $controller */
$controller = Craft::$app->controller;
$query = Product::find();
if ($controller->type) {
$query->type(explode(',', $controller->type));
}
return $controller->saveElements($query);
}
];
}
);
Output Helpers
Internally, Craft keeps console feedback consistent with a suite of helper methods provided by craft5:craft\console\ControllerTrait.
- Success — Output a message with a ✅ icon:
$this->success('Done!');
- Failure — Output a message prefixed with an
X
:$this->failure('Something went wrong.');
- Tips — Output a message with a 💡 icon:
$this->tip('Try this, next!');
- Warning — Output a message with a ⚠️ icon:
$this->warning('Check your input and try again.');
- Generic “Note” — Output a message with a custom icon or prefix:
$this->note('Eat your vegetables!', '🥬 ');
The above methods run the $note
argument through craft5:craft\console\ControllerTrait::markdownToAnsi(), which provides some basic formatting for long messages. All methods write to stdout
—use $this->stderr()
if you need to target a particular output stream.
You can also format messages directly, using yii2:yii\console\Controller::stdout(). Additional craft5:craft\helpers\Console constants can be passed after the first argument (the message itself) to decorate the text output:
use craft\helpers\Console;
$this->stdout(
'This message will be bold and vibrant!',
Console::FG_RED,
Console::BG_YELLOW,
Console::BOLD,
// ...
);