2

Depending on a custom order's attribute, we would like to slightly adapt the emails for the new order confirmations.

Therefor, we try to implement a new equals directive in Magento\Framework\Filter\Template (we extend this class in a custom module, of course). This directive should take two parameters and evaluate whether these values are equal. Magento's build in if directive only checks, if the given parameter is not equal an empty string.

For example:

{{equals value1 value2}}The two parameters are equal.{{else}}The two parameters are NOT equal.{{/equals}}

We added the following constant to our custom Template.php:

const CONSTRUCTION_EQUALS_PATTERN = '/{{equals\s*(.*?)}}(.*?)({{else}}(.*?))?{{\\/equals\s*}}/si';

The value of this constant is the same as the value of the CONSTRUCTION_IF_PATTERN constant, except we replaced both if with equals.

Furthermore, we override the filter($value) function of the original Template and teach this function to execute a new callback named equalsDirective, if one of the given values matches to above defined pattern.

foreach ([
  self::CONSTRUCTION_DEPEND_PATTERN => 'dependDirective',
  self::CONSTRUCTION_IF_PATTERN => 'ifDirective',
  self::CONSTRUCTION_TEMPLATE_PATTERN => 'templateDirective',
  self::CONSTRUCTION_EQUALS_PATTERN => 'equalsDirective' // this is interesting line
] as $pattern => $directive)

The function equalsDirective just should write a debug message, when it's got called.

Additionally, we adapt the template for the new orders confirmation emails (Magento\Sales\view\email\order_new.html) by adding the following beneath the greeting:

{{equals order.checkout_type request}}This is a request.{{else}}This is an order.{{/equals}}

The problem is, the equalsDirective function never gets called. The given values of the filter function do not contain the above equals directive. Thus, a pattern -- as defined above -- never is found.

We also verified that {{var order.checkout_type}} returns the correct value. Surprisingly, this is not part of the given values of the filter function, as well. But its value is correctly rendered in the email that we received.

Has someone an idea what we missed? Do we have to declare the directives that are parsed from the email templates somewhere else?

We appreciate any help :)

FYI: Couple of years ago we did the same in Magento 1 and it was working fine.

1

This is what we found out after some more hours of research. Probably, it is not best practice, but it does work for now. We would be glad, if someone would give us hints in order to improve this solution.

It is not sufficient to only extend the Magento\Framework\Filter\Template and override the filter() function. In the Magento_Email module you can find the Model\Template\Filter which is used for the email template processing. This class extends the Magento\Framework\Filter\Template and overrides its filter() function, too. Inside this filter() function the parent function is called, which is not the function of our Template class but the one of Magento's original Template class (Magento\Framework\Filter\Template);

Thus, you have to override the Magento\Email\Model\Template\Filter class, as well. Copy the whole Filter class to your custom module and make it extend your -- previously mentioned -- Template class that extends the Magento\Framework\Filter\Template.

Now, we can use the above declared equals directive inside the email templates and it is working fine.

Nevertheless, we discovered the following drawbacks:

  • We had to copy the whole Filter class. Otherwise we need multiple inheritance from Magento\Framework\Filter\Template and Magento\Email\Model\Template\Filter.
  • The Filter class that we copied uses the Magento\Email\Model\Template\Css\Processor class. This class is not in the module's API. Thus, we copied this class to our custom module, as well.

As mentioned in the first paragraph, we would appreciate any hints that help us to improve this solution.

| improve this answer | |
1

Seems like in 2.3.4 this logic was modified and now you can use di.xml to inject your directives by passing it into the directiveProcessors property of the constructor, see gitlab link.

Taken from Magento's original article for v2.3.4

Create a class that implements Magento\Framework\Filter\SimpleDirective\ProcessorInterface:

declare(strict_types=1);
namespace GadgetCorp\CustomEmailDirective\Model;
use Magento\Framework\Filter\SimpleDirective\ProcessorInterface;
use Magento\Framework\Pricing\PriceCurrencyInterface;
/**
* Calculates the lifetime spend of all customers
*/
class LifetimeSpendDirective implements ProcessorInterface
{
 /**
 * @var PriceCurrencyInterface
 */
 private $priceCurrency;

 /**
 * @param PriceCurrencyInterface $priceCurrency
 */
 public function __construct(PriceCurrencyInterface $priceCurrency)
 {
     $this->priceCurrency = $priceCurrency;
 }

 /**
 * @inheritDoc
 */
 public function getName(): string
 {
     return 'lifetime_spend';
 }

 /**
 * @inheritDoc
 */
 public function process($value, array $parameters, ?string $html): string
 {
     $shouldBold = !empty($parameters['should_bold']);
     $amount = $this->priceCurrency->getCurrencySymbol() . $this->calculateLifetimeSpend();
     return ($shouldBold ? '<strong>' . $amount . '</strong>' : $amount);
 }

 /**
 * @inheritDoc
 */
 public function getDefaultFilters(): ?array
 {
     // Make sure newlines are converted to <br /> tags by default
     return ['nl2br'];
 }

 /**
 * Calculate the total amount of money spent by all customers for all time
 *
 * @return float
 */
 private function calculateLifetimeSpend(): float
 {
     // Add code here to calculate the lifetime spend
     return 123.45;
 }

}

Add the new directive to the pool by adding this block to di.xml.

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
 <type name="Magento\Framework\Filter\SimpleDirective\ProcessorPool">
 <arguments>
     <argument name="processors" xsi:type="array">
         <item name="lifetime_spend" xsi:type="object">GadgetCorp\CustomEmailDirective\Model\LifetimeSpendDirective</item>
     </argument>
 </arguments>

| improve this answer | |

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.