How to change product image in cart and minicart in Magento2

Magento2 has a new, modern tech stack. One of the newest tools is knockout.js library, and chances are that you’ll find yourself stucked with it as soon as you start customizing checkout components.

In one of my active projects, we allow customers to design their own product. It’s basically a simple product with custom options, where every option has its own color. Once they add their customized version to the cart, we bundle images for choosen options into a final product image. This is what we want to display in minicart/cart page, and not the default product image.

I spent literally a day trying to figure out how to do it. So let’s see the most important part of the solution I came up with. I have created a separate extension for this, so I suggest you to do the same.

Minicart

Before we start off, there’s one very important note for you: minicart in Magento2 is heavily cached. This makes it harder to understand what PHP class is responsible for preparing data for the frontend. It is Magento\Checkout\CustomerData\DefaultItem::doGetItemData(). However, this method is protected, so we can’t use plugins on it. Instead, since it extends from Magento\Checkout\CustomerData\AbstractItem, it’s a perfect case to modify its getItemData() function, which looks like this:

public function getItemData(Item $item)
{
    $this->item = $item;
    return \array_merge(
        ['product_type' => $item->getProductType()],
        $this->doGetItemData()
    );
}

First, create a etc/frontend/di.xml in your extension:

<?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\Checkout\CustomerData\AbstractItem">
        <plugin name="Vendor_Module::Minicart_Image_Changer" type="Vendor\Module\Plugin\Minicart\Image" sortOrder="1"/>
    </type>
</config>

Make sure to replace Vendor and Module with your real names. Then, add a file Vendor/Module/Plugin/Minicart/Image.php with the following code:

<?php

namespace Vendor\Module\Plugin\Minicart;

class Image
{
	public function aroundGetItemData($subject, $proceed, $item)
	{
		$result = $proceed($item);
		if(CHECK_IF_YOU_NEED_TO_REPLACE_IMAGE) {
			$result['product_image']['src'] = YOUR_NEW_IMAGE;
		}
		return $result;
	}
}

This is very simplified. We’re using around hook, that will call the original method, then check if we need to replace the image, because we don’t necessarily do it for all products (in my case, it’s just for a few of them), and if so – we’ll assign a new image to $result[‘product_image’][‘src’].

Cart

Of course, the same thing is needed on the cart page. Modify di.xml file that we created for minicart, and just add the following:

<type name="Magento\Checkout\Block\Cart\Item\Renderer">
    <plugin name="Vendor_Module::Cart_Image_Changer" type="Vendor\Module\Plugin\Cart\Image" sortOrder="1"/>
</type>

We will alter Magento\Checkout\Block\Cart\Item\Renderer::getImage() with after plugin. So, create a file Vendor\Module\Plugin\Cart\Image.php like this:

<?php

namespace Vendor\Module\Plugin\Cart;

class Image
{
	public function afterGetImage($item, $result)
	{
		if(YOUR_CONDITION) {
			$result->setImageUrl( YOUR_IMAGE_URL );
		}
		return $result;
	}
}

Since you have access to $item, you’re able to perform your checks after the original method is called, and based on your business rules – change the item image.

Showcase

For the end, this is how it looks on the frontend:

magento2-minicart-change-image

Minicart – First product has a customized image, while the second one uses default product image

magento2-cart-change-image

Cart – First product uses default product image, while the second has a customized image

Milan Stojanov is a certified Magento developer and Tuts+ author on Magento Fundamentals premium course. He likes to read and write about web development.

  • Jose Reyes

    Thank you so much, your example got me on the right path to displaying custom attributes on the minicart.