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
相关产品推荐
相关产品推荐

