5

I am struggling with Bundle Product add to cart programmatically in Magento 2.

Here I need to add all products with custom price and quantity and I want to do this operation in Product list.phtml file.

Can you help me with this, please?

11
  • add your code. what you tried?
    – Bojjaiah
    Commented Nov 22, 2016 at 13:22
  • I just follow this article (magento.stackexchange.com/questions/112788/…) but I did not understand what is what in this array ('bundle_option' => [ 13 => 23, 20 => 24, 14 => 25, 16 => [ 0 => 21, 1 => 12, ], ],) Commented Nov 22, 2016 at 13:52
  • If you done with this can you explain me the parameters and right process to add a bundle product to cart programmatically ? Commented Nov 22, 2016 at 13:54
  • is it working my solutions?
    – Bojjaiah
    Commented Nov 24, 2016 at 5:43
  • I am trying this solution friend.Once it is working fine then let you know and accept your answer. Commented Nov 24, 2016 at 6:23

6 Answers 6

6

Create a Controller

<?php

namespace Company\Module\Controller\Index;

use Magento\Catalog\Model\Product;
use Magento\Catalog\Model\ProductFactory;
use Magento\Framework\App\Action\Action;
use Magento\Framework\App\Action\Context;
use Magento\Framework\Controller\Result\Json as ResultJson;
use Magento\Framework\Controller\Result\JsonFactory;
use Magento\Framework\Data\Form\FormKey;
use Magento\Checkout\Model\Cart;

class Addtocart extends Action
{
    /**
     * @var ProductFactory
     */
    private $productFactory;
    /**
     * @var Cart
     */
    private $cart;
    /**
     * @var FormKey
     */
    private $formKey;
    /**
     * @var JsonFactory
     */
    private $resultJsonFactory;

    /**
     * @param Context $context
     * @param FormKey $formKey
     * @param JsonFactory $resultJsonFactory
     * @param Cart $cart
     * @param ProductFactory $productFactory
     */
    public function __construct(
        Context $context,
        FormKey $formKey,
        JsonFactory $resultJsonFactory,
        Cart $cart,
        ProductFactory $productFactory
    ) {
        parent::__construct($context);
        $this->formKey = $formKey;
        $this->productFactory = $productFactory;
        $this->resultJsonFactory = $resultJsonFactory;
        $this->cart = $cart;
    }

    /**
     *
     * @return ResultJson
     */
    public function execute()
    {
        $data = $this->getRequest()->getParams();
        $resultData = [
            'status' => 'success',
            'status_code' => 1,
            'message' => __('Products Added successfully.')
        ];

        $result = $this->resultJsonFactory->create();
        $qty = 1;

        $product = $this->productFactory->create()->load($productId);
        $productsArray = $this->getBundleOptions($product);
        $params = [
            'product' => $productId,
            'bundle_option' => $productsArray,
            'qty' => $qty
        ];

        try {
            /**
             * Add bundle product in cart
             */
            if ($product->getId()) {
                $this->cart->addProduct($product, $params);
                $this->cart->save();
            }
        } catch (\Exception $e) {
            $resultData = [
                'status' => 'fail',
                'status_code' => 0,
                'message' => __('Unable to add the Product. Exception ' . $e->getMessage())
            ];
            return $result->setData($resultData);
        }
        return $result->setData($resultData);
    }

    /**
     * get all the selection products used in bundle product
     * @param $product
     * @return mixed
     */
    private function getBundleOptions(Product $product)
    {
        $selectionCollection = $product->getTypeInstance()
            ->getSelectionsCollection(
                $product->getTypeInstance()->getOptionsIds($product),
                $product
            );
        $bundleOptions = [];
        foreach ($selectionCollection as $selection) {
            $bundleOptions[$selection->getOptionId()][] = $selection->getSelectionId();
        }
        return $bundleOptions;
    }
}
1
  • 2
    Very helpful, three years later. Got me over a hump. Thank you.
    – kookaburra
    Commented Sep 9, 2021 at 22:43
4

This worked for me (Magento 2.2.6):

$product = $this->_productRepository->getById($id, false, null, true);
$this->_cart->addProduct($product, $data);

where $data is an array as shown below:

