How to add a custom button to minicart in Magento 2

How to add a custom button to minicart in Magento 2

To create a custom button inside minicart we need to first take a look inside vendor/module-checkout/view/frontend/web/template/minicart/content.html template file:

<!--
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
-->
<div class="block-title">
    <strong>
        <span class="text" translate="'My Cart'"></span>
        <span
            class="qty empty"
            text="getCartParam('summary_count')"
            data-bind="css: { empty: !!getCartParam('summary_count') == false },
                       attr: { title: $t('Items in Cart') }">
        </span>
    </strong>
</div>

<div class="block-content">
    <button type="button"
            id="btn-minicart-close"
            class="action close"
            data-action="close"
            data-bind="
                attr: {
                    title: $t('Close')
                },
                click: closeMinicart()
            ">
        <span translate="'Close'"></span>
    </button>

    <if args="getCartParam('summary_count')">
        <div class="items-total">
            <span class="count" if="maxItemsToDisplay < getCartLineItemsCount()" text="maxItemsToDisplay"></span>
            <translate args="'of'" if="maxItemsToDisplay < getCartLineItemsCount()"></translate>
            <span class="count" text="getCartParam('summary_count')"></span>
                <!-- ko if: (getCartParam('summary_count') > 1) -->
                    <span translate="'Items in Cart'"></span>
                <!--/ko-->
                <!-- ko if: (getCartParam('summary_count') === 1) -->
                    <span translate="'Item in Cart'"></span>
                <!--/ko-->
        </div>

        <each args="getRegion('subtotalContainer')" render=""></each>
        <each args="getRegion('extraInfo')" render=""></each>

        <div class="actions" if="getCartParam('possible_onepage_checkout')">
            <div class="primary">
                <button
                        id="top-cart-btn-checkout"
                        type="button"
                        class="action primary checkout"
                        data-action="close"
                        data-bind="
                            attr: {
                                title: $t('Proceed to Checkout')
                            },
                            click: closeMinicart()
                        "
                        translate="'Proceed to Checkout'">
                </button>
                <div data-bind="html: getCartParamUnsanitizedHtml('extra_actions')"></div>
            </div>
        </div>
    </if>

    <if args="getCartParam('summary_count')">
        <strong class="subtitle" translate="'Recently added item(s)'"></strong>
        <div data-action="scroll" class="minicart-items-wrapper">
            <ol id="mini-cart" class="minicart-items" data-bind="foreach: { data: getCartItems(), as: 'item' }">
                <each args="$parent.getRegion($parent.getItemRenderer(item.product_type))"
                      render="{name: getTemplate(), data: item, afterRender: function() {$parents[1].initSidebar()}}"></each>
            </ol>
        </div>
    </if>

    <ifnot args="getCartParam('summary_count')">
        <strong class="subtitle empty"
                translate="'You have no items in your shopping cart.'"></strong>
        <if args="getCartParam('cart_empty_message')">
            <p class="minicart empty text" text="getCartParam('cart_empty_message')"></p>
            <div class="actions">
                <div class="secondary">
                    <a class="action viewcart" data-bind="attr: {href: shoppingCartUrl}">
                        <span translate="'View and Edit Cart'"></span>
                    </a>
                </div>
            </div>
        </if>
    </ifnot>

    <div class="actions" if="getCartParam('summary_count')">
        <div class="secondary">
            <a class="action viewcart" data-bind="attr: {href: shoppingCartUrl}">
                <span translate="'View and Edit Cart'"></span>
            </a>
        </div>
    </div>

    <div id="minicart-widgets" class="minicart-widgets" if="regionHasElements('promotion')">
        <each args="getRegion('promotion')" render=""></each>
    </div>
</div>
<each args="getRegion('sign-in-popup')" render=""></each>

So according to the template file there can be 2 approaches:

  1. Create a custom template file for extra-info renderer and then pass a custom component.
  2. Override content.html template file and push html changes inside

1. Pass custom component to template:

Create default.xml file:

Know/Module/view/frontend/layout/default.xml

<?xml version="1.0" encoding="UTF-8" ?>

<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceBlock name="minicart">
            <arguments>
                <argument name="jsLayout" xsi:type="array">
                    <item name="components" xsi:type="array">
                        <item name="minicart_content" xsi:type="array">
                            <item name="children" xsi:type="array">
                                <item name="extra_info" xsi:type="array">
                                    <item name="config" xsi:type="array">
                                        <item name="template" xsi:type="string">Know_Module/extra-info</item>
                                    </item>
                                    <item name="children" xsi:type="array">
                                        <item name="extra_info_btn" xsi:type="array">
                                            <item name="component" xsi:type="string">Know_Module/js/custom-button</item>
                                            <item name="displayArea" xsi:type="string">extraInfoBtn</item>
                                        </item>
                                    </item>
                                </item>
                            </item>
                        </item>
                    </item>
                </argument>
            </arguments>
        </referenceBlock>
    </body>
</page>

Now create extra-info template file:

Know/Module/view/frontend/web/template/extra-info.html

<each args="getRegion('extraInfoBtn')" render=""></each>

Then create custom-button component file:

Know/Module/view/frontend/web/js/custom-button.js

define([
    'uiComponent',
    'ko'
], function (Component, ko) {
        'use strict';

        return Component.extend({
            defaults: {
                template: 'Know_Module/custom-button'
            },

            btnContent: ko.observable(''),

            initialize: function () {
                this._super();
                this.fetchButtonContent();
            },

            fetchButtonContent: function () {
                let button = document.createElement('button');
                button.className = 'action';
                button.classList.add('primary');
                button.textContent = 'External button';
                this.btnContent(button.outerHTML);
            }
        });
});

Next create the component template file:

Know/Module/view/frontend/web/template/custom-button.html

<div data-bind="html: btnContent()"></div>

Flush the cache and clear the static or generated content:

php bin/magento c:c

rm -r generated/* var/cache/* var/view_preprocessed/* pub/static/*

The output to the above will look like the screenshot below:

minicart-custom-button-extra-info

2. Override content.html template file:

Modify the default.xml layout file and make following changes:

Know/Module/view/frontend/layout/default.xml

<?xml version="1.0" encoding="UTF-8" ?>

<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceBlock name="minicart">
            <arguments>
                <argument name="jsLayout" xsi:type="array">
                    <item name="components" xsi:type="array">
                        <item name="minicart_content" xsi:type="array">
                            <item name="config" xsi:type="array">
                                <item name="template" xsi:type="string">Know_Module/minicart/content</item>
                            </item>
                            <item name="children" xsi:type="array">
                                <item name="extra_info_btn" xsi:type="array">
                                    <item name="component" xsi:type="string">Know_Module/js/custom-button</item>
                                    <item name="displayArea" xsi:type="string">extraInfoBtn</item>
                                </item>
                            </item>
                        </item>
                    </item>
                </argument>
            </arguments>
        </referenceBlock>
    </body>
</page>

Now create content.html template file:

Know/Module/view/frontend/web/template/minicart/content.html

<!--
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
-->
<div class="block-title">
    <strong>
        <span class="text" translate="'My Cart'"></span>
        <span
            class="qty empty"
            text="getCartParam('summary_count')"
            data-bind="css: { empty: !!getCartParam('summary_count') == false },
                       attr: { title: $t('Items in Cart') }">
        </span>
    </strong>
</div>

<div class="block-content">
    <button type="button"
            id="btn-minicart-close"
            class="action close"
            data-action="close"
            data-bind="
                attr: {
                    title: $t('Close')
                },
                click: closeMinicart()
            ">
        <span translate="'Close'"></span>
    </button>

    <if args="getCartParam('summary_count')">
        <div class="items-total">
            <span class="count" if="maxItemsToDisplay < getCartLineItemsCount()" text="maxItemsToDisplay"></span>
            <translate args="'of'" if="maxItemsToDisplay < getCartLineItemsCount()"></translate>
            <span class="count" text="getCartParam('summary_count')"></span>
            <!-- ko if: (getCartParam('summary_count') > 1) -->
            <span translate="'Items in Cart'"></span>
            <!--/ko-->
            <!-- ko if: (getCartParam('summary_count') === 1) -->
            <span translate="'Item in Cart'"></span>
            <!--/ko-->
        </div>

        <each args="getRegion('subtotalContainer')" render=""></each>
        <each args="getRegion('extraInfo')" render=""></each>

        <div class="actions" if="getCartParam('possible_onepage_checkout')">
            <div class="primary">
                <button
                    id="top-cart-btn-checkout"
                    type="button"
                    class="action primary checkout"
                    data-action="close"
                    data-bind="
                            attr: {
                                title: $t('Proceed to Checkout')
                            },
                            click: closeMinicart()
                        "
                    translate="'Proceed to Checkout'">
                </button>
                <div data-bind="html: getCartParamUnsanitizedHtml('extra_actions')"></div>
            </div>
        </div>
    </if>

    <if args="getCartParam('summary_count')">
        <strong class="subtitle" translate="'Recently added item(s)'"></strong>
        <div data-action="scroll" class="minicart-items-wrapper">
            <ol id="mini-cart" class="minicart-items" data-bind="foreach: { data: getCartItems(), as: 'item' }">
                <each args="$parent.getRegion($parent.getItemRenderer(item.product_type))"
                      render="{name: getTemplate(), data: item, afterRender: function() {$parents[1].initSidebar()}}"></each>
            </ol>
        </div>
    </if>

    <ifnot args="getCartParam('summary_count')">
        <strong class="subtitle empty"
                translate="'You have no items in your shopping cart.'"></strong>
        <if args="getCartParam('cart_empty_message')">
            <p class="minicart empty text" text="getCartParam('cart_empty_message')"></p>
            <div class="actions">
                <div class="secondary">
                    <a class="action viewcart" data-bind="attr: {href: shoppingCartUrl}">
                        <span translate="'View and Edit Cart'"></span>
                    </a>
                </div>
            </div>
        </if>
    </ifnot>

    <div class="actions" if="getCartParam('summary_count')">
        <div class="secondary">
            <a class="action viewcart" data-bind="attr: {href: shoppingCartUrl}">
                <span translate="'View and Edit Cart'"></span>
            </a>
        </div>
    </div>

    <div id="minicart-widgets" class="minicart-widgets" if="regionHasElements('promotion')">
        <each args="getRegion('promotion')" render=""></each>
    </div>

    <div id="custom-button">
        <each args="getRegion('extraInfoBtn')" render=""></each>
    </div>
</div>
<each args="getRegion('sign-in-popup')" render=""></each>

Flush the cache and clear the static or generated content:

php bin/magento c:c

rm -r generated/* var/cache/* var/view_preprocessed/* pub/static/*

Now the output will look like the screenshot below:

minicart-custom-button-override-template

That’s all. Thank you for reading the post.

Leave a Reply

Your email address will not be published. Required fields are marked *