Using Events in a Custom Module

You can customize Craft’s behavior by listening for any of the events it triggers and introducing your own logic.

Subscribing to events requires a minimal amount of PHP in a custom plugin or module. The fastest way to start using events in your project is to use the empty module included with Craft by default at modules/Module.php.

Bootstrap the Module #

Before we add any code, we’ll want to bootstrap the module so it’s loaded with every request and ready before Craft triggers events.

To bootstrap the module, uncomment the 'bootstrap' line in craft/config/app.php...

// ...

return [
    'id' => App::env('APP_ID') ?: 'CraftCMS',
    'modules' => [
        'my-module' => \modules\Module::class,
    ],
    //'bootstrap' => ['my-module'],
];

...so it looks like this...

// ...

return [
    'id' => App::env('APP_ID') ?: 'CraftCMS',
    'modules' => [
        'my-module' => \modules\Module::class,
    ],
    'bootstrap' => ['my-module'],
];

Add Event Code #

Now that we’ve bootstrapped a custom module, we can add code to its init() method subscribe to an event and run our custom logic.

Let’s use the defineRules event to require all entry titles to be at least ten characters.

Here’s the new code we’ll be adding:

use craft\elements\Entry;
use craft\base\Model;
use craft\events\DefineRulesEvent;

Event::on(
    Entry::class,
    Model::EVENT_DEFINE_RULES,
    function(DefineRulesEvent $event) {
        // existing validation rules
        $rules = $event->rules;

        // add our rule to the array
        $rules[] = ['title', 'length' => [10]];

        // replace the original rules with our updated array
        $event->rules = $rules;
    }
);

This declares a listener for a common EVENT_DEFINE_RULES event that’s triggered when a model is initializing its validation rules. Here we’re listening specifically for the event coming from Entry class instances.

$event is a DefineRulesEvent object that’s passed along when the event is triggered, and our code modifies the included rules array to append our custom 10-character minimum to the title field.

The rules array is a core part of Yii’s validation system. Check out Validating Input or jump straight to the Core Validators reference for more about how these work.

Once added, the entire contents of modules/Module.php will look like this:

<?php
namespace modules;

use craft\elements\Entry;
use craft\base\Model;
use craft\events\DefineRulesEvent;
use Craft;

/**
 * Custom module class.
 *
 * This class will be available throughout the system via:
 * `Craft::$app->getModule('my-module')`.
 *
 * You can change its module ID ("my-module") to something else from
 * config/app.php.
 *
 * If you want the module to get loaded on every request, uncomment this line
 * in config/app.php:
 *
 *     'bootstrap' => ['my-module']
 *
 * Learn more about Yii module development in Yii's documentation:
 * http://www.yiiframework.com/doc-2.0/guide-structure-modules.html
 */
class Module extends \yii\base\Module
{
    /**
     * Initializes the module.
     */
    public function init()
    {
        // Set a @modules alias pointed to the modules/ directory
        Craft::setAlias('@modules', __DIR__);

        // Set the controllerNamespace based on whether this is a console or web request
        if (Craft::$app->getRequest()->getIsConsoleRequest()) {
            $this->controllerNamespace = 'modules\\console\\controllers';
        } else {
            $this->controllerNamespace = 'modules\\controllers';
        }

        parent::init();

        Event::on(
            Entry::class,
            Model::EVENT_DEFINE_RULES,
            function(DefineRulesEvent $event) {
                // existing validation rules
                $rules = $event->rules;

                // add our rule to the array
                $rules[] = ['title', 'length' => [10]];

                // replace the original rules with our updated array
                $event->rules = $rules;
            }
        );
    }
}

Craft will now prompt the editor to fix the title if an entry is saved with fewer than ten characters.

You can take advantage of any events Craft or third-party plugins make available, just be sure to check the documentation for whatever details are provided and what you’re able to do with them.