$data = [
    'qty' => 1,
    'product' => 45,
    'bundle_option' => [
        1 => 4,
        2 => 8, 
        3 => 2,
        4 => 7,
    ],
    'bundle_option_qty' => [
        1 => 1,
        2 => 4, 
        3 => 2,
        4 => 14,
    ]
];

the keys inside bundle_option and bundle_option_qty are indexes, not some ID's. I reckon it doesn't matter what these keys are as long as they correspond to the keys in the other array.

Items inside bundle_option array are options ID's and the other contains quantities so in this case we add 1 item ID=4, 4 items ID=8 and so on...

1
  • This saved me time, thanks for the correct answer to the data format Commented May 19, 2020 at 20:31
1

I'm a bit late to the party, but I was struggling with the same issue myself. There were a few bundle products with required attributes. In order to tackle this in my case, a seperate product attribute called "is_fixed_bundle" was created, and the below code was used to be able to add the product to cart including its required options from the catalog list, based on some of the answers used in this question. So, for people reading this and those who are working on Magento 2.3+, this might help.

app/code/Vendor/Module/etc/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\Catalog\Model\Product\Type\AbstractType">
        <plugin disabled="false" name="Vendor_Module_Plugin_Magento_Catalog_Model_Product_Type_AbstractType" sortOrder="10" type="Vendor\Module\Plugin\Magento\Catalog\Model\Product\Type\AbstractType"/>
    </type>

    <type name="Magento\Checkout\Controller\Cart\Add">
        <plugin disabled="false" name="Vendor_Module_Plugin_Magento_Checkout_Controller_Cart_Add" sortOrder="10" type="Vendor\Module\Plugin\Magento\Checkout\Controller\Cart\Add"/>
    </type>
</config>

Create the plugins:
app/code/Vendor/Module/Plugin/Magento/Catalog/Model/Product/Type/AbstractType.php

<?php
/**
 * Copyright ©  All rights reserved.
 * See COPYING.txt for license details.
 */
declare(strict_types=1);

namespace Vendor\Module\Plugin\Magento\Catalog\Model\Product\Type;

class AbstractType
{

    /**
     * There are some bundle products with attribute "is_fixed_bundle" indicating this product
     * contains required products in its bundle, magento by default does not allow adding these bundles
     * to cart without specifying the bundle products.
     * @param \Magento\Catalog\Model\Product\Type\AbstractType $subject
     * @param $result
     * @param $product
     * @return bool
     */
    public function afterIsPossibleBuyFromList(
        \Magento\Catalog\Model\Product\Type\AbstractType $subject,
        $result,
        $product
    ) {
        // check if result initially is false, because we only want to double-check then
        // please note this needs to have product attribute "is_fixed_bundle"
        if (!$result && $product->hasIsFixedBundle() && (bool) $product->getIsFixedBundle()) {
            return true;
        }
        return $result;
    }
}

Next is the Add plugin, which is a beforePlugin on the add to cart route:

<?php
/**
 * Copyright ©  All rights reserved.
 * See COPYING.txt for license details.
 */
declare(strict_types=1);

namespace Vendor\Module\Plugin\Magento\Checkout\Controller\Cart;

use Magento\Catalog\Model\{ProductFactory, Product};

class Add
{
    /**
     * @var ProductFactory
     */
    private $productFactory;

    /**
     * @param ProductFactory $productFactory
     */
    public function __construct(
         ProductFactory $productFactory
    )
    {
        $this->productFactory = $productFactory;
    }

    /**
     * @param \Magento\Checkout\Controller\Cart\Add $subject
     * @return array
     */
    public function beforeExecute(
        \Magento\Checkout\Controller\Cart\Add $subject
    ) {
        $requestParams = $subject->getRequest()->getParams();
        // we already have bundle option, meaning we're on product detail page, skip further processing of bundle options
        if (isset($requestParams['bundle_option'])) {
            return [];
        }
        $productId = (int)$subject->getRequest()->getParam('product');
        $product = $this->productFactory->create()->load($productId);
        if ($product && $product->hasIsFixedBundle() && (bool) $product->getIsFixedBundle()) {
            $bundleOptions['bundle_option'] = $this->getBundleOptions($product);
            $subject->getRequest()->setParams(array_merge($requestParams, $bundleOptions));
        }
        return [];
    }

