Having multiple product types listed in your store catalog helps to make the customer experience in your store more diverse. One of the many options you can provide is a bundle product. Basically, it consists of simple and virtual products that can be customized according to the client's preferences. Customers can choose the size, weight, color, etc. to get the very product they like.

Although, you can create bundle products from the admin panel creating bundle products programmatically is much faster. So in this article, you'll learn how to do that.

Use the below method to create a bundle product in Magento 2 programmatically.

<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
use Magento\Framework\App\Bootstrap;
require __DIR__ . '/app/bootstrap.php';
$bootstrap = Bootstrap::create(BP, $_SERVER);
$objectManager = $bootstrap->getObjectManager();
$state = $objectManager->get(\Magento\Framework\App\State::class);
$state->setAreaCode('frontend');
try {
$bundleProduct = $objectManager->create(\Magento\Catalog\Api\Data\ProductInterface::class);
$bundleProduct
->setStoreId(0)//you can set data in store scope
->setWebsiteIds(array(1))//website ID the product is assigned to, as an array
->setAttributeSetId(4)//ID of a attribute set named 'default'
->setTypeId('bundle')//product type
->setCreatedAt(strtotime('now'))//product creation time
//->setUpdatedAt(strtotime('now')) //product update time
->setSkuType(0)//SKU type (0 - dynamic, 1 - fixed)
->setSku('bundle')//SKU
->setName('Test Bundle Product')//product name
->setWeightType(0)//weight type (0 - dynamic, 1 - fixed)
//->setWeight(4.0000)
->setShipmentType(0)//shipment type (0 - together, 1 - separately)
->setStatus(1)//product status (1 - enabled, 2 - disabled)
->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH)//catalog and search visibility
->setManufacturer(83)//manufacturer id
->setColor(24)//color id
->setNewsFromDate('01/01/2020')//product set as new from
->setNewsToDate('12/31/2020')//product set as new to
->setCountryOfManufacture('IN')//country of manufacture (2-letter country code)
->setPriceType(0)//price type (0 - dynamic, 1 - fixed)
->setPriceView(0)//price view (0 - price range, 1 - as low as)
->setSpecialPrice(50.00)//special price in form 11.22 special price in percentage of original price
->setSpecialFromDate('01/01/2020')//special price from (MM-DD-YYYY)
->setSpecialToDate('12/31/2020')//special price to (MM-DD-YYYY)
//only available if price type is 'fixed'/
//->setPrice(11.22) //price, works only if price type is fixed
//->setCost(22.33) //price in form 11.22
//->setMsrpEnabled(1) //enable MAP
//->setMsrpDisplayActualPriceType(1) //display actual price (1 - on gesture, 2 - in cart, 3 - before order confirmation, 4 - use config)
//->setMsrp(99.99) //Manufacturer's Suggested Retail Price
//->setTaxClassId(4) //tax class (0 - none, 1 - default, 2 - taxable, 4 - shipping)
//only available if price type is 'fixed'/
->setMetaTitle('test meta title')
->setMetaKeyword('test meta keyword')
->setMetaDescription('test meta description')
->setDescription('This is a long description')
->setShortDescription('This is a short description')
->setMediaGallery(array('images' => array(), 'values' => array()))//media gallery initialization
->setStockData(array(
'use_config_manage_stock' => 1, //'Use config settings' checkbox
'manage_stock' => 1, //manage stock
'is_in_stock' => 1, //Stock Availability
)
)
->setCategoryIds(array(4, 10)); //assign product to categories

// Set bundle product items
$bundleProduct->setBundleOptionsData(
[
[
'title' => 'Bundle Test Items 1',
'default_title' => 'Bundle Test Items 2',
'type' => 'select',
'required' => 1,
'delete' => '',
],
[
'title' => 'Bundle Test Items 2',
'default_title' => 'Bundle Test Items 2',
'type' => 'select',
'required' => 1,
'delete' => '',
]
]
)->setBundleSelectionsData(
[
[
['product_id' => 1, 'selection_qty' => 1, 'selection_can_change_qty' => 1, 'delete' => ''],
['product_id' => 3, 'selection_qty' => 1, 'selection_can_change_qty' => 1, 'delete' => ''],
],
[
['product_id' => 2, 'selection_qty' => 1, 'selection_can_change_qty' => 1, 'delete' => ''],
['product_id' => 4, 'selection_qty' => 1, 'selection_can_change_qty' => 1, 'delete' => ''],
],
]
);
if ($bundleProduct->getBundleOptionsData()) {
$options = [];
foreach ($bundleProduct->getBundleOptionsData() as $key => $optionData) {
if (!(bool)$optionData['delete']) {
$option = $objectManager->create(\Magento\Bundle\Api\Data\OptionInterface::class);
$option->setData($optionData);
$option->setSku($bundleProduct->getSku());
$option->setOptionId(null);

$links = [];
$bundleLinks = $bundleProduct->getBundleSelectionsData();

if (!empty($bundleLinks[$key])) {
foreach ($bundleLinks[$key] as $linkData) {
if (!(bool)$linkData['delete']) {

/** @var \Magento\Bundle\Api\Data\LinkInterface $link */
$link = $objectManager->create(\Magento\Bundle\Api\Data\LinkInterface::class);
$link->setData($linkData);
$linkProduct = $objectManager->get(\Magento\Catalog\Api\ProductRepositoryInterface::class)->getById($linkData['product_id']);
$link->setSku($linkProduct->getSku());
$link->setQty($linkData['selection_qty']);

if (isset($linkData['selection_can_change_qty'])) {
$link->setCanChangeQuantity($linkData['selection_can_change_qty']);
}
$links[] = $link;
}
}
$option->setProductLinks($links);
$options[] = $option;
}
}
}

$extension = $bundleProduct->getExtensionAttributes();
$extension->setBundleProductOptions($options);
$bundleProduct->setExtensionAttributes($extension);
}

$bundleProduct->save();
echo 'success';

} catch (\Exception $e) {
$objectManager->get(\Psr\Log\LoggerInterface::class)->info($e->getMessage());
echo $e->getMessage();
}

Was it hard, coders?

If you prefer to create Magento 2 bundle products programmatically — there you go! Feel free to use this solution to optimize the process of creating bundle products in your store.

If you want to dive deeper into the subject, you can also learn how to create grouped product in Magento 2 programmatically.