Search code examples
productmagento2cartcheckout

Magento 2 how to pass additional data while add to cart product


I have added input field in product detail page and need to save with cart without any product attribute and new table column. How to do this?


Solution

  • To do this, you can use additional_options by using event-observer.

    Please check my below answer.

    events.xml : app\code\Vendor\Module\etc\events.xml

    <?xml version="1.0"?>
    <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
    
       <!-- add option with quote item when add to cart -->
        <event name="checkout_cart_product_add_after">
         <observer name="pf_checkout_cart_product_add_after" instance="Vendor\Module\Observer\CheckoutCartAddObserver" />
        </event>
    
        <!-- add option with quote item with ORDER -->
        <event name="sales_model_service_quote_submit_before">
         <observer name="pf_sales_model_service_quote_submit_before" instance="Vendor\Module\Observer\QuoteSubmitObserver" />
        </event>
    </config>
    

    CheckoutCartAddObserver: app\code\Vendor\Module\Observer\CheckoutCartAddObserver.php

    <?php
    
    namespace Vendor\Module\Observer;
    
    use Magento\Framework\Event\Observer as EventObserver;
    use Magento\Framework\Event\ObserverInterface;
    
    /**
     * CheckoutCartAddObserver
     */
    class CheckoutCartAddObserver implements ObserverInterface
    {
        protected $_layout;
        protected $_storeManager;
        protected $_request;
        
        /**
         * __construct
         *
         * @param \Magento\Store\Model\StoreManagerInterface storeManager
         * @param \Magento\Framework\View\LayoutInterface layout
         * @param \Magento\Framework\App\RequestInterface request
         * @param \Magento\Framework\Serialize\SerializerInterface serializer
         *
         */
        public function __construct(
            \Magento\Store\Model\StoreManagerInterface $storeManager,
            \Magento\Framework\View\LayoutInterface $layout,
            \Magento\Framework\App\RequestInterface $request,
            \Magento\Framework\Serialize\SerializerInterface $serializer
        ) {
            $this->_layout = $layout;
            $this->_storeManager = $storeManager;
            $this->_request = $request;
            $this->serializer = $serializer;
        }
        
        /**
         * execute
         *
         * @param EventObserver observer
         *
         * @return void
         */
        public function execute(EventObserver $observer)
        {
            $postValue = $this->_request->getParams();
    
            // product_color_shade is input field in product view page
            if (isset($postValue['product_color_shade']) &&
                $postValue['product_color_shade']) {
                $item = $observer->getQuoteItem();
    
                $colorShade = [];
                $colorShade[] = [
                                'label' => 'Color Shade',
                                'value' => $postValue['product_color_shade'],
                        ];
    
                if (count($colorShade) > 0) {
                    $item->addOption([
                        'product_id' => $item->getProductId(),
                        'code' => 'additional_options',
                        'value' => $this->serializer->serialize($colorShade),
                    ]);
                }
            }
        }
    }
    

    QuoteSubmitObserver: app\code\Vendor\Module\Observer\QuoteSubmitObserver.php

    <?php
    
    namespace Vendor\Module\Observer;
    
    use Magento\Framework\Event\Observer as EventObserver;
    use Magento\Framework\Event\ObserverInterface;
    
    /**
     * QuoteSubmitObserver
     */
    class QuoteSubmitObserver implements ObserverInterface
    {
        private $quoteItems = [];
        private $quote = null;
        private $order = null;
        
        /**
         * __construct
         *
         * @param \Magento\Store\Model\StoreManagerInterface storeManager
         * @param \Magento\Framework\View\LayoutInterface layout
         * @param \Magento\Framework\App\RequestInterface request
         * @param \Magento\Framework\Serialize\SerializerInterface serializer
         *
         */
        public function __construct(
            \Magento\Store\Model\StoreManagerInterface $storeManager,
            \Magento\Framework\View\LayoutInterface $layout,
            \Magento\Framework\App\RequestInterface $request,
            \Magento\Framework\Serialize\SerializerInterface $serializer
        ) {
            $this->_layout = $layout;
            $this->_storeManager = $storeManager;
            $this->_request = $request;
            $this->serializer = $serializer;
        }
        
        /**
         * execute
         *
         * @param EventObserver observer
         *
         * @return void
         */
        public function execute(EventObserver $observer)
        {
            $this->quote = $observer->getQuote();
            $this->order = $observer->getOrder();
            foreach ($this->order->getItems() as $orderItem) {
                if ($quoteItem = $this->getQuoteItemById($orderItem->getQuoteItemId())) {
                    if ($additionalOptionsQuote = $quoteItem->getOptionByCode('additional_options')) {
                        if ($additionalOptionsOrder = $orderItem->getProductOptionByCode('additional_options')) {
                            $additionalOptions = array_merge($additionalOptionsQuote, $additionalOptionsOrder);
                        } else {
                            $additionalOptions = $additionalOptionsQuote;
                        }
                        if (count($additionalOptions->getData()) > 0) {
                            $options = $orderItem->getProductOptions();
                            $options['additional_options'] = $this->serializer->unserialize($additionalOptions->getValue());
                            $orderItem->setProductOptions($options);
                        }
                    }
                }
            }
        }
        
        /**
         * getQuoteItemById
         *
         * @param mixed id
         *
         * @return void
         */
        private function getQuoteItemById($id)
        {
            if (empty($this->quoteItems)) {
                if ($this->quote->getItems()) {
                    foreach ($this->quote->getItems() as $item) {
                        $this->quoteItems[$item->getId()] = $item;
                    }
                }
            }
            if (array_key_exists($id, $this->quoteItems)) {
                return $this->quoteItems[$id];
            }
    
            return null;
        }
    }
    

    catalog_product_view.xml: app\code\Vendor\Module\view\frontend\layout\catalog_product_view.xml

    <?xml version="1.0"?>
    <page layout="1column" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
        <body>
            <referenceContainer name="product.info.form.content">
                <block class="Magento\Catalog\Block\Product\View" name="color.shade" template="Vendor_Module::color_shade.phtml" before="product.info.addtocart" />
            </referenceContainer>
        </body>
    </page>
    

    color_shade.phtml :app\code\Vendor\Module\view\frontend\templates\color_shade.phtml

    <input type="text" name="product_color_shade" id="product_color_shade" />
    

    By this, you can add your custom product related values in cart and also in quote. So this value will bind with order and will display in order data. (Backend and Frontend)