How to add an extra product attribute to checkout summary box

Would you like to display another product attribute or a custom one in the checkout summary? Let's see together how you can do that!

In our example, we will display below the product's name, the product's manufacturer. First of all, we have to include the manufacturer attribute in the quote item as in not included by default. So to achieve that we have to create a file under app/code/Armmage/ManufacturerAttriute/etc/catalog_attributes.xml and we add the following code.


<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Catalog:etc/catalog_attributes.xsd">
    <group name="quote_item">
        <attribute name="manufacturer"/>
    </group>
</config>

As is well known, Magento 2 checkout is built up from a series of Knockout JS components which are then rendered using the Knockout JS templating system. Magento 2 defines each one of these components and their parent / child relationship in a large XML file which can be extended or overridden in your own theme or module. For Magento 2 checkout this large XML file can be found under

vendor/magento/module-checkout/view/frontend/layout/checkout_index_index.xmlThe definition of component item that is responsible for the summary item details in checkout is the following.<item name="component" xsi:type="string">Armmage_ManufacturerAttriute/js/view/summary/item/details</item>So override this component we will have to create a new checkout_index_index.xml in our module, under
app/code/Armmage/ManufacturerAttriute/view/frontend/layout/checkout_index_index.xml

adding the following code which defines only the path to this component that we need to override.

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceBlock name="checkout.root">
            <arguments>
                <argument name="jsLayout" xsi:type="array">
                    <item name="components" xsi:type="array">
                        <item name="checkout" xsi:type="array">
                            <item name="children" xsi:type="array">
                                <item name="sidebar" xsi:type="array">
                                    <item name="children" xsi:type="array">
                                        <item name="summary" xsi:type="array">
                                            <item name="children" xsi:type="array">
                                                <item name="cart_items" xsi:type="array">
                                                    <item name="children" xsi:type="array">
                                                        <item name="details" xsi:type="array">
                                                            <item name="component"
                                                                  xsi:type="string">Armmage_ManufacturerAttriute/js/view/summary/item/details</item>
                                                        </item>
                                                    </item>
                                                </item>
                                            </item>
                                        </item>
                                    </item>
                                </item>
                            </item>
                        </item>
                    </item>
                </argument>
            </arguments>
        </referenceBlock>
    </body>
</page>

As we can see on the code below the value of the component item is a path to JS file where also the template file for this component is declared. As we need to override this template file, this value has path to a JS file in our module. So you can easily copy the 

vendor/magento/module-checkout/view/frontend/web/js/view/summary/item/details.js

under

app/code/Armmage/ManufacturerAttriute/view/frontend/web/js/view/summary/item/details.js

and replace the file's code with the code below.

*jshint browser:true jquery:true*/
/*global alert*/
define(
    [
        'uiComponent'
    ],
    function (Component) {
        "use strict";
        var quoteItemData = window.checkoutConfig.quoteItemData;
        return Component.extend({
            defaults: {
                template: 'Armmage_ManufacturerAttriute/summary/item/details'
            },
            quoteItemData: quoteItemData,
            getValue: function(quoteItem) {
                return quoteItem.name;
            },
            getManufacturer: function(quoteItem) {
                var item = this.getItem(quoteItem.item_id);
                return item.manufacturer;
            },
            getItem: function(item_id) {
                var itemElement = null;
                _.each(this.quoteItemData, function(element, index) {
                    if (element.item_id == item_id) {
                        itemElement = element;
                    }
                });
                return itemElement;
            }
        });
    }
);

Afterwards, create a html file and name it details.html under

app/code/Armmage/ManufacturerAttriute/view/frontend/web/template/summary/item/details.html

<!-- ko foreach: getRegion('before_details') -->
    <!-- ko template: getTemplate() --><!-- /ko -->
