Skip to content

Email

Email Templates After Patch 2.3.4

This patch brought in some changes to the way Magento 2 handles email templates. There are now two modes for templates, legacy and not legacy. In version 2.3.4 until 2.4.0 any custom templates that clients create will be broken because of this change.

Legacy Templates

These are traditional email templates and include any templates created before the site was patched to 2.3.4 or up and any Magento templates.

They can continue to use the standard variables that Magento offers in email templates.

Non Legacy

These are templates not set to legacy and can only contain variables which are scalar types or arrays.

What Does This Mean?!?

Basically any new template will be unable to access object variables, think $order in order emails.

The functionality for this can be seen here: StrictResolver.php

What Do I Do Then?

You will need to pass variables as strict scalar types or as arrays. Instead of passing the Magento order object you will pass an array of items from that order.

In order to visualize this take a look at this code:

$order = $this->getData('order');

        if ($order !== null) {
            return $order;
        }
This is, technically, how magento loads the order for email templates. The problem comes from the getData call, it is calling for the object order - however we can no longer pass objects so this has to be changed to:
$orderId = (int)$this->getData('order_id');
        if ($orderId) {
            $order = $this->orderRepository->get($orderId);
            $this->setData('order', $order);
        }
So now we are loading the order from the repo based on an id that is sent from the template.

How do I make these changes

The best way is to overwrite the way that objects such as order are being passed to templates, which is what magento are doing in patch 2.4.0.

So the options are to either update the site to patch 2.4.0 or to create a custom module that adds the updated changes from 2.4.0 to the required classes.

Can I just overwrite template saving to always be Legacy?

Yes!! It's a bit trashy, but it works fine:

<?php

declare(strict_types=1);

namespace EdmondsCommerce\EmailTemplateLegacy\Plugin;

class EmailTemplate 
{

    public function beforeBeforeSave(\Magento\Email\Model\Template $subject)
    {
        $subject->setData('is_legacy', 1);
        return [];
    }
}
di.xml:
<?xml version="1.0" ?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Email\Model\Template">
        <plugin disabled="false" name="EdmondsCommerce_EmailTemplateLegacy_Plugin_Magento_Email_Model_Template" sortOrder="10" type="EdmondsCommerce\EmailTemplateLegacy\Plugin\EmailTemplate"/>
    </type>
</config>
<?php

declare(strict_types=1);

use Magento\Framework\Setup\Patch\DataPatchInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;

class LegacyColumnChange implements DataPatchInterface
{

    protected $setup;

    /**
     * LegacyColumnChange constructor.
     * @param \ModuleDataSetupInterface $setup
     */
    public function __construct(
        ModuleDataSetupInterface $setup
    ) {
        $this->setup = $setup;
    }

    /**
     * @inheritDoc
     */
    public static function getDependencies()
    {
        return [];
    }

    /**
     * @inheritDoc
     */
    public function getAliases()
    {
        return [];
    }

    /**
     * @inheritDoc
     */
    public function apply()
    {   
        try {
            $connection = $this->setup->getConnection();
            $emailTemplateTable = $connection->getTableName('email_template');
            $connection->query("UPDATE `$emailTemplateTable` SET `is_legacy` = '1';");

        } catch (\Exception $e) {
            // ignore
        }
    }
}

This plugin will get called on every template save and make the template legacy. The patch is just for existing templates.