You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Magento 2自定义邮件模块获取订单及礼品消息异常排查

我来帮你搞定这个问题!你复制了Sales模块的getOrder方法但还是遇到订单对象为null的问题,核心原因是邮件场景下Registry里的current_order通常不存在,而且你可能没把订单对象正确传递到自定义Block里。下面是一步步的解决方案:

解决步骤

1. 重构自定义Block的代码,正确获取订单对象

不要直接照搬Magento\Sales\Block\Order\Items的逻辑,它依赖Registry(适合前端订单页面),而邮件模板里的Block需要直接接收订单数据。重新编写你的Block:

1.1 正确注入依赖并实现getOrder方法

<?php
namespace YourVendor\YourModule\Block\Email;

use Magento\Framework\View\Element\Template;
use Magento\Sales\Api\OrderRepositoryInterface;
use Magento\GiftMessage\Api\GiftMessageRepositoryInterface;
use Magento\Sales\Model\Order;

class OrderGiftMessage extends Template
{
    /**
     * @var OrderRepositoryInterface
     */
    protected $orderRepository;

    /**
     * @var GiftMessageRepositoryInterface
     */
    protected $giftMessageRepository;

    public function __construct(
        Template\Context $context,
        OrderRepositoryInterface $orderRepository,
        GiftMessageRepositoryInterface $giftMessageRepository,
        array $data = []
    ) {
        $this->orderRepository = $orderRepository;
        $this->giftMessageRepository = $giftMessageRepository;
        parent::__construct($context, $data);
    }

    /**
     * 获取订单对象
     * 优先从Block的data中取,其次通过order_id查询
     * @return Order|null
     */
    public function getOrder(): ?Order
    {
        // 优先用直接传递的订单对象(邮件场景下最可靠)
        if ($this->hasData('order')) {
            return $this->getData('order');
        }

        // 如果传递了order_id,通过Repository查询
        $orderId = $this->getData('order_id');
        if ($orderId) {
            try {
                return $this->orderRepository->get($orderId);
            } catch (\Exception $e) {
                $this->_logger->error('Failed to load order: ' . $e->getMessage());
                return null;
            }
        }

        return null;
    }

    /**
     * 获取订单级别的礼品消息
     * @return string
     */
    public function getOrderGiftMessage(): string
    {
        $order = $this->getOrder();
        if (!$order || !$order->getGiftMessageId()) {
            return '';
        }

        try {
            $giftMessage = $this->giftMessageRepository->get($order->getGiftMessageId());
            return $giftMessage->getMessage();
        } catch (\Exception $e) {
            $this->_logger->error('Failed to load gift message: ' . $e->getMessage());
            return '';
        }
    }
}

这里的核心优化点:

  • 优先使用直接传递给Block的订单对象(邮件生成时手动传递),比依赖Registry更可靠
  • 注入GiftMessageRepositoryInterface规范获取礼品消息,避免直接使用ObjectManager
  • 加入日志方便后续排查错误

2. 确保邮件生成时把订单对象传递给Block

假设你是通过Observer在订单支付成功后触发邮件发送,那在构建邮件模板时,必须把订单对象明确传递给自定义Block:

// 在你的Observer类中
public function execute(\Magento\Framework\Event\Observer $observer)
{
    $order = $observer->getEvent()->getOrder();
    // 其他业务代码...

    // 构建邮件
    $transport = $this->transportBuilder
        ->setTemplateIdentifier('your_email_template_id') // 替换成你的邮件模板ID
        ->setTemplateOptions([
            'area' => \Magento\Framework\App\Area::AREA_FRONTEND,
            'store' => $order->getStoreId()
        ])
        ->setTemplateVars([
            'order' => $order,
            // 直接创建Block并传递订单对象
            'gift_message_block' => $this->layoutFactory->create()
                ->createBlock(\YourVendor\YourModule\Block\Email\OrderGiftMessage::class)
                ->setData('order', $order)
        ])
        ->setFrom(['email' => 'sender@example.com', 'name' => 'Sender Name']) // 替换成你的发件人信息
        ->addTo('recipient@example.com') // 替换成指定邮箱
        ->getTransport();

    $transport->sendMessage();
}

如果你的邮件是通过layout XML定义的,要在XML里传递order参数:

<block class="YourVendor\YourModule\Block\Email\OrderGiftMessage" name="order.gift.message" template="YourVendor_YourModule::email/order_gift_message.phtml">
    <arguments>
        <argument name="order" xsi:type="object">Magento\Sales\Model\Order</argument>
    </arguments>
</block>

3. 修改邮件模板,通过Block获取礼品消息

不要再直接在模板里调用$_order->getGiftMessageId(),而是通过自定义Block的封装方法获取:

方式1:直接在邮件模板中插入Block

{{block class="YourVendor\YourModule\Block\Email\OrderGiftMessage" order=$order template="YourVendor_YourModule::email/order_gift_message.phtml"}}

方式2:在模板文件中调用Block方法

在你的邮件模板phtml文件里:

<?php $giftMessage = $block->getOrderGiftMessage(); ?>
<?php if ($giftMessage): ?>
    <div class="order-gift-message">
        <h4>Gift Message:</h4>
        <p><?= $block->escapeHtml($giftMessage) ?></p>
    </div>
<?php endif; ?>

4. 排查订单对象为null的常见问题

如果还是出现订单为null的情况,按下面步骤排查:

  • 检查Block是否接收到订单数据:在getOrder()方法里加日志,比如$this->_logger->info('Block data: ' . print_r($this->getData(), true));,看是否有order或order_id字段
  • 确认订单ID有效性:如果是通过order_id传递,检查ID是否正确,是否能通过OrderRepository查询到订单
  • 权限问题:确保邮件发送的代码有足够权限读取订单(后台触发的Observer通常没问题,但如果是前端触发,可能需要检查权限)

内容的提问来源于stack exchange,提问作者kafaya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 06:36:23