    /**
     * get all the selection products used in bundle product
     * @param $product
     * @return mixed
     */
    private function getBundleOptions(Product $product)
    {
        $selectionCollection = $product->getTypeInstance()
            ->getSelectionsCollection(
                $product->getTypeInstance()->getOptionsIds($product),
                $product
            );
        $bundleOptions = [];
        foreach ($selectionCollection as $selection) {
            $bundleOptions[$selection->getOptionId()][$selection->getProductId()] = $selection->getSelectionId();
        }
        return $bundleOptions;
    }
}

A thing to note, the usage of ->load() is deprecated and should be replaced by using the product resource model.
Parts of this module was created using mage2gen, thanks to @Devendra Gupta for the getBundleOptions() method.

1
  • Doesn't work for me - Magento 2.3.2 Commented Feb 24, 2021 at 19:20
0

Hi you can try like below.

$product = $this->productRepository->getById("29");
$magento = array(21=>"1",22 => "2", 23 => "3");
$par = array('product' => $product->getId(),
             'bundle_options' => array(  1 => $magento),
             'qty' => $qty);
$this->cart->addProduct($_product,$par);
$this->cart->save();

$magento parameters 21,22,23 are child product ids

$par should be below screenshot.

enter image description here

And finally Bundle product should configure the like below screenshot other wise it won't work.

enter image description here

Now run the above code it will add the bundle product to cart.

Feel free to ask if you have any queries.

1
  • Isn't it 'bundle_option' ? You write 'bundle_options'
    – Mr.K
    Commented Aug 7, 2017 at 13:28
0

I have implemented in the following way,

  1. i have add to cart url like this:

    $cartHelper = $this->helper('Magento\Checkout\Helper\Cart');
    $addToCartUrl = $cartHelper->getAddUrl($product);
    
  2. If the the product type is bundle, then get the bundle options as magento requires to add it to cart.

    $productBundleOptions = $product->getProductOptions()['info_buyRequest'];

  3. then add a form with hidden values of bundle options in phtml file like this :

     <form data-role="tocart-form" action="<?php echo $addToCartUrl; ?>" method="post">
                    <?php echo $block->getBlockHtml('formkey')?>
                    <div class="btn">
                        <button type="submit" title="Add to Cart" class="action tocart primary">
                            <span>Add to Cart</span>
                        </button>
                    </div>
                    <?php
                        $bundleOptionArray = $productBundleOptions['bundle_option'];
                        foreach ($bundleOptionArray as $bundleOptionArrayKey => $bundleOptionArrayValue) { ?>
                            <input type="hidden" class="bundle-option-<?= $bundleOptionArrayKey ?>  product bundle option" name="bundle_option[<?= $bundleOptionArrayKey ?>]" value="<?= $bundleOptionArrayValue ?>" id="bundle-option-<?= $bundleOptionArrayKey."-".$bundleOptionArrayValue ?>" checked="checked" aria-required="true">
                        <?php } ?>
                </form>
    
1
  • Hi Use this code but it adds only one item of bundle product in cart. please can you give me the solution. @TS Guhan Commented Sep 9, 2020 at 11:19
-1

Please find below code I have used for add to cart bundle product programmatically.

The $this->_product property is an object of \Magento\Catalog\Model\Product

The $this->cartManagementInterface property is an object of \Magento\Quote\Api\CartManagementInterface

The $this->cartRepositoryInterface property is an object of \Magento\Quote\Api\CartRepositoryInterface

$cartId = $this->cartManagementInterface->createEmptyCart(); //Create empty cart

$quote = $this->cartRepositoryInterface->get($cartId);

$qty = 2;

$items = $orderData->getAllItems();

foreach ($items as $innerItem) {

    if ($innerItem->getProductType() == 'bundle' ){
            $product = $this->_product->load($innerItem->getProductId());
            $buyRequest = $innerItem->getProductOptionByCode('info_buyRequest');
            $buyRequest = new \Magento\Framework\DataObject($buyRequest);
            $buyRequest->setQty($qty);
            $quote->addProduct($product, $buyRequest);
        }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.