1

Previously, we used the following module to load the email variable with a custom CreatedAt value. Because this is deprecated, it will not work anymore (https://devdocs.magento.com/guides/v2.4/frontend-dev-guide/templates/template-email-migration.html).

How can we modify the following, to keep using this custom CreatedAt from Magento 2.4.3-p2?

app/code/Mago/Delivery/registration.php

<?php
\Magento\Framework\Component\ComponentRegistrar::register(
\Magento\Framework\Component\ComponentRegistrar::MODULE,
'Mago_Delivery',
__DIR__
);

app/code/Mago/Delivery/etc/module.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Mago_Delivery" setup_version="1.0.1">
   </module>
</config>

app/code/Mago/Delivery/etc/di.xml

<?xml version="1.0"?>
<config>
    <preference for="Magento\Sales\Model\Order" type="Mago\Delivery\Model\Rewrite\Order" />
</config>

app/code/Mago/Delivery/Model/Rewrite/Order.php

<?php

namespace Mago\Delivery\Model\Rewrite;

class Order extends \Magento\Sales\Model\Order
{

    public function getDeliveryDate()
    {
        $orderDate = $this->getCreatedAt(); //ORDER CREATED DATE
        return date('Y-m-d', strtotime($orderDate. ' + 10 days'));
    }

}

Finally in your email template you can get this date by:

{{var order.getDeliveryDate()}}

EDIT, new code with Order, Invoice and Creditmemo:

<?php
declare(strict_types=1);

namespace Acme\SalesEmail\Observer\Email;

use Magento\Framework\DataObject;
use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use Magento\Framework\Locale\ResolverInterface;
use Magento\Framework\Stdlib\DateTime\TimezoneInterface;
use Magento\Sales\Model\Order;
use Magento\Sales\Model\Order\Invoice;
use Magento\Sales\Model\Order\Creditmemo;

class OrderSetTemplateVarsBefore implements ObserverInterface
{
    protected TimezoneInterface $timezone;
    protected string            $locale;

    public function __construct(
        TimezoneInterface $timezone,
        ResolverInterface $localeResolver
    ) {
        $this->timezone = $timezone;
        $this->locale   = $localeResolver->getLocale();
    }

    /**
     * @inheritDoc
     */
    public function execute(Observer $observer): void
    {
        /** @var DataObject $transport */
        $transport = $observer->getEvent()->getData('transportObject');
        /** @var Order $order */
        $order     = $transport->getData('order');
        $orderData = $transport->getData('order_data');        
        /** @var Invoice $invoice */
        $invoice    = $transport->getData('invoice');
        $invoiceData = $transport->getData('invoice_data');
        /** @var Creditmemo $creditmemo */
        $creditmemo    = $transport->getData('creditmemo');
        $creditmemoData = $transport->getData('creditmemo_data');        

        $orderDate = new \DateTime($order->getCreatedAt(), new \DateTimeZone('UTC'));
        $orderData['order_date'] = $this->timezone->formatDateTime(
            $orderDate,
            \IntlDateFormatter::SHORT,
            \IntlDateFormatter::NONE,
            $this->locale
        );
        $transport->setData('order_data', $orderData);
        
        if($invoice){     
            $invoiceDate = new \DateTime($invoice->getCreatedAt(), new \DateTimeZone('UTC'));
            $invoiceData['invoice_date'] = $this->timezone->formatDateTime(
                $invoiceDate,
                \IntlDateFormatter::SHORT,
                \IntlDateFormatter::NONE,
                $this->locale
            );
            $transport->setData('invoice_data', $invoiceData);
        }
        
        if($creditmemo){     
            $creditmemoDate = new \DateTime($creditmemo->getCreatedAt(), new \DateTimeZone('UTC'));
            $creditmemoData['creditmemo_date'] = $this->timezone->formatDateTime(
                $creditmemoDate,
                \IntlDateFormatter::SHORT,
                \IntlDateFormatter::NONE,
                $this->locale
            );
            $transport->setData('creditmemo_data', $creditmemoData);
        }
    }
}

1 Answer 1

3

You should use the same logic described in comment https://magento.stackexchange.com/a/358427/91782

I don't recommend to rewrite models such Order just for get some value for email template.

You need to create observer for event email_order_set_template_vars_before, or you can use the same observer for prepare any required data and using transportObject add custom variables to order_data.

You can use order object from transportObject as current order

You also can cover following events (if needed):

  • email_order_comment_set_template_vars_before
  • email_invoice_set_template_vars_before
  • email_invoice_comment_set_template_vars_before
  • email_shipment_set_template_vars_before
  • email_shipment_comment_set_template_vars_before
  • email_creditmemo_set_template_vars_before
  • email_creditmemo_comment_set_template_vars_before

You can use single observer for all events because all of them are has order instance and order_data which you can extend for templates.

[Update]

It's easy to create separate module (extension) and you already provided an example in your answer, but I will repeat

1. Create Registration module file

app/code/Acme/SalesEmail/registration.php

<?php
declare(strict_types=1);

use Magento\Framework\Component\ComponentRegistrar;

ComponentRegistrar::register(ComponentRegistrar::MODULE, 'Acme_SalesEmail', __DIR__);

Where Acme is your vendor name and SalesEmail is module name

2. Define module and dependencies

app/code/Acme/SalesEmail/etc/module.xml

<?xml version="1.0" ?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Acme_SalesEmail">
        <sequence>
            <module name="Magento_Sales"/>
        </sequence>
    </module>
</config>

3. Register observers to events

app/code/Acme/SalesEmail/etc/events.xml

<?xml version="1.0" ?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
    <event name="email_order_set_template_vars_before">
        <observer name="acme_salesemail_observer_email_order_set_template_vars_before"
                  instance="Acme\SalesEmail\Observer\Email\OrderSetTemplateVarsBefore"/>
    </event>
    <event name="email_order_comment_set_template_vars_before">
        <observer name="acme_salesemail_observer_email_order_comment_set_template_vars_before"
                  instance="Acme\SalesEmail\Observer\Email\OrderSetTemplateVarsBefore"/>
    </event>
    <event name="email_invoice_set_template_vars_before">
        <observer name="acme_salesemail_observer_email_invoice_set_template_vars_before"
                  instance="Acme\SalesEmail\Observer\Email\OrderSetTemplateVarsBefore"/>
    </event>
    <event name="email_invoice_comment_set_template_vars_before">
        <observer name="acme_salesemail_observer_email_invoice_comment_set_template_vars_before"
                  instance="Acme\SalesEmail\Observer\Email\OrderSetTemplateVarsBefore"/>
    </event>
    <event name="email_shipment_set_template_vars_before">
        <observer name="acme_salesemail_observer_email_shipment_set_template_vars_before"
                  instance="Acme\SalesEmail\Observer\Email\OrderSetTemplateVarsBefore"/>
    </event>
    <event name="email_shipment_comment_set_template_vars_before">
        <observer name="acme_salesemail_observer_email_shipment_comment_set_template_vars_before"
                  instance="Acme\SalesEmail\Observer\Email\OrderSetTemplateVarsBefore"/>
    </event>
    <event name="email_creditmemo_set_template_vars_before">
        <observer name="acme_salesemail_observer_email_creditmemo_set_template_vars_before"
                  instance="Acme\SalesEmail\Observer\Email\OrderSetTemplateVarsBefore"/>
    </event>
    <event name="email_creditmemo_comment_set_template_vars_before">
        <observer name="acme_salesemail_observer_email_creditmemo_comment_set_template_vars_before"
                  instance="Acme\SalesEmail\Observer\Email\OrderSetTemplateVarsBefore"/>
    </event>
</config>

4. Create universal observer

app/code/Acme/SalesEmail/Observer/Email/OrderSetTemplateVarsBefore.php

<?php
declare(strict_types=1);

namespace Acme\SalesEmail\Observer\Email;

use Magento\Framework\DataObject;
use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use Magento\Framework\Locale\ResolverInterface;
use Magento\Framework\Stdlib\DateTime\TimezoneInterface;
use Magento\Sales\Model\Order;

class OrderSetTemplateVarsBefore implements ObserverInterface
{
    protected TimezoneInterface $timezone;
    protected string            $locale;

    public function __construct(
        TimezoneInterface $timezone,
        ResolverInterface $localeResolver
    ) {
        $this->timezone = $timezone;
        $this->locale   = $localeResolver->getLocale();
    }

    /**
     * @inheritDoc
     */
    public function execute(Observer $observer): void
    {
        /** @var DataObject $transport */
        $transport = $observer->getEvent()->getData('transportObject');
        /** @var Order $order */
        $order     = $transport->getData('order');
        $orderData = $transport->getData('order_data');

        $billing   = $order->getBillingAddress();
        $orderData['customer_firstname'] = $billing->getFirstname();
        $orderData['customer_lastname']  = $billing->getLastname();

        $deliveryDate = new \DateTime($order->getCreatedAt(), new \DateTimeZone('UTC'));
        $deliveryDate->add(new \DateInterval('P10D'));

        $orderData['delivery_date'] = $this->timezone->formatDateTime(
            $deliveryDate,
            \IntlDateFormatter::SHORT,
            \IntlDateFormatter::NONE,
            $this->locale
        );

        $transport->setData('order_data', $orderData);
    }
}

P.S.

You can use Generator Tool for create some skeleton of code

enter image description here

9
  • Thanks Victor! Can you help me out with the right custom module code? So we can implement it as a custom module?
    – JGeer
    Aug 7 at 12:18
  • See updated answer Aug 7 at 19:58
  • Thanks a lot! And how can we load it correct in the e-mail template then?
    – JGeer
    Aug 8 at 6:50
  • In the same way: {{var order_data.customer_firstname}} or {{trans "%firstname," firstname=$order_data.customer_firstname}} Aug 8 at 10:31
  • 1
    You can register invoice_data array for transport and populate it if invoice present. After you can use like {{var invoice_data.customer_firstname}}. Please see example and check transport object. You can find in core code by event name what the system pass into transport. You can use any variable which are you set into transport in template. 2 days ago

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.