Magento – How to add custom option in quote or order item

magento2quotequoteitem

We are trying to add custom option or custom value in quote item so that we can also get it in order item.

We are able to add custom value in quote using following code but it is get returning value in order item

  $quote = $this->quoteRepository->getActive($cartId);
    foreach ($quote->getAllItems() as $item) {
            $item->setCustomValue(1);
            $item->save();

     }

Best Answer

You can achieve by a plugin in Magento 2.2.*

First of all, we need to create an observer file and one Magento event file to implement this functionality.

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
    <event name="catalog_product_load_after">
        <observer name="set_additional_options" instance="CompanyName\ModuleName\Model\SetAdditionalOptions" />
    </event>    
</config>

Once you have created this file, now you need to Create another file and named as: CompanyName\ModuleName/Model/SetAdditionalOptions.php

<?php
namespace CompanyName\ModuleName\Model;

use Magento\Framework\Event\ObserverInterface;
use Magento\Framework\App\RequestInterface;
use Magento\Framework\App\ObjectManager;
use Magento\Framework\Serialize\Serializer\Json;

class SetAdditionalOptions implements ObserverInterface
{
    protected $_request;    
    public function __construct(RequestInterface $request, Json $serializer = null) 
    {
        $this->_request = $request;
        $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance()
            ->get(\Magento\Framework\Serialize\Serializer\Json::class);
    }

    /**
     * @param \Magento\Framework\Event\Observer $observer
     */
    public function execute(\Magento\Framework\Event\Observer $observer)
    {
        // Check and set information according to your need
        $product = $observer->getProduct();                    
        if ($this->_request->getFullActionName() == 'checkout_cart_add') { //checking when product is adding to cart
            $product = $observer->getProduct();
            $additionalOptions = [];
            $additionalOptions[] = array(
                'label' => "Release Date", //Custom option label
                'value' => $product->getReleaseDate(), //Custom option value
            );                        
            $product->addCustomOption('additional_options', $this->serializer->serialize($additionalOptions));
        }
    }

}

Now, We need to create a plugin for the retrieve custom option from cart to order.

First We need to create di.xml.

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Quote\Model\Quote\Item\ToOrderItem">
        <plugin name="unique_name" type="CompanyName\ModuleName\Model\Plugin\Quote\ToOrderItem" sortOrder="1" />
    </type>
</config>

Once you have created this file, now you need to Create another file and named as: CompanyName\ModuleName\Model\Plugin\Quote\ToOrderItem.php

<?php
namespace ZCompanyName\ModuleName\Model\Plugin\Quote;

use Magento\Quote\Model\Quote\Item\ToOrderItem as QuoteToOrderItem;
use Magento\Framework\Serialize\Serializer\Json;
class ToOrderItem
{    
    public function __construct(Json $serializer = null) 
    {        
        $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance()
            ->get(\Magento\Framework\Serialize\Serializer\Json::class);
    }

    public function aroundConvert(QuoteToOrderItem $subject,
        \Closure $proceed,
        $item,
        $data = []
    ) {
        // Get Order Item
        $orderItem = $proceed($item, $data);               

        $additionalOptions = $item->getOptionByCode('additional_options');        
        // Check if there is any additional options in Quote Item                    
        if (count($additionalOptions) > 0) {
            // Get Order Item's other options
            $options = $orderItem->getProductOptions();
            // Set additional options to Order Item
            $options['additional_options'] = $this->serializer->unserialize($additionalOptions->getValue());
            $orderItem->setProductOptions($options);
        }

        return $orderItem;
    }
}