求助:Magento2自定义配送方式附加数据无法保存至报价与订单
嘿,刚上手Magento2遇到这种自定义配送方式的附加数据保存问题太正常了,我来一步步给你捋清楚怎么搞定!
第一步:确保前端表单数据能正确提交到后端
首先得让你添加的附加表单字段数据在结账时被一起提交。在你的自定义配送方式的前端模板(比如 view/frontend/templates/shipping_method/your_custom_method.phtml)里,把表单字段放在结账配送地址表单的范围内,并且字段名最好用统一前缀,方便后端识别:
<div class="custom-delivery-field"> <label for="delivery_special_note"><?= __('Special Delivery Instructions') ?></label> <input type="text" name="shipping_additional[delivery_note]" id="delivery_special_note" class="input-text" /> </div>
记得要通过布局XML把这个模板正确挂载到配送方式的渲染区块里,确保用户选择你的配送方式时能看到这个表单。
第二步:拦截配送信息保存,把数据存到Quote里
Magento2的结账流程中,Magento\Checkout\Model\ShippingInformationManagement::saveShippingInformation 是保存配送信息的核心方法,我们可以用插件来拦截它,获取前端提交的附加数据并存到Quote中:
- 先在你的模块
etc/di.xml里注册插件:
<type name="Magento\Checkout\Model\ShippingInformationManagement"> <plugin name="save_custom_delivery_quote_data" type="YourVendor\YourModule\Plugin\SaveCustomDeliveryQuoteData" /> </type>
- 编写插件类:
<?php namespace YourVendor\YourModule\Plugin; use Magento\Checkout\Model\ShippingInformationManagement; use Magento\Quote\Model\QuoteRepository; use Magento\Framework\App\RequestInterface; use Magento\Framework\ObjectManagerInterface; class SaveCustomDeliveryQuoteData { protected $quoteRepository; protected $request; protected $objectManager; public function __construct( QuoteRepository $quoteRepository, RequestInterface $request, ObjectManagerInterface $objectManager ) { $this->quoteRepository = $quoteRepository; $this->request = $request; $this->objectManager = $objectManager; } public function beforeSaveShippingInformation( ShippingInformationManagement $subject, $cartId, \Magento\Checkout\Api\Data\ShippingInformationInterface $addressInformation ) { // 拿到前端提交的附加数据 $additionalShippingData = $this->request->getParam('shipping_additional'); if (!empty($additionalShippingData['delivery_note'])) { $quote = $this->quoteRepository->getActive($cartId); // 用扩展属性存数据(不用改数据库表,符合Magento规范) $quoteExtension = $quote->getExtensionAttributes(); if (!$quoteExtension) { $quoteExtension = $this->objectManager->create( \Magento\Quote\Api\Data\QuoteExtensionInterface::class ); } $quoteExtension->setDeliveryNote($additionalShippingData['delivery_note']); $quote->setExtensionAttributes($quoteExtension); $this->quoteRepository->save($quote); } return [$cartId, $addressInformation]; } }
- 别忘了在
etc/extension_attributes.xml里定义Quote的扩展属性,这样Magento能识别这个字段:
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Api/etc/extension_attributes.xsd"> <extension_attributes for="Magento\Quote\Api\Data\QuoteInterface"> <attribute code="delivery_note" type="string" /> </extension_attributes> <!-- 同时提前定义Order的扩展属性,后面同步用 --> <extension_attributes for="Magento\Sales\Api\Data\OrderInterface"> <attribute code="delivery_note" type="string" /> </extension_attributes> </config>
第三步:把Quote里的附加数据同步到Order
当Quote转换为Order时,我们需要把刚才存在Quote里的数据复制到Order中,这里用Observer监听sales_convert_quote_to_order事件:
- 在
etc/events.xml里注册Observer:
<event name="sales_convert_quote_to_order"> <observer name="convert_custom_delivery_to_order" instance="YourVendor\YourModule\Observer\ConvertCustomDeliveryToOrder" /> </event>
- 编写Observer类:
<?php namespace YourVendor\YourModule\Observer; use Magento\Framework\Event\Observer; use Magento\Framework\Event\ObserverInterface; use Magento\Framework\ObjectManagerInterface; class ConvertCustomDeliveryToOrder implements ObserverInterface { protected $objectManager; public function __construct(ObjectManagerInterface $objectManager) { $this->objectManager = $objectManager; } public function execute(Observer $observer) { $quote = $observer->getQuote(); $order = $observer->getOrder(); // 从Quote扩展属性拿到数据 $deliveryNote = $quote->getExtensionAttributes()->getDeliveryNote(); if ($deliveryNote) { // 把数据存到Order的扩展属性里 $orderExtension = $order->getExtensionAttributes(); if (!$orderExtension) { $orderExtension = $this->objectManager->create( \Magento\Sales\Api\Data\OrderExtensionInterface::class ); } $orderExtension->setDeliveryNote($deliveryNote); $order->setExtensionAttributes($orderExtension); // 如果你给sales_order表加了自定义字段,也可以直接这么存: // $order->setDeliveryNote($deliveryNote); } return $this; } }
额外注意点
- 如果你不想用扩展属性,而是想直接在数据库表中存储,可以创建安装脚本给
quote和sales_order表添加自定义字段(比如delivery_note),然后在代码中直接用$quote->setDeliveryNote(...)和$order->setDeliveryNote(...)来存取。 - 做完所有修改后,一定要执行
bin/magento cache:flush清除缓存,确保插件和Observer被正确加载。 - 可以在前端加一些表单验证,比如限制输入长度,提升用户体验。
这样操作下来,你的自定义配送方式的附加数据就能顺利保存到Quote和Order里啦!
内容的提问来源于stack exchange,提问作者Andrew Smith
相关产品推荐
相关产品推荐