<!-- /ko -->
<div class="product-item-details">

    <div class="product-item-inner">
        <div class="product-item-name-block">
            <strong class="product-item-name" data-bind="text: $parent.name"></strong>
            <!-- ko if: (getManufacturer($parent))-->
                <strong class="product-item-manufacturer" data-bind="text: getManufacturer($parent)"></strong>
            <!-- /ko -->
            <div class="details-qty">
                <span class="label"><!-- ko i18n: 'Qty' --><!-- /ko --></span>
                <span class="value" data-bind="text: $parent.qty"></span>
            </div>
        </div>

        <!-- ko foreach: getRegion('after_details') -->
            <!-- ko template: getTemplate() --><!-- /ko -->
        <!-- /ko -->
    </div>

    <!-- ko if: (JSON.parse($parent.options).length > 0)-->
    <div class="product options" data-bind="mageInit: {'collapsible':{'openedState': 'active'}}">
        <span data-role="title" class="toggle"><!-- ko i18n: 'View Details' --><!-- /ko --></span>
        <div data-role="content" class="content">
            <strong class="subtitle"><!-- ko i18n: 'Options Details' --><!-- /ko --></strong>
            <dl class="item-options">
                <!--ko foreach: JSON.parse($parent.options)-->
                <dt class="label" data-bind="text: label"></dt>
                    <!-- ko if: ($data.full_view)-->
                    <dd class="values" data-bind="html: full_view"></dd>
                    <!-- /ko -->
                    <!-- ko ifnot: ($data.full_view)-->
                    <dd class="values" data-bind="html: value"></dd>
                    <!-- /ko -->
                <!-- /ko -->
            </dl>
        </div>
    </div>
    <!-- /ko -->
</div>

The only change to the original file, which can be found under

vendor/magento/module-checkout/view/frontend/web/template/summary/item/details.html

is that we added to display the product's manufacturer below the product's name.

The vendor/magento/module-checkout/Model/DefaultConfigProvider.php class is used for retrieving data in checkout. In this class, the function getConfig() is returning an array of the data which is gonna used in different places in checkout. For the checkout, the summary template is the totalsData output array field. As we can see the product's manufacturer data is not included in that array. So we have to extend this function by creating a plugin and add the product's manufacturer to the totalsData. After having a deeper look, we found out that this is gonna work only in the shipping step, as in the payment step, the total data array is set again only with Magento's default quote total values. So to display the product's manufacturer in the checkout order summary in both steps we need to add the product's manufacturer into the quoteItemData array.

Create a di.xml file to declare the plugin.

<?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\Model\DefaultConfigProvider">
        <plugin name="checkout-summary-product-attribute" type="Armmage\ManufacturerAttriute\Plugin\Checkout\Model\DefaultConfigProvider" />
    </type>
</config>

Create a class under /app/code/Armmage/ManufacturerAttriute/Plugin/Checkout/Model/DefaultConfigProvider.php with an afterGetConfig() function, where we will add our logic of adding the product's manufacturer information.

<?php
namespace Armmage\ManufacturerAttriute\Plugin\Checkout\Model;

use Magento\Checkout\Model\Session as CheckoutSession;

class DefaultConfigProvider
{
    /**
     * @var CheckoutSession
     */
    protected $checkoutSession;

    /**
     * Constructor
     *
     * @param CheckoutSession $checkoutSession
     */
    public function __construct(
        CheckoutSession $checkoutSession
    ) {
        $this->checkoutSession = $checkoutSession;
    }

    public function afterGetConfig(
        \Magento\Checkout\Model\DefaultConfigProvider $subject,
        array $result
    ) {
        $items = $result['totalsData']['items'];
        foreach ($items as $index => $item) {
            $quoteItem = $this->checkoutSession->getQuote()->getItemById($item['item_id']);
            $result['quoteItemData'][$index]['manufacturer'] = $quoteItem->getProduct()->getAttributeText('manufacturer');
        }
        return $result;
    }
}

So now the Attribute should be visible.

If you have any questions, just write in comments.

source



Ready to elevate your e-commerce business?

Discuss your business objectives with us. Get in touch today to explore ways we can assist in reaching them.

Copyright © 2021-2024 ArmMage LLC. All rights reserved.