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 🙂