Events
CM Gift Card 4.0.0 and later fires events at important moments. You can write your own Joomla plugin, listen to these events, and change what CM Gift Card does. You never edit a CM Gift Card file, so your work is safe when you update the extension.
Here are some of the things you can do with events:
- Add your own tags to emails, for example
{shop_name}. - Send an email to a different address, or stop it.
- Generate gift card codes in your own format.
- Send order details to another system, such as your accounting software.
- Reject a gift card at the counter, for example when it is too old.
- Show extra information on the gift card page.
A before event runs before CM Gift Card does something. You can change the data, and with some of these events you can also stop the action.
An after event runs after CM Gift Card has done something. You cannot change anything, so use these events to tell another system what happened.
A plugin needs three files. Put them in a folder called myplugin, make a ZIP file of the folder, then install the ZIP in Joomla.
Your plugin must be in the cmgiftcard plugin group. After installing it, go to System → Plugins, find your plugin, and enable it.
<?xml version="1.0" encoding="utf-8"?>
<extension version="5.4" type="plugin" group="cmgiftcard" method="upgrade">
<name>My Gift Card Plugin</name>
<version>1.0.0</version>
<author>Your Name</author>
<namespace path="src">MyCompany\Plugin\CMGiftCard\MyPlugin</namespace>
<files>
<folder plugin="myplugin">services</folder>
<folder>src</folder>
</files>
</extension>
<?php
defined('_JEXEC') or die;
use Joomla\CMS\Extension\PluginInterface;
use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use Joomla\Event\DispatcherInterface;
use MyCompany\Plugin\CMGiftCard\MyPlugin\Extension\MyPlugin;
return new class () implements ServiceProviderInterface {
public function register(Container $container)
{
$container->set(
PluginInterface::class,
function (Container $container) {
$plugin = new MyPlugin(
$container->get(DispatcherInterface::class),
(array) PluginHelper::getPlugin('cmgiftcard', 'myplugin')
);
$plugin->setApplication(Factory::getApplication());
return $plugin;
}
);
}
};
<?php
namespace MyCompany\Plugin\CMGiftCard\MyPlugin\Extension;
defined('_JEXEC') or die;
use CMExtension\Component\CMGiftCard\Administrator\Event\PrepareMailTagsEvent;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\Event\SubscriberInterface;
final class MyPlugin extends CMSPlugin implements SubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [
'onCMGCPrepareMailTags' => 'addMyTags',
];
}
public function addMyTags(PrepareMailTagsEvent $event): void
{
$event->addTag('{shop_name}', 'My Wonderful Shop');
}
}
You can now write {shop_name} in any email template, and your plugin puts the shop name in its place.
To use more events, add more lines to getSubscribedEvents(), with one method for each event.
Every event has a context. The context tells you where the event comes from, for example com_cmgiftcard.order.
Email events use the name of the email in the context, for example com_cmgiftcard.order_success. Use the context when you only want to change one email or one page:
if ($event->getContext() !== 'com_cmgiftcard.order_success') {
return;
}
Some before events let you stop the action: call cancel() and give a reason, and CM Gift Card shows that reason to the user.
$event->cancel('Sorry, we cannot accept this order.');
Put your text in a language file so that it works in every language:
$event->cancel(Text::_('PLG_CMGIFTCARD_MYPLUGIN_ORDER_REFUSED'));
Every event below is available since CM Gift Card 4.0.0.
| Event | When it runs | What you can do |
|---|---|---|
onCMGCPrepareMailTags | Before the tags in an email are replaced | Add or change tags |
onCMGCBeforeSendMail | Before an email is sent | Change the email, or stop it |
onCMGCAfterSendMail | After an email has been sent | Read only |
onCMGCGenerateCardCode | When a gift card needs its code | Give your own code |
onCMGCBeforeCreateOrder | Before a new order is saved | Change the order, or stop it |
onCMGCAfterCreateOrder | After a new order has been saved | Read only |
onCMGCBeforeCreateCard | Before a gift card is saved | Change the gift card, or stop it |
onCMGCAfterCreateCard | After a gift card has been saved | Read only |
onCMGCAfterOrderPaid | After an order has been paid and the codes exist | Read only |
onCMGCBeforeRedeemCard | Before a staff member redeems a gift card | Stop the redemption |
onCMGCAfterRedeemCard | After a gift card has been redeemed | Read only |
onCMGCBeforeAddToCart | Before a gift card is added to the cart | Change it, or stop it |
onCMGCAfterAddToCart | After a gift card has been added to the cart | Read only |
onCMGCValidateCardAmount | When the amount is checked | Refuse the amount |
onCMGCPrepareCardPdf | Before the PDF gift card is generated | Change the HTML |
onCMGCPrepareInvoicePdf | Before the PDF invoice is generated | Change the HTML |
onCMGCBeforeDisplayCard | Before gift card details are shown | Add HTML above |
onCMGCAfterDisplayCard | After gift card details are shown | Add HTML below |
All event classes are in the namespace CMExtension\Component\CMGiftCard\Administrator\Event.
Every event also has the method getContext().
Runs just before CM Gift Card replaces the {tags} in an email.
Methods: getTags(), setTags(array $tags), addTag($tag, $value), getOrder(), getCard().
Since: 4.0.0
Contexts: com_cmgiftcard.order_success, com_cmgiftcard.gift_card_recipient, com_cmgiftcard.gift_card_sender, com_cmgiftcard.physical_admin, com_cmgiftcard.offline_client, com_cmgiftcard.offline_admin.
getOrder() and getCard() give you the order and the gift card. Either one can be empty, because not every email is about both, so always check them before you use them.
This example adds the phone number of the customer, but only to the order email:
public function addMyTags(PrepareMailTagsEvent $event): void
{
if ($event->getContext() !== 'com_cmgiftcard.order_success') {
return;
}
$order = $event->getOrder();
$event->addTag('{customer_phone}', $order ? $this->loadPhoneNumber($order->user_id) : '');
}
Runs before CM Gift Card sends an email. You can change the email or stop it.
Methods: getRecipient(), setRecipient($email), getSubject(), setSubject($subject), getBody(), setBody($html), getAttachmentPath(), setAttachmentPath($path), getAttachmentName(), setAttachmentName($name), cancel($reason).
Since: 4.0.0
This example sends every email to a single test address, which is useful while you are building the site:
public function redirectMail(BeforeSendMailEvent $event): void
{
$event->setRecipient('test@example.com');
$event->setSubject('[TEST] ' . $event->getSubject());
}
CM Gift Card can send a copy of an email to your administrators. The context of a copy ends with _copy, for example com_cmgiftcard.order_success_copy. This example stops all copies:
public function stopAdminCopies(BeforeSendMailEvent $event): void
{
if (str_ends_with($event->getContext(), '_copy')) {
$event->cancel();
}
}
Runs after CM Gift Card has sent the email, or after sending has failed.
Methods: getRecipient(), getSubject(), getBody(), isSent().
Since: 4.0.0
public function logMail(AfterSendMailEvent $event): void
{
if (!$event->isSent()) {
Log::add('Email to ' . $event->getRecipient() . ' failed', Log::WARNING, 'my-plugin');
}
}
Runs when a gift card needs its code, which happens when the order is paid.
Methods: getCardId(), getCode(), setCode($code).
Since: 4.0.0
If you do nothing, CM Gift Card generates the code itself. If you call setCode(), CM Gift Card uses your code instead.
CM Gift Card rejects your code if it is empty or if another gift card already has it, and generates its own code instead. A paid gift card always gets a code.
public function makeMyCode(GenerateCardCodeEvent $event): void
{
$event->setCode('SHOP-' . strtoupper(bin2hex(random_bytes(4))));
}
Runs before CM Gift Card saves a new order. The order is not paid yet.
Methods: getData(), setData(array $data), cancel($reason).
Since: 4.0.0
public function checkOrder(BeforeCreateOrderEvent $event): void
{
$data = $event->getData();
if (str_ends_with($data['email'], '@blocked-domain.test')) {
$event->cancel(Text::_('PLG_CMGIFTCARD_MYPLUGIN_EMAIL_NOT_ALLOWED'));
return;
}
$data['city'] = ucwords($data['city']);
$event->setData($data);
}
Runs after CM Gift Card has saved the new order.
Methods: getOrderId(), getOrderNumber(), getData().
Since: 4.0.0
Important
This event runs inside a database transaction, so only work with the database here. If you call another website, the transaction stays open and your shop becomes slow. To communicate with another system, use
onCMGCAfterOrderPaidinstead.
Runs after the order has been paid and after every gift card in the order has its code. This is the best event to use for communicating with another system.
Methods: getOrderId(), getTransactionId().
Since: 4.0.0
public function sendToAccounting(AfterOrderPaidEvent $event): void
{
$order = CMGiftCardHelper::getOrder($event->getOrderId());
$this->postToMyApi([
'order_number' => $order->order_number,
'amount' => $order->amount,
'transaction_id' => $event->getTransactionId(),
]);
}
Runs before CM Gift Card saves a gift card. The gift card has no code yet.
Methods: getData(), setData(array $data), getOrderId(), cancel($reason).
Since: 4.0.0
Runs after CM Gift Card has saved a gift card. Like onCMGCAfterCreateOrder, this event runs inside a database transaction.
Methods: getCardId(), getOrderId(), getData().
Since: 4.0.0
Runs before a staff member marks a gift card as redeemed. It also runs before they undo a redemption. Use cancel() to stop the action.
Methods: getCard(), isRedeeming(), cancel($reason).
Since: 4.0.0
isRedeeming() is true when the staff member is redeeming the card, and false when they are undoing a redemption.
This example rejects a gift card more than one year after it was delivered:
public function checkAge(BeforeRedeemCardEvent $event): void
{
if (!$event->isRedeeming()) {
return;
}
$card = $event->getCard();
if (!$card->delivered) {
return;
}
if (Factory::getDate($card->delivered) < Factory::getDate('-1 year')) {
$event->cancel(Text::_('PLG_CMGIFTCARD_MYPLUGIN_CARD_TOO_OLD'));
}
}
Runs after a staff member has redeemed a gift card, or after they have undone a redemption.
Methods: getCard(), isRedeeming().
Since: 4.0.0
Runs before a gift card is added to the shopping cart.
Methods: getData(), setData(array $data), cancel($reason).
Since: 4.0.0
Runs after a gift card has been added to the shopping cart.
Methods: getData(), getCart().
Since: 4.0.0
Runs when CM Gift Card validates the amount the customer entered. It runs only when the amount is already between the smallest and the largest amount set in the component options.
Methods: getAmount(), getCardType(), cancel($reason).
Since: 4.0.0
getCardType() is physical or electronic.
This example allows only amounts that are divisible by 5:
public function checkAmount(ValidateCardAmountEvent $event): void
{
if (fmod($event->getAmount(), 5) !== 0.0) {
$event->cancel();
}
}
Runs before CM Gift Card generates a PDF gift card. The tags have already been replaced. This event runs both for the PDF that is emailed to the recipient and for a PDF that an administrator downloads in the back end.
Methods: getHtml(), setHtml($html), getCard().
Since: 4.0.0
public function addTermsToPdf(PrepareCardPdfEvent $event): void
{
$event->setHtml($event->getHtml() . '<p>Valid for one year.</p>');
}
Runs before CM Gift Card generates the PDF invoice for the order email.
Methods: getHtml(), setHtml($html), getOrder().
Since: 4.0.0
Run when CM Gift Card shows the details of a gift card. This happens in two places:
- In the Staff Area, after a staff member scans or types a code.
- On the gift card page a customer opens from their order.
Use addHtml() to put your own HTML above or below the details.
Methods: getCard(), getHtml(), addHtml($html).
Since: 4.0.0
public function showNote(AfterDisplayCardEvent $event): void
{
$event->addHtml('<p>Thank you for using our gift cards!</p>');
}
Important
CM Gift Card outputs your HTML as it is. If you display text that a customer entered, always escape it first with
htmlspecialchars().
- Keep your plugin fast. Every event runs while somebody is waiting for a page.
- Only stop an email or an order when you have a good reason. The customer sees the result.
- Use
getContext()to make sure your code runs only where you want it. - Test your plugin with a real order on a test site before you use it on a live site.