2 Comments

Commandline Craft: Creating a Craft Console Plugin

I recently worked on automating a deployment step for a website built with Craft. Specifically, I wanted to clear some caches during a deploy. Previously this had been a manual step done through the admin interface, but it was easy to forget. Furthermore, invalidating the CloudFront cache without first invalidating the Craft cache meant that sometimes CloudFront would re-cache old pages and images.

During deploys, we already run several other commands on the server (for example: to update file permissions and create symlinks) so I set out to find a way to expose this cache-clearing functionality through the command line.

I found good documentation for creating Craft plugins, but the details of creating plugins specifically intended to be run from the command line were not clear. I’d like to share what I learned about how to do this. I won’t go into detail about the cache-clearing code, but I’ll demonstrate how to set up a console plugin and invoke it from the command line.

Yii Command Runner

Craft is built on the Yii framework and includes a command runner, yiic under craft/app/etc/console/:


$ /Applications/MAMP/bin/php/php5.6.7/bin/php ./craft/app/etc/console/yiic help
Yii command runner (based on Yii v1.1.16)
Usage: ./craft/app/etc/console/yiic  [parameters...]

The following commands are available:
 - base
 - migrate
 - querygen
 - shell

To see individual command help, use the following:
   ./craft/app/etc/console/yiic help 

These commands run in a context where the Craft code has already been bootstraped, so (in theory, at least) anything that can be done through the Craft admin panel can also be done from a custom yiic command here.

The benefit of exposing functionality through this command line interface is ease of automation. Other scripts can be written to call these commands for you—for example: during a deploy, or from a cron job that runs on regular basis.

After creating and installing our plugin, we’ll have a new custom command available:


$ /Applications/MAMP/bin/php/php5.6.7/bin/php ./craft/app/etc/console/yiic help
Yii command runner (based on Yii v1.1.16)
Usage: ./craft/app/etc/console/yiic  [parameters...]

The following commands are available:
 - base
 - helloworld
 - migrate
 - querygen
 - shell

To see individual command help, use the following:
   ./craft/app/etc/console/yiic help 

Creating a Basic Plugin

To create our simple Craft console plugin, we’ll first start with a basic plugin as described in the Craft docs. For the sake of programming tradition, we’ll call ours “Hello World” so let’s start with a directory helloworld/ containing a HelloWorldPlugin.php file:


<?php
namespace Craft;

class HelloWorldPlugin extends BasePlugin
{
    function getName()
    {
         return Craft::t('Hello World');
    }

    function getVersion()
    {
        return '0.0.1';
    }

    function getDeveloper()
    {
        return 'Atomic Object';
    }

    function getDeveloperUrl()
    {
        return 'https://atomicobject.com';
    }
}
?>

We’ll put this helloworld/ directory under craft/plugins/ when we install it.


craft/
│ ...
├── plugins/
│   │ ...
│   ├── helloworld/
│   │   └── HelloWorldPlugin.php
...

Creating a Craft Console Plugin

Now, for making something accessible from the command line, we’ll create a new BaseCommand. This will go in a file called HelloWorldCommand.php under a subdirectory called consolecommands.


craft/
│ ...
├── plugins/
│   │ ...
│   ├── helloworld/
│   │   ├── HelloWorldPlugin.php
│   │   ├── consolecommands/
│   │   │   └── HelloWorldCommand.php
...

In HelloWorldCommand.php we’ll put the following code:


<?php
namespace Craft;

class HelloWorldCommand extends BaseCommand
{
  public function actionHello()
  {
    echo "Hello World!\n";
  }
}
?>

If we check yiic again, we might expect to see our command, but…


$ /Applications/MAMP/bin/php/php5.6.7/bin/php ./craft/app/etc/console/yiic help
Yii command runner (based on Yii v1.1.16)
Usage: ./craft/app/etc/console/yiic  [parameters...]

The following commands are available:
 - base
 - migrate
 - querygen
 - shell

To see individual command help, use the following:
   ./craft/app/etc/console/yiic help 


It’s still not there. Before it will appear, we need to enable our plugin:

Enable_Plugin

Plugin_Enabled

Now when we check `yiic`, we see our command:


$ /Applications/MAMP/bin/php/php5.6.7/bin/php ./craft/app/etc/console/yiic help
Yii command runner (based on Yii v1.1.16)
Usage: ./craft/app/etc/console/yiic  [parameters...]

The following commands are available:
 - base
 - helloworld
 - migrate
 - querygen
 - shell

To see individual command help, use the following:
   ./craft/app/etc/console/yiic help 


Let’s check that help…


$ /Applications/MAMP/bin/php/php5.6.7/bin/php ./craft/app/etc/console/yiic help helloworld
Usage: ./craft/app/etc/console/yiic helloworld hello

So, it looks like the actionHello() function we created earlier is mapped to the subcommand hello.

Let’s run it:


$ /Applications/MAMP/bin/php/php5.6.7/bin/php ./craft/app/etc/console/yiic helloworld hello
Hello World!

Success!

Now we’re equipped to create more complex Craft console plugins that invoke things like craft()->templateCache->deleteAllCaches() in our PHP code and make these features available from the command line. We can use the Yii command runner to call these new commands from bash scripts, deployment scripts, and cron jobs. Automating Craft tasks just got a lot easier.

Credit

Credit to the following Stack Exchange posts for pointing me in the right direction: