With Grouped Product in Magento 2, merchants can grab multiple items on a single page that simplifies the customer shopping experience. Each product detail page displays many single products collected by season or theme that you can promote sales for multiple items at the same time.

For example, you sell cooking utensils and you can easily add the tools such as pots, bowls, spoons, etc. into one product page, allowing customers to select which tools they want. Presenting a grouped product can create an incentive for customers to purchase additional items.

Although they are presented as a group, each product in the group is purchased as a separate item. In the shopping cart, each item and the quantity purchased appears a separate line item.

To create a grouped product programmatically, we need a class as follows:

<?php

namespace Vendor\Module\Helper;

use Magento\Catalog\Api\Data\ProductInterface;
use Magento\Catalog\Model\ProductFactory;
use Magento\Catalog\Api\Data\ProductInterfaceFactory;
use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\Catalog\Api\Data\ProductLinkInterfaceFactory;
use Magento\InventoryApi\Api\SourceItemsSaveInterface;
use Magento\InventoryApi\Api\Data\SourceItemInterface;
use Magento\InventoryApi\Api\Data\SourceItemInterfaceFactory;
use Magento\Catalog\Model\Product\Visibility;
use Magento\Catalog\Model\Product\Attribute\Source\Status;

class CreateGroupedProduct
{
	protected $_productFactory;

	protected $_productInterface;

	protected $_productResource;

	protected $_productLink;

	protected $_sourceItemSave;

	protected $_sourceItemFactory;

	/**
 	* CreateGroupedProduct constructor.
 	*
 	* @param ProductFactory $productFactory
 	* @param ProductInterfaceFactory $productInterface
 	* @param ProductRepositoryInterface $productResource
 	* @param ProductLinkInterfaceFactory $productLink
 	* @param SourceItemsSaveInterface $sourceItemsSave
 	* @param SourceItemInterfaceFactory $sourceItemInterfaceFactory
 	*/
	public function __construct(
    	ProductFactory $productFactory,
    	ProductInterfaceFactory $productInterface,
    	ProductRepositoryInterface $productResource,
    	ProductLinkInterfaceFactory $productLink,
    	SourceItemsSaveInterface $sourceItemsSave,
    	SourceItemInterfaceFactory $sourceItemInterfaceFactory
	) {
    	$this->_productFactory	  = $productFactory;
    	$this->_productInterface  = $productInterface;
    	$this->_productResource   = $productResource;
    	$this->_productLink   	  = $productLink;
    	$this->_sourceItemSave	  = $sourceItemsSave;
    	$this->_sourceItemFactory = $sourceItemInterfaceFactory;
	}

	public function execute()
	{
    	//get default product attribute set ID
    	$attributeSetId = $this->_productFactory->create()->getDefaultAttributeSetId();

    	//create simple products and return SKUs for mapping
    	$simpleProductSKUs = $this->createSimpleProducts($attributeSetId);

    	//create grouped product
    	$groupedProduct = $this->createGroupedProduct($attributeSetId);

    	//link simple products to grouped product
    	$this->linkGroupedProduct($groupedProduct, $simpleProductSKUs);
	}
}

Here we’ve defined the dependencies and the 3 steps needed to create a grouped product. $attributeSetId is the default attribute set of products, here it is defined first to simplify the next steps.

1/ Created simple products

In this step, we will create some simple products to associate with a grouped product later. The goal is to return the SKUs of products you want to associate with.

Create function createSimpleProducts:

private function createSimpleProducts($attributeSetId)
{
    	$skus = [];

    	//create product
    	$firstProduct = $this->_productInterface->create()
        	->setTypeId('simple')
        	->setAttributeSetId($attributeSetId)
        	->setName('Simple 1')
        	->setSku('simple_1')
        	->setPrice(10)
        	->setVisibility(Visibility::VISIBILITY_BOTH)
        	->setStatus(Status::STATUS_ENABLED);
    	$this->_productResource->save($firstProduct);

$skus[] = $firstProduct->getSku();

    	$secondProduct = $this->_productInterface->create()
        	->setTypeId('simple')
        	->setAttributeSetId($attributeSetId)
        	->setName('Simple 2')
        	->setSku('simple_2')
        	->setPrice(20)
        	->setVisibility(Visibility::VISIBILITY_BOTH)
        	->setStatus(Status::STATUS_ENABLED);
    	$this->_productResource->save($secondProduct);

    	$skus[] = $secondProduct->getSku();

    	//create stock for simple products
    	foreach ($skus as $sku) {
        	// Update Stock Data
        	$sourceItem = $this->_sourceItemFactory->create();
        	$sourceItem->setSourceCode('default');
        	$sourceItem->setQuantity(100);
        	$sourceItem->setSku($sku);
        	$sourceItem->setStatus(SourceItemInterface::STATUS_IN_STOCK);
        	$sourceItems[] = $sourceItem;
    	}
    	$this->_sourceItemSave->execute($sourceItems);

    	return $skus;
}

2/ Create grouped product

Create function createGroupedProduct:

private function createGroupedProduct($attributeSetId)
{
    	$product = $this->_productInterface->create()
        	->setAttributeSetId($attributeSetId)
        	->setTypeId('grouped')
        	->setName('Grouped Product Sample')
        	->setSku('grouped_sample')
        	->setVisibility(Visibility::VISIBILITY_BOTH)
        	->setStatus(Status::STATUS_ENABLED);
    	$this->_productResource->save($product);

    	return $product;
}

This function returns a product interface.

3/ Link simple products to grouped product

Finally, add function linkGroupedProduct:

private function linkGroupedProduct(ProductInterface $groupedProduct, $skus)
{
    	$position   = 0;
    	$associated = [];
    	foreach ($skus as $sku) {
        	$productLink      	= $this->_productLink->create()->setSku($groupedProduct->getSku())
            	->setLinkType('associated')
            	->setLinkedProductSku($sku)
            	->setLinkedProductType('simple')
            	->setPosition($position);
		//add default qty for included products
        	$productLinkAttribute = $productLink->getExtensionAttributes();
        	$productLinkAttribute->setQty(1);
        	$productLink->setExtensionAttributes($productLinkAttribute);
        	$associated[] = $productLink;
        	$position++;
    	}
    	$groupedProduct->setProductLinks($associated);

	//if stock data is not set, grouped product will show as out of stock
    	$groupedProduct->setStockData(['is_in_stock' => 1]);
    	$this->_productResource->save($groupedProduct);
}

You can find the final code here.

Final result

After following the instructions in this guide, you will have the final result as below:

We hope that our article contains the answers to your problems. If you need further support, please drop us an email at support@magenest.com.