0

Magneto2 How can I create dependent simple products?

First, parent simple product is added to cart & then the second simple product is added to cart.

If first is removed then display an error message.

How can I achieve this functionality?

1 Answer 1

0

So assuming a hard coded product parent-child relationship.

The product with sku="product-a" has a child sku="product-b"

  • When "product-a" is added to cart we want to add "product-b"
  • When "product-a" is removed we display an error message

I used observers for this, hooking into checkout_cart_product_add_after and sales_quote_remove_item.

app/code/StackExchange/DependentProduct/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">
    <event name="checkout_cart_product_add_after">
        <observer name="add_dependent_product_to_cart" instance="StackExchange\DependentProduct\Observer\AddDependentProductToCart" />
    </event>
    <event name="sales_quote_remove_item">
        <observer name="remove_dependent_product_from_cart" instance="StackExchange\DependentProduct\Observer\RemoveDependentProductFromCart" />
    </event>
</config>

app/code/StackExchange/DependentProduct/Observer/AddDependentProductToCart.php

<?php
declare(strict_types=1);

namespace StackExchange\DependentProduct\Observer;

use Magento\Catalog\Model\ProductRepository;
use Magento\Checkout\Model\Session;
use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use Magento\Quote\Api\CartRepositoryInterface;
use Magento\Quote\Model\Quote;

class AddDependentProductToCart implements ObserverInterface
{
    /**
     * @var ProductRepository
     */
    private ProductRepository $productRepository;
    /**
     * @var CartRepositoryInterface
     */
    private CartRepositoryInterface $cartRepository;
    /**
     * @var Session
     */
    private Session $checkoutSession;

    public function __construct(
        Session $checkoutSession,
        ProductRepository $productRepository,
        CartRepositoryInterface $cartRepository
    ) {
        $this->productRepository = $productRepository;
        $this->cartRepository = $cartRepository;
        $this->checkoutSession = $checkoutSession;
    }

    public function execute(Observer $observer)
    {
        /** @var \Magento\Catalog\Model\Product $product */
        $product = $observer->getEvent()->getData('product');

        if ($product->getSku() != "product-a") {
            return;
        }
        /** @var \Magento\Quote\Model\Quote\Item $quoteItem */
        $quoteItem = $observer->getEvent()->getData('quote_item');
        $productB = $this->productRepository->get('product-b');

        $quote = $this->checkoutSession->getQuote();

        $quote->addProduct($productB, (int) $quoteItem->getQty());
    }
}

app/code/StackExchange/DependentProduct/Observer/RemoveDependentProductFromCart.php

<?php
declare(strict_types=1);

namespace StackExchange\DependentProduct\Observer;

use Magento\Catalog\Model\ProductRepository;
use Magento\Checkout\Model\Session;
use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use Magento\Framework\Message\ManagerInterface as MessageManager;
use Magento\Quote\Api\CartRepositoryInterface;

class RemoveDependentProductFromCart implements ObserverInterface
{
    private MessageManager $messageManager;

    public function __construct(
        MessageManager $messageManager
    ) {
        $this->messageManager = $messageManager;
    }

    public function execute(Observer $observer)
    {
        /** @var \Magento\Quote\Model\Quote\Item $quoteItem */
        $quoteItem = $observer->getEvent()->getData('quote_item');

        if ($quoteItem->getSku() != "product-a") {
            return;
        }

        $this->messageManager->addErrorMessage(__('Error message'));
    }

}

You might need to review so that the correct qty are added to cart if a product is added several times. There is also another event checkout_cart_product_update_after you might want to look into. However, the above code shows the basic idea.

Good luck!

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.