核心概念:邮件模板如何工作?

Magento 2 的邮件发送流程基于 模板加载器变量解释器

magento邮件模板变量
(图片来源网络,侵删)
  1. 模板加载器:当你触发一个邮件事件(如下单、创建账户等),Magento 会根据预定义的配置加载一个特定的 .html 模板文件。
  2. 变量解释器:模板引擎会扫描这个 HTML 文件,找到所有以 开头和 结尾的“变量占位符”。
  3. 数据替换:系统会根据当前的上下文(当前订单、当前客户)从相应的数据模型中获取数据,并用这些实际数据替换掉模板中的变量占位符。

变量的类型和常见示例

Magento 2 的邮件变量主要分为以下几类:

全局变量

这些变量在大多数邮件模板中都可用,它们通常与当前作用域有关,比如当前订单、当前客户等。

变量代码 描述 示例
{{var customer.name}} 客户的姓名 John Doe
{{var customer.email}} 客户的电子邮件 john.doe@example.com
{{var order.increment_id}} 订单号 100000045
{{var order.created_at}} 订单创建日期和时间 2025-10-27 10:30:00
{{var order.grand_total}} 订单总金额 $150.99
{{var order.shipping_address.format('html')}} 格式化的配送地址 HTML <address>...</address>
{{var order.billing_address.format('html')}} 格式化的账单地址 HTML <address>...</address>
{{var store.frontend_name}} 当前商店的名称 My Awesome Store
{{var store.url}} 当前商店的 URL https://www.myawesomestore.com

订单相关变量

这些变量专门用于展示订单的详细信息,通常在订单确认、发货等邮件中使用。

变量代码 描述 示例
{{var order.getShippingDescription()}} 配送方式名称 Flat Rate - Fixed
{{var order.getPaymentMethod().getTitle()}} 支付方式标题 Check / Money order
{{var order.getAllVisibleItems()}} 订单中所有可见商品的集合 一个商品对象列表
{{var order.getAllVisibleItems().getSize()}} 订单中商品的数量 3
{{var order.getCouponCode()}} 使用的优惠券代码 WELCOME10

商品相关变量

这些变量需要与订单商品变量结合使用,用于遍历和展示订单中的每一个商品。

magento邮件模板变量
(图片来源网络,侵删)

在模板中,你通常会使用一个 foreach 循环来遍历商品集合:

