Ostatnio rozmawialiśmy o tworzeniu e-maili w Magento 1. Czas na Magento 2. Nie jest tajemnicą, że Magento 2 totalnie zmieniło swoją architekturę. Jednak co do zasady wiele funkcjonalności działa podobnie. Dziś pokażę Wam jak stworzyć e-mail przypominający o konieczności dokonania płatności za złożone zamówienie.
Gdzie znajdują się szablony e-mail w Magento 2?
Magento 2 charakteryzuje się większą „kapsulacją”. Oznacza to, że jeśli będziemy szukać e-maili sprzedażowych, należałoby zajrzeć do lokalizacji
vendor/magento/module-sales/view/frontend/email
Jeżeli natomiast interesuje nas szablon e-mail formularza kontaktowego:
vendor/magento/module-contact/view/frontend/email/submitted_form.html
Jest to podstawowa różnica w stosunku do magento 1. Jeśli więc będziemy tworzyć swój indywidualny e-mail, umieścimy go w przestrzeni naszego modułu.
Jak dodać nowy szablon e-mail w Magento 2?
Załóżmy, że mamy swój moduł Namespace_Payreminder i chcemy, aby obsługiwał wysłanie naszego reminder’a. W tym celu potrzebujemy dwóch dodatkowych plików poza module.xml w katalogu etc naszego modułu, a mianowicie:
Namespace/Payreminder/etc/config.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Store:etc/config.xsd">
<default>
<design>
<email>
<payreminder>payreminder_email_general_email</payreminder>
</email>
</design>
</default>
</config>
Namespace/Payreminder/etc/email_templates.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Email:etc/email_templates.xsd">
<template id="payreminder_email_general_email" label="Payreminder" file="payreminder.html" type="html" module="Namespace_Payreminder" area="frontend"/>
</config>
Dzięki tym dwóm plikom powiemy naszemu sklepowi skąd ma wziąć plik szablonu e-mail (email_templates.xml) i jaki będzie jego id-handler dla wywołań w skrypach. Plik email_templates.xml stanowi więc uzupełnienie dla szablonu zgłaszanego w pliku config.xml. Całość dzięki temu nabiera większej czytelności, choć dla wielu może być to skomplikowaniem czegoś co świetnie działało w Magento 1. Jednak jak się tak lepiej zastanowić, to w magento 1 w pliku config.xml modułu, można było znaleźć dosłownie wszystko – w przypadku bardziej skomplikowanych modułów bardzo zamazywało to jego czytelność. Dla mnie więc osobiście ta zmiana jest bardzo na plus.
Wracając do szablonów, aby dodać treść naszego szablonu wystarczy stworzyć plik w lokalizacji:
Namespace/Payreminder/view/frontend/email/payreminder.html
o treści:
<!--@subject Payment reminder @-->
<!--@vars {
"var formattedBillingAddress|raw":"Billing Address",
"var order.getEmailCustomerNote()":"Email Order Note",
"var order.increment_id":"Order Id",
"layout handle="sales_email_order_items" order=$order area="frontend"":"Order Items Grid",
"var payment_html|raw":"Payment Details",
"var formattedShippingAddress|raw":"Shipping Address",
"var order.getShippingDescription()":"Shipping Description"
} @-->
{{template config_path="design/email/header_template"}}
Dzień dobry,
<br />
Nie odnotowaliśmy płatności za {{trans 'zamówienie nr #%increment_id' increment_id=$order.increment_id |raw}}
Pozdrawiamy
Twój sklep
{{template config_path="design/email/footer_template"}}
Jeśli poprawnie wszystko uzupełnicie, będziecie mogli odnaleźć i załadować swój e-mail za pomocą mechanizmu, o którym pisałam w artykule dot. e-maili tranksakcyjnych w Magento 2 i customizacji e-maili sprzedażowych.
Warto również zauważyć, że o ile wcześniej nasze e-maile leżały w konkretnym language pack’u, tak teraz możemy dokonywać tłumaczeń bezpośrednio w mailu. Służy do tego funkcja trans().
Tworzenie konfiguracji dla e-maili transakcyjnych
Podobnie jak w Magento 1 tak i w Magento 2 mamy tzw. „store configuration”. Jest to bardzo przydatna funkcjonalność do określania indywidualnych konfiguracji dla poszczególnych storów / websitów. W tym celu podobnie jak w magento1 musimy stworzyć plik system.xml.
Zmianie uległa natomiast lekko lokalizacja:
Namespace/Payreminder/etc/adminhtml/system.xml
W pliku tym umieścić należy poniższy xml:
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd">
<system>
<section id="payreminder_email" translate="label" sortOrder="130" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Payreminder</label>
<tab>sales</tab>
<resource>Namespace_Payreminder::configuration</resource>
<group id="general" translate="label" type="text" sortOrder="10" showInDefault="1" showInWebsite="0" showInStore="0">
<label>General</label>
<field id="email" translate="label comment" type="select" sortOrder="3" showInDefault="1" showInWebsite="1" showInStore="1" canRestore="1">
<label>Template</label>
<comment>Email template chosen based on theme fallback when "Default" option is selected.</comment>
<source_model>Magento/Config/Model/Config/Source/Email/Template</source_model>
</field>
</group>
</section>
</system>
</config>
Najważniejszą różnicą pomiędzy Magento 1, a Magento 2, która na moment mnie wstrzymała, to ID szablonu. Wcześniej tak naprawdę nie ważne było, pod jakim ID jest szablon, a pod jakim konfiguracja dla niego. Tutaj po nazwaniu pola konfiguracyjnego email otrzymałam komunikat w pliku var/log/exception.log:
![]()
Na nic czyszczenie cache, robienie upgrade i sto innych prób wyświetlenia czegoś na ekranie. Próbowałam podstawiać inne rodzaje source_model. Ku memu zdziwieniu działały. Zmieniłam ID szablonu, na to wskazane w logu, w plikach config.xml oraz emails_templates.xml i zadziałało 🙂
Podobnie jak w przypadku Magento 1, jeśli chcemy korzystać ze store config, musimy zmodyfikować nasz skrypt PHP, tak by pobierał informacje o identyfikatorze szablonu.
$transport = $this->transportBuilder->setTemplateIdentifier(
$this->scopeConfig->getValue('payreminder_email/general/email',
MagentoStoreModelScopeInterface::SCOPE_STORE)
)
->setTemplateOptions($templateOptions)
->setTemplateVars($templateVars)
->setFrom($sender)
->addTo($to)
->getTransport();
Ustawienia ACL w Magento 2 dla konfiguracji naszego modułu
Skoro nasza konfiguracja już działa, pozostaje upewnić się, że tylko odpowiedni operatorzy (np. tylko admini) mają do niej dostęp. W tym celu tworzymy plik:
Namespace/Payreminder/etc/acl.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Acl/etc/acl.xsd">
<acl>
<resources>
<resource id="Magento_Backend::admin">
<resource id="Magento_Backend::stores">
<resource id="Magento_Backend::stores_settings">
<resource id="Magento_Config::config">
<resource id="Namespace_Payreminder::configuration" title="Payreminder" />
</resource>
</resource>
</resource>
</resource>
</resources>
</acl>
</config>
Zauważcie, że resource id jest taki sam jak w pliku: Namespace/Payreminder/etc/adminhtml/system.xml
Teraz pozostaje już tylko sprawdzić czy nasza rola się wyświetla. Znajdziemy ją w drzewie w lokalizacji:
System → Role użytkownika → Dodaj rolę → Zasoby roli
Wysyłanie e-maili w Magento 2 za pomocą PHP
Następnym krokiem jest przygotowanie skryptu shellowego dla Magento 2.
W naszym głównym katalogu projektu tworzymy plik payreminder.php z zawartością:
<?php
require_once __DIR__ . '/app/bootstrap.php';
class Payreminder implements MagentoFrameworkAppInterface
{
protected $orderRepository;
protected $storeManager;
protected $scopeConfig;
protected $inlineTranslation;
protected $transportBuilder;
protected $state;
public function __construct(
\Magento\Framework\App\State $state,
\Magento\Sales\Api\OrderRepositoryInterface $orderRepository,
\Magento\Store\Model\StoreManagerInterface $storeManager,
\Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
\Magento\Framework\Translate\Inline\StateInterface $inlineTranslation,
\Magento\Framework\Mail\Template\TransportBuilder $transportBuilder
)
{
$state->setAreaCode(MagentoFrameworkAppArea::AREA_GLOBAL);
$this->orderRepository = $orderRepository;
$this->storeManager = $storeManager;
$this->scopeConfig = $scopeConfig;
$this->inlineTranslation = $inlineTranslation;
$this->transportBuilder = $transportBuilder;
}
public function launch()
{
$order = $this->orderRepository->get(1);
$storeId = $order->getStoreId();
$templateOptions = array('area' => MagentoFrameworkAppArea::AREA_FRONTEND, 'store' => $storeId);
$templateVars = array(
'store' => $this->storeManager->getStore($order->getStoreId()),
'order' => $order,
);
$this->inlineTranslation->suspend();
$to = array($order->getCustomerEmail());
$sender = [
'name' => $this->scopeConfig->getValue(
'trans_email/ident_sales/name',
MagentoStoreModelScopeInterface::SCOPE_STORE
),
'email' => $this->scopeConfig->getValue(
'trans_email/ident_sales/email',
MagentoStoreModelScopeInterface::SCOPE_STORE
)
];
$transport = $this->transportBuilder->setTemplateIdentifier('payreminder_email_general_email')
->setTemplateOptions($templateOptions)
->setTemplateVars($templateVars)
->setFrom($sender)
->addTo($to)
->getTransport();
$transport->sendMessage();
$this->inlineTranslation->resume();
die();
}
public function catchException(
MagentoFrameworkAppBootstrap $bootstrap,
Exception $exception)
{
echo "expcetionn";
return true;
}
}
$bootstrap = MagentoFrameworkAppBootstrap::create(BP, $_SERVER);
$app = $bootstrap->createApplication('Payreminder');
$bootstrap->run($app);
Skrypt nie jest trudny w zrozumieniu. To co wymaga jednak wytłumaczenia, to struktura klasy. InterfaceAppInterface wymaga od nas posiadania metody launch() i catchException(). Pierwsza z nich to idealne miejsce dla „ciała” naszego skryptu. Skrypt nie posiada pętli, która by wskazywała, które zamówienia powinny być notyfikowane. Na potrzeby tego artykułu wzięłam jedynie pod uwagę zamówienie o ID = 1.
Dzięki temu artykułowi sama czegoś się nowego nauczyłam 🙂 Podobnie jak dla Was tak i dla mnie był mój pierwszy e-mail w Magento 2. Mój pierwszy własny e-mail w Magento 2!
W następnym poście popełnię zestawienie najważniejszych kwestii dot. e-maili w Magento zarówno 1 jak i 2. Do zobaczenia 🙂