1

Anyone written a simple plugin that does this out there? When a user submits a form on the frontend, it creates a new entry (with the default status set to disabled). I'd like to set it up so that the admins receive an email notification every time a new disabled entry is created for that section.

2

You can do this with a simple module. You can set one up at pluginfactory.io with no controllers and a service called Email. If you're unsure about how modules work or how to set one up, I can highly recommend reading Andrew Welch's guide to creating a module in Craft 3.

In this code, I've called the module 'MyModule' but you can give it any name you like.

Update the main module file's init method to look something like this:

public function init()
{
    parent::init();
    self::$instance = $this;

    // This line calls a private method to register a new email message in Craft
    $this->_registerEmailMessages();
}

At the bottom of your main module file, add the _registerEmailMessages() function:

private function _registerEmailMessages()
{
    Event::on(
        SystemMessages::class,
        SystemMessages::EVENT_REGISTER_MESSAGES,
        function(RegisterEmailMessagesEvent $event) {
            $event->messages = array_merge($event->messages, [
                [
                    'key' => 'my-module_publish-notification',
                    'heading' => Craft::t('my-module', 'my-module_publish-notification_heading'),
                    'subject' => Craft::t('my-module', 'my-module_publish-notification_subject'),
                    'body' => Craft::t('my-module', 'my-module_publish-notification_body'),
                ]
            ]);
        }
    );
}

Note: you'll need to add the correct 'use' statements at the top of your module file, if you're not using an IDE like PhpStorm which adds them automatically:

use craft\events\RegisterEmailMessagesEvent;
use craft\services\SystemMessages;

What this function does is to add a new system email message with the key 'my-module_publish-notification', with translation strings for the heading, subject and body. This email will be accessible and editable in the CP by going to Utilities > System Messages.

Now you need to add some text to those translation strings. Your Pluginfactory module should come with everything set up for this. Look in the src/translations/en folder and you should find a file named after your module, e.g. 'my-module.php'

In this file, you can add the text that you want to be shown in this email by default:

'my-module_publish-notification_heading' => 'When an entry is created:',
'my-module_publish-notification_subject' => 'An entry has been created',
'my-module_publish-notification_body' => "A new entry has been created by {{ username }}.",

The heading is what's shown in the System Messages screen above the email, and the subject and body are exactly what you'd expect: the subject of the email, and the body text of the email.

The next step is to listen to the EVENT_AFTER_SAVE event to trigger the email itself. Add another line to your module's init method:

$this->installEventListeners();

Then add the installEventListeners() method at the bottom of the module file:

protected function installEventListeners()
{
    Event::on(
        Entry::class,
        Element::EVENT_AFTER_SAVE,
        function(ModelEvent $event) {
            /** @var Entry $entry */
            $entry = $event->sender;

            if (ElementHelper::isDraftOrRevision($entry)) {
                return;
            }

            if ($entry->isNew) {
                $this::$instance->emailService->sendEntryNotification($entry);
            }
        }
    );
}

This method adds a listener which will be called after an entry is saved, and if the entry is a new entry (i.e. it's not an existing entry being edited) then it calls the Email service's sendEntryNotification method.

In your Email service, that method would look something like this:

public function sendEntryNotification(Entry $entry)
{
    $admins = User::find()
        ->admin(true)
        ->all();

    foreach($admins as $admin) {
        $mail = Craft::$app->getMailer()
            ->composeFromKey('my-module_publish-notification', [
                'username' => $entry->author->username
            ]);

        $mail
            ->setTo($admin)
            ->send();
    }
}

This method fetches all admins, then loops through each one and sends the notification email as defined by the key that's passed into composeFromKey - the key should match the string that we set as the key in our _registerEmailMessages function.

You can pass any sort of data through to your email. I've shown how to pass the username of the entry's author, but you can pass any data through in an array as the second argument in composeFromKey. The key of each data can be used in your email's content to show the value. In this example, the translation string for 'my-module_publish-notification_body' shows the username like this:

"A new entry has been created by {{ username }}."

You could pass in the name of the user, the creation date and any other data from the entry.

The last step is to register your module with your Craft app. The Pluginfactory download comes with a config directory with an app.php file inside. Copy the code that starts with 'my-module' - it should look something like this:

'my-module' => [
    'class' => \modules\mymodule\MyModule::class,
    'components' => [
        'email' => [
            'class' => 'modules\mymodule\services\Email',
        ],
    ],
],
'bootstrap' => ['my-module'],

Open up your Craft app.php file, which lives in the root config directory, and add the code from above. This should end up looking something like this:

return [
    '*' => [
        'modules' => [
            'my-module' => [
                'class' => \modules\mymodule\MyModule::class,
                'components' => [
                    'email' => [
                        'class' => 'modules\mymodule\services\Email',
                    ],
                ],
            ],
        ],
        'bootstrap' => ['my-module'],
    ],
];

The final step is to make Composer happy. Add your module to your composer.json's autoload object:

"autoload": {
    "psr-4": {
        "modules\\mymodule\\": "modules/mymodule/src/"
    }
}

Then run composer dump-autoload to rebuild the Com­pos­er autoload map.

That should get you almost all of the way there! You may need to update your event listener to make sure it's only calling the email method for the correct section(s) within your site.

  • Great answer, Martin! – Brad Bell Nov 9 '20 at 5:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.