{{var order.getAllVisibleItems().each(function(item){})}
    <!-- 循环体内的变量使用 item 前缀 -->
    <tr>
        <td>{{var item.getName()}}</td>
        <td>{{var item.getSku()}}</td>
        <td>{{var item.getQtyOrdered()}}</td>
        <td>{{var item.getPrice()}}</td>
        <td>{{var item.getRowTotal()}}</td>
    </tr>
{{/var}}
变量代码 (在循环内) 描述
{{var item.getName()}} 商品名称
{{var item.getSku()}} 商品 SKU
{{var item.getProductUrl()}} 商品详情页 URL
{{var item.getQtyOrdered()}} 已订购数量
{{var item.getPrice()}} 商品单价
{{var item.getRowTotal()}} 该商品行总价
{{var item.getImage().toHtml()}} 商品图片的 HTML <img>

自定义变量

这是 Magento 2 最强大的功能之一,你可以为任何数据模型(如客户、产品、订单)添加自定义属性,然后在邮件模板中直接使用它们。

场景示例:假设你在客户注册表单中增加了一个“生日”字段,并希望在新用户欢迎邮件中显示生日祝福。

  1. 确保数据已保存:确保“生日”字段的数据已经正确保存到 customer_entity 数据表中。
  2. 在模板中使用
    Dear {{var customer.name}},
    <br>
    Welcome to our store! We see that your birthday is on {{var customer.dob}}. Happy Birthday in advance!
    <br>
    ...

    注意:这里的 dob 是你数据库中字段名的蛇形命名法表示。

    magento邮件模板变量
    (图片来源网络,侵删)

如何在邮件模板中使用变量

在 HTML 模板文件中直接使用

这是最常见的方式,打开你的邮件模板文件(sales/order/new.html),直接将变量插入到 HTML 代码中。

<!-- 文件: app/design/frontend/Vendor/theme/Magento_Sales/templates/email/order/new.html -->
{{template config_path="email/header"}}
<h1>Your Order #{{var order.increment_id}} Has Been Placed</h1>
<p>Hello {{var customer.name}},</p>
<p>Thank you for your order from {{var store.frontend_name}}. Your order is confirmed and will be processed soon.</p>
<h2>Order Details</h2>
<table>
    <thead>
        <tr>
            <th>Product Name</th>
            <th>SKU</th>
            <th>Qty</th>
            <th>Price</th>
        </tr>
    </thead>
    <tbody>
        {{var order.getAllVisibleItems().each(function(item){})}
        <tr>
            <td>{{var item.getName()}}</td>
            <td>{{var item.getSku()}}</td>
            <td>{{var item.getQtyOrdered()}}</td>
            <td>{{var order.formatPrice(item.getPrice())}}</td> <!-- 使用格式化函数 -->
        </tr>
        {{/var}}
    </tbody>
</table>
<p><strong>Grand Total:</strong> {{var order.formatPrice(order.grand_total)}}</p>
{{template config_path="email/footer"}}

使用 .phtml 文件作为模板

对于更复杂的逻辑,你可以创建一个 .phtml 文件,然后在 HTML 模板中通过 {{block}} 指令来引用它。

  1. 创建 PHTML 文件

    // 文件: app/code/Vendor/Module/view/frontend/email/order/items.phtml
    <?php
    /** @var $block \Vendor\Module\Block\Order\Email\Items */
    $items = $block->getOrder()->getAllVisibleItems();
    ?>
    <table>
        <?php foreach ($items as $item): ?>
        <tr>
            <td><?= $block->escapeHtml($item->getName()) ?></td>
            <td><?= $block->escapeHtml($item->getSku()) ?></td>
            <!-- 可以在这里写更复杂的 PHP 逻辑 -->
        </tr>
        <?php endforeach; ?>
    </table>
  2. 在 HTML 模板中引用

    <!-- 在你的 new.html 文件中 -->
    ...
    <tbody>
        {{block class='Vendor\Module\Block\Order\Email\Items' area='frontend' order='order' template='Vendor_Module::email/order/items.phtml'}}
    </tbody>
    ...

如何查找所有可用的变量

当你不确定某个变量是否存在或如何调用时,可以采用以下方法:

查看核心文件

这是最权威的方法,邮件模板的变量定义通常在模块的 etc/email_templates.xml 文件中。

查看 Magento_Sales 模块的文件: vendor/magento/module-sales/etc/email_templates.xml

你会看到类似这样的结构:

<template id="sales_order_new" label="New Order" file="order_new.html" type="html">
    <variable name="order" required="true">Order</variable>
    <variable name="billing" required="true">Order Billing Address</variable>
    <variable name="payment_html" required="true">Payment Details</variable>
    <variable name="store" required="true">Store</variable>
    <variable name="customer" required="true">Customer</variable>
</template>

这个文件定义了 sales_order_new 这个邮件模板有哪些可用的变量(order, billing 等)以及它们对应的数据模型。

使用 var/log/debug.log 日志

在模板中,你可以尝试输出一个对象的类型,以便了解它有哪些方法。

<!-- 在模板中添加这行,然后检查日志 -->
<p>Order object class: {{var order.getClass()}}</p>
<p>Customer object class: {{var customer.getClass()}}</p>

这会输出类似 Magento\Sales\Model\OrderMagento\Customer\Model\Customer 的类名,然后你可以去查看这些模型的 PHP 类文件,了解它们有哪些公共方法(即可以在模板中调用的方法)。

使用第三方模块

市面上有一些优秀的开发者工具,如 FireGento_DebugEcomDev_PHPUnit,可以帮助你更直观地查看模板变量。


最佳实践和注意事项

  1. 始终转义输出:为了防止 XSS 攻击,对于任何可能包含用户输入的变量,都应使用 escapeHtmlescapeUrl 等方法。

    <!-- 安全 -->
    <td>{{var block.escapeHtml(item.getName())}}</td>
    <!-- 不安全 -->
    <td>{{var item.getName()}}</td>

    注意:在标准的 HTML 模板中,Magento 的模板引擎通常会自动进行基本的转义,但养成手动转义的习惯更安全。

  2. 使用辅助方法:许多数据模型(如 Order, Store)提供了格式化方法,如 formatPrice(), formatDate(),优先使用它们来保证格式的一致性。

    <!-- 推荐 -->
    <td>{{var order.formatPrice(item.getPrice())}}</td>
    <!-- 不推荐 -->
    <td>$ {{var item.getPrice()}}</td>
  3. 保持模板简洁:如果模板逻辑过于复杂,考虑将其拆分到一个独立的 .phtml 文件中,以提高可维护性。

  4. 测试:在部署到生产环境前,务必在不同的场景下(不同客户、不同订单、不同商品)充分测试你的邮件模板,确保所有变量都按预期显示。

希望这份详细的指南能帮助你更好地理解和使用 Magento 2 的邮件模板变量!