Introduction
This article describes how developers can configure and send custom email notifications. Custom email notifications may be useful if you want to send messages upon certain events.
For the sake of example, we will create a page in X-Cart's admin area, where you can send a message to given email address.
Preparation: creating module, page and form
We start off with creating a new module with the developer ID XCExample and the module ID EmailDemo.
Then, we create a page admin.php?target=example_email_demo
in admin area. For that we create:
Controller class
\XLite\Module\XCExample\EmailDemo\Controller\Admin\ExampleEmailDemo
with the following content:<?php
namespace XLite\Module\XCExample\EmailDemo\Controller\Admin;
/**
* ExampleEmailDemo
*/
class ExampleEmailDemo extends \XLite\Controller\Admin\AAdmin
{
}Page viewer class
\XLite\Module\XCExample\EmailDemo\View\Page\Admin\ExampleEmailDemo
with the following content:<?php
namespace XLite\Module\XCExample\EmailDemo\View\Page\Admin;
/**
* ExampleEmailDemoPage
*
* @ListChild (list="admin.center", zone="admin")
*/
class ExampleEmailDemo extends \XLite\View\AView
{
/**
* Return list of allowed targets
*/
public static function getAllowedTargets()
{
return array_merge(parent::getAllowedTargets(), array('example_email_demo'));
}
/**
* Return widget default template
*/
public function getDefaultTemplate()
{
return 'modules/XCExample/EmailDemo/page/example_email_demo/body.twig';
}
}Empty page template
skins/admin/modules/XCExample/EmailDemo/page/example_email_demo/body.twig
.
Then, we display from that contains two fields: 'Email to' and 'Body' on this page.
We create form widget's class
\XLite\Module\XCExample\EmailDemo\View\Model\EmailDemo
with the following content:<?php
namespace XLite\Module\XCExample\EmailDemo\View\Model;
class EmailDemo extends \XLite\View\Model\AModel
{
protected $schemaDefault = [
'to' => [
self::SCHEMA_CLASS => 'XLite\View\FormField\Input\Text\Email',
self::SCHEMA_LABEL => 'Email to',
self::SCHEMA_REQUIRED => true,
],
'body' => [
self::SCHEMA_CLASS => 'XLite\View\FormField\Input\Text',
self::SCHEMA_LABEL => 'Body',
self::SCHEMA_REQUIRED => false,
],
];
protected function getDefaultModelObject()
{
return null;
}
protected function getFormClass()
{
return 'XLite\Module\XCExample\EmailDemo\View\Form\EmailDemo';
}
}We create
\XLite\Module\XCExample\EmailDemo\View\Form\EmailDemo
form class used bygetFormClass()
method:<?php
namespace XLite\Module\XCExample\EmailDemo\View\Form;
class EmailDemo extends \XLite\View\Form\AForm
{
protected function getDefaultTarget()
{
return 'example_email_demo';
}
protected function getDefaultAction()
{
return 'send';
}
}We update the
skins/admin/modules/XCExample/EmailDemo/page/example_email_demo/body.twig
template and define its content as follows:<h2>Email sending script</h2>
{{ widget('\\XLite\\Module\\XCExample\\EmailDemo\\View\\Model\\EmailDemo') }}
At this point, we have a module and the form on the admin.php?target=example_email_demo
page:
The form can be submitted, but it will not produce any result.
Sending email
All X-Cart notifications are sent via \XLite\Core\Mailer
class. The main method for sending notifications is \XLite\Core\Mailer::compose()
. Here is the list of parameters it accepts:
- string $type - defines the type of notification and it can be used to pre-process the
$to
,$from
,$dir
and$customHeaders
parameters. You can create a set of methods with names likeprepare<param><type>()
, e.g. , if$type
is 'DemoMail', they can beprepareCustomHeadersDemoMail($customHeaders)
orprepareToDemoMail($to)
methods and those methods will be called automatically during message composing. - string $from - email's From field.
- string $to - email's To field.
- string $dir - directory where mail templates are located. The parent folders for this directory is
<X-Cart>/skins/mail/admin
,<X-Cart>/skins/mail/customer
or<X-Cart>/skins/mail/common
depending on whether you send an email to admin or customer. Such directory must containsubject.twig
template that defines email's subject andbody.twig
one that defines email's text. - (optional) array $customHeaders - an array of key-value pairs with additional headers (Cc, Bcc, Reply-To, etc).
- (optional) boolean $doSend - flag to cancel sending; can be used to debug the mailer.
- (optional) string $interface (default: customer) - template interface, either
\XLite::ADMIN_INTERFACE
or\XLite::CUSTOMER_INTERFACE
. Depending on this parameter, X-Cart will look templates either in<X-Cart>/skins/mail/admin/$dir
or in<X-Cart>/skins/mail/customer/$dir
directory. If it cannot find templates there, it will look for them in<X-Cart>/skins/mail/common/$dir
one. - (optional) string $languageCode - language code of the message.
- (optional) bolean $force flag. If the notification is not enabled in admin area, it will still be sent if this parameter is
true
.
We are going to create our own method that will call this compose()
method, but with our parameters, so we have to decorate \XLite\Core\Mailer
class. We create classes/XLite/Module/XCExample/EmailDemo/Core/Mailer.php
file with the following content:
<?php
namespace XLite\Module\XCExample\EmailDemo\Core;
/**
* Mailer core class
*/
abstract class Mailer extends \XLite\Core\Mailer implements \XLite\Base\IDecorator
{
public static function sendEmailDemoMessage($to, $body = '')
{
static::register([
'subject' => 'Demo notification',
'body' => $body,
]);
static::compose(
'DemoMail',
static::getSiteAdministratorMail(),
$to,
'modules/XCExample/EmailDemo/message',
array(),
true,
\XLite::CUSTOMER_INTERFACE
);
return static::getMailer()->getLastError();
}
}
This sendEmailDemoMessage()
method is the one we will be using. Make sure you define this method as static
and it has unique name as all modules add methods for sending notifications to \XLite\Core\Mailer
class. The method accepts two parameters: recepient's address and text for notifcation.
When we call this static::register()
method inside, it registers variables that will be available in email notification templates:
- 'subject' variable will always have value of 'Demo notification' and it can be accessed as
this.subject
in templates; - 'body' variable will have value of
$body
variable passed to the method. Similarly, it can be accessed asthis.body
in templates.
After that we just call already known compose()
method:
static::compose(
'DemoMail',
static::getSiteAdministratorMail(),
$to,
'modules/XCExample/EmailDemo/message',
array(),
true,
\XLite::CUSTOMER_INTERFACE
);
$type = 'DemoMail'
, we just have to specify some sort of type for this notification.$from = static::getSiteAdministratorMail()
, so all such notifications will be sent from site's admin email. You can also use pre-defined methods such asstatic::getSupportDepartmentMail()
,static::getUsersDepartmentMail()
orstatic::getOrdersDepartmentMail()
which reflect emails specified in 'Store setup > Contact information > Contacts' section in admin area.$to
parameter is defined as$to
variable passed into this method.$dir = 'modules/XCExample/EmailDemo/message'
, which means that X-Cart will look for templates for this notification inskins/mail/customer/modules/XCExample/EmailDemo/message
directory (since 7th parameter is defined as \XLite::CUSTOMER_INTERFACE) or inskins/mail/common/modules/XCExample/EmailDemo/message
one. We will have to create those templates as a next step.$customHeaders = array()
, which means that we do not define any custom headers.$doSend = true
, which means that this message will indeed be sent.interface = \XLite::CUSTOMER_INTERFACE
, which means that this is a notification to customers, so we look for templates inskins/mail/customer/modules/XCExample/EmailDemo/message
directory as well as define customer options for this notificaiton in admin area. More about it later in the article.
After we send a message, we return mailer's last error static::getMailer()->getLastError()
. If everything is OK, it will return null
.
Next step is to create templates that will be used by email sending process. We will put our templates into <X-Cart>/skins/mail/common
folder, because they will work for both admin and customer interfaces. So, we create skins/mail/common/modules/XCExample/EmailDemo/message
directory and put two templates into it:
subject.twig
{{ this.subject }}
body.twig
<p>
Text: {{ this.body }}
</p>
As you can see, we use {{ this.subject }}
and {{ this.body }}
variables defined earlier.
We already have properly working email sending method and now we need to call it. It will be called from inside controller that handles submitted form we created earlier. Let us create such controller's method.
For that we edit our \XLite\Module\XCExample\EmailDemo\Controller\Admin\ExampleEmailDemo
class and add the following method there:
protected function doActionSend()
{
$request = \XLite\Core\Request::getInstance();
$error = \XLite\Core\Mailer::sendEmailDemoMessage(
$request->to,
$request->body
);
if (!is_null($error)) {
\XLite\Core\TopMessage::getInstance()->addError('Error of test e-mail sending: ' . $error);
} else {
\XLite\Core\TopMessage::getInstance()->add('Test e-mail has been successfully sent');
}
$this->setReturnURL(
$this->buildURL('example_email_demo', '', array())
);
}
This doActionSend()
method will be called when you submit a request with 'action=send' parameter, which will happen when we submit a form. In this case, we pull 'to' and 'body' parameters from the request and then call the \XLite\Core\Mailer::sendEmailDemoMessage()
method with them:
$request = \XLite\Core\Request::getInstance();
$error = \XLite\Core\Mailer::sendEmailDemoMessage(
$request->to,
$request->body
);
If there is an error while sending email notification, we will display it, otherwise we will display 'Test e-mail has been successfully sent' message:
if (!is_null($error)) {
\XLite\Core\TopMessage::getInstance()->addError('Error of test e-mail sending: ' . $error);
} else {
\XLite\Core\TopMessage::getInstance()->add('Test e-mail has been successfully sent');
}
After that we redirect a user to the same page:
$this->setReturnURL(
$this->buildURL('example_email_demo', '', array())
);
After we have done all that, we can go to our admin.php?target=example_email_demo
page and send an email from there. Just specify recepient's email and text for the message. However, usually all email notifications are registered in the system, so that you can edit their subject and main part from admin's interface, rather than editing the template.
Let us register our message in X-Cart, so we could do that as well.
Registering the notification
The admin area of an X-Cart store allows you to manage email notifcations. You can configure them in the 'Store setup > Email notifications > Settings' section in admin area. This page contains a list of different notification types and provides switches allowing the admin to enable/disable specific notification types for administrators or customers. For a custom notification to appear in the aforementioned list, it should be registered by special code in module's install.yaml
file. Here is the content of our classes/XLite/Module/XCExample/EmailDemo/install.yaml
file:
XLite\Model\Notification:
- templatesDirectory: modules/XCExample/EmailDemo/message
availableForAdmin: false
availableForCustomer: true
enabledForAdmin: false
enabledForCustomer: true
translations:
- code: en
name: Demo notification (Email Demo module)
description: This notification is sent from testing page admin.php?target=example_email_demo
customerSubject: Demo notification
customerText: Body of demo notification
Let us walk through what we are doing in this file:
XLite\Model\Notification:
says that we are registering an email notification;-
says that now will go details of this email notification;templatesDirectory: modules/XCExample/EmailDemo/message
says that below details will be applied to the notification defined bymodules/XCExample/EmailDemo/message
folder (our notification);availableForAdmin
andavailableForCustomer
options define whether such notification can be sent to admin or customer users. In our case, we can send it to customers, but we cannot send it to admins. One notification can also be sent to admins and customers at the same. This option defines the following selectors in 'Store setup > Email notifications > Settings' section:enabledForAdmin
andenabledForCustomer
options define whether this notification is enabled for customers and admins. It is enabled for customers and disabled for admins;translations:
section defines that below will be defined multi-language components of the notification;- code: en
line defines that below will be multi-language values for English language;name: Demo notification (Email Demo module)
defines the name of the notification when displayed in the notification list:description: This notification is sent ...
defines the description of the notifcation when displayed in the notification list (see screenshot above);customerSubject
andcustomerText
define subject and main text of the message repsectively. These values will appear on the notification details page like this:- If your notification is supposed to be sent to admins, you have to have
adminSubject
andadminText
settings as well. They are the same ascustomerSubject
andcustomerText
, but for admin notifications. If you have both customer and admins subjects and texts, you will have the following tab on the notification details page:
That is it. Once we define such YAML file, we should load it to the system and after that you will see our notification in the 'Store setup > Email notifications > Settings' section.
Now we only need to change our skins/mail/common/modules/XCExample/EmailDemo/message/subject.twig
template, so it would pick up subject defined in admin area. For that we define the template's content as follows:
{{ this.getNotificationSubject() }}
We do not need to do anything with email's body, because the text we defined in admin area will be inserted into the email automatically. Also, we no longer need to register 'subject' variable in sendEmailDemoMessage()
method, because it is not used anywhere.
Module pack
You can download this module's pack from here: XCExample-EmailDemo-v5_3_0.tar