Programmatically Get Cross-Sell Items On Cart Page In Magento 2

by StackCamp Team 64 views

In Magento 2, cross-selling is a powerful technique to encourage customers to purchase related products, thereby increasing the average order value. Displaying cross-sell items on the cart page is a strategic way to remind customers of complementary products they might need or want, enhancing their shopping experience and boosting sales. This article delves into how to programmatically retrieve and display cross-sell products on the cart page in Magento 2.

Understanding Cross-Selling in Magento 2

Cross-selling involves recommending products that complement the items already in the customer's cart. These recommendations are typically based on product relationships, purchase history, or other predefined criteria. In Magento 2, cross-sell products are usually displayed on the cart page, encouraging customers to add more items before proceeding to checkout. By strategically placing these suggestions, you can significantly influence customer purchasing decisions and drive revenue growth.

Why Programmatically Access Cross-Sell Items?

While Magento 2 provides built-in functionality to manage cross-sell products, accessing them programmatically offers several advantages:

  • Customization: Programmatic access allows for greater flexibility in how and where cross-sell items are displayed. You can tailor the presentation to match your store's design and user experience.
  • Advanced Logic: You can implement custom logic to determine which cross-sell products to display, based on factors such as customer attributes, cart contents, or even real-time inventory levels.
  • Integration: Programmatic access enables seamless integration with other modules or third-party services, allowing for a more cohesive and personalized shopping experience.

Key Steps to Programmatically Get Cross-Sell Items

To retrieve cross-sell items programmatically in Magento 2, you typically need to perform the following steps:

  1. Create a Block: Develop a custom block in Magento 2 that will handle the logic for fetching and preparing the cross-sell products.
  2. Inject Dependencies: Inject the necessary dependencies, such as the Magento\Checkout\Model\Cart and Magento\Catalog\Model\Product classes, into your block.
  3. Retrieve Cart Items: Get the current cart items using the Magento\Checkout\Model\Cart model.
  4. Get Cross-Sell Products: For each item in the cart, load the product and retrieve its associated cross-sell products.
  5. Prepare Data: Prepare the data for display, such as product names, images, and URLs.
  6. Display in Template: Render the cross-sell products in a template file associated with your block.

Implementing the Solution

Let's walk through a practical example of how to implement this in Magento 2. We'll start by creating a custom block, injecting dependencies, and then retrieving and displaying the cross-sell products.

Step 1: Create a Custom Block

First, you need to create a custom block that will handle the logic for fetching and displaying cross-sell products. Create a file at app/code/YourVendor/YourModule/Block/Cart/Crosssell.php with the following content:

<?php

namespace YourVendor\YourModule\Block\Cart;

use Magento\Catalog\Block\Product\AbstractProduct;
use Magento\Checkout\Model\Cart as CheckoutCart;
use Magento\Catalog\Model\Product;
use Magento\Catalog\Model\Product\Visibility;
use Magento\Checkout\Helper\Cart as CartHelper;
use Magento\Framework\View\LayoutInterface;

class Crosssell extends AbstractProduct
{
    protected $_checkoutCart;
    protected $_productVisibility;
    protected $_cartHelper;
    protected $_itemCollFactory;

    public function __construct(
        \Magento\Catalog\Block\Product\Context $context,
        CheckoutCart $checkoutCart,
        Visibility $productVisibility,
        CartHelper $cartHelper,
        \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $itemCollFactory,
        array $data = []
    ) {
        $this->_checkoutCart = $checkoutCart;
        $this->_productVisibility = $productVisibility;
        $this->_cartHelper = $cartHelper;
        $this->_itemCollFactory = $itemCollFactory;
        parent::__construct($context, $data);
    }

    public function getCrosssellItems()
    {
        $items = $this->_checkoutCart->getQuote()->getAllVisibleItems();
        $productIds = [];
        foreach ($items as $item) {
            $productIds[] = $item->getProductId();
        }

        if (empty($productIds)) {
            return [];
        }

        $collection = $this->_itemCollFactory->create()
            ->addAttributeToSelect('*')
            ->addAttributeToFilter('entity_id', ['nin' => $productIds])
            ->addAttributeToFilter('visibility', $this->_productVisibility->getVisibleInCatalogIds())
            ->addAttributeToFilter('status', 1);

        $collection->getSelect()->order('rand()');
        $collection->setPageSize(4);

        return $collection;
    }

    public function getItemCount()
    {
        return $this->getCrosssellItems()->getSize();
    }

    public function getAddToCartUrl(Product $product)
    {
        return $this->_cartHelper->getAddUrl($product);
    }
}

This block class, Crosssell, is responsible for retrieving cross-sell products. It injects several dependencies:

  • Magento\Checkout\Model\Cart: To access the current cart.
  • Magento\Catalog\Model\Product\Visibility: To filter products based on visibility.
  • Magento\Checkout\Helper\Cart: To get the add-to-cart URL.
  • Magento\Catalog\Model\ResourceModel\Product\CollectionFactory: To create a product collection.

The getCrosssellItems method fetches products that are not already in the cart and are visible in the catalog. It retrieves a random set of 4 products to display as cross-sells.

Step 2: Declare the Block in Layout XML

Next, you need to declare the block in your layout XML file so that it can be rendered on the cart page. Create or modify the checkout_cart_index.xml file in your module's view/frontend/layout directory (app/code/YourVendor/YourModule/view/frontend/layout/checkout_cart_index.xml) with the following content:

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceContainer name="content">
            <block class="YourVendor\YourModule\Block\Cart\Crosssell" name="checkout.cart.crosssell" template="YourVendor_YourModule::cart/crosssell.phtml" before="checkout.cart.totals"/>
        </referenceContainer>
    </body>
</page>

This XML declares a block with the class YourVendor\YourModule\Block\Cart\Crosssell and assigns it the name checkout.cart.crosssell. The template YourVendor_YourModule::cart/crosssell.phtml will be used to render the block, and it is positioned before the cart totals.

Step 3: Create the Template File

Now, create the template file app/code/YourVendor/YourModule/view/frontend/templates/cart/crosssell.phtml with the following content:

<?php
/** @var \YourVendor\YourModule\Block\Cart\Crosssell $block */
?>
<?php $items = $block->getCrosssellItems(); ?>
<?php if ($items && $items->getSize()): ?>
    <div class="block crosssell">
        <div class="title">
            <strong><?= $block->escapeHtml(__('You may also be interested in')) ?></strong>
        </div>
        <div class="content products wrapper grid products-grid">
            <ol class="products list items product-items">
                <?php foreach ($items as $item): ?>
                    <li class="item product product-item">
                        <div class="product-item-info">
                            <a href="<?= $block->escapeUrl($item->getProductUrl()) ?>" class="product photo product-item-photo">
                                <?php $productImage = $block->getImage($item, 'crosssell_products_list'); ?>
                                <img src="<?= $block->escapeUrl($productImage->getImageUrl()) ?>" alt="<?= $block->escapeHtml($item->getName()) ?>"/>
                            </a>
                            <div class="product details product-item-details">
                                <strong class="product name product-item-name">
                                    <a class="product-item-link" href="<?= $block->escapeUrl($item->getProductUrl()) ?>">
                                        <?= $block->escapeHtml($item->getName()) ?>
                                    </a>
                                </strong>
                                <?= $block->getProductPrice($item) ?>
                                <div class="product actions product-item-actions">
                                    <div class="actions-primary">
                                        <form action="<?= $block->escapeUrl($block->getAddToCartUrl($item)) ?>" method="post">
                                            <input type="hidden" name="product" value="<?= $block->escapeHtml($item->getEntityId()) ?>" />
                                            <?= $block->getBlockHtml('formkey') ?>
                                            <button type="submit" title="<?= $block->escapeHtml(__('Add to Cart')) ?>" class="action tocart primary">
                                                <span><?= $block->escapeHtml(__('Add to Cart')) ?></span>
                                            </button>
                                        </form>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </li>
                <?php endforeach; ?>
            </ol>
        </div>
    </div>
<?php endif; ?>

This template iterates through the cross-sell items retrieved by the block and displays them in a grid format. It includes the product image, name, price, and an add-to-cart button. The template also uses Magento's escaping functions to ensure that the output is secure.

Step 4: Enable the Module

Finally, enable your module by running the following commands in the Magento root directory:

php bin/magento module:enable YourVendor_YourModule
php bin/magento setup:upgrade
php bin/magento setup:di:compile
php bin/magento setup:static-content:deploy -f
php bin/magento cache:flush

These commands enable the module, upgrade the database schema, compile the dependency injection configuration, deploy static content, and flush the cache.

Conclusion

Cross-selling is a vital strategy for boosting sales in Magento 2. By programmatically accessing cross-sell items, you gain the flexibility to customize their display and implement advanced logic for product recommendations. This article provided a step-by-step guide on how to retrieve and display cross-sell products on the cart page, enhancing the shopping experience and driving revenue growth. By implementing these techniques, you can create a more engaging and profitable e-commerce environment for your customers. Remember to tailor the implementation to your specific needs and design to ensure a seamless and effective cross-selling strategy.