How to display order summary in a modal in Magento 2
Today we will discuss about customizing the order summary. We will enhance the appearance of order summary on both cart and checkout pages by displaying it within a modal, rather than keeping it constantly visible.
1. Customizing the cart layout
Begin with creating checkout_cart_index.xml layout file inside your module’s front-end directory.
app/code/Know/OrderSummaryModal/view/frontend/layout/checkout_cart_index.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> <referenceContainer name="content"> <referenceBlock name="checkout.cart"> <referenceContainer name="cart.summary"> <block class="Magento\Framework\View\Element\Template" name="checkout.cart.summary.modal" template="Know_OrderSummaryModal::cart-summary-action.phtml" after="checkout.cart.summary.title"> <arguments> <argument name="jsLayout" xsi:type="array"> <item name="components" xsi:type="array"> <item name="summary-modal-component" xsi:type="array"> <item name="component" xsi:type="string">Know_OrderSummaryModal/js/view/cart/summary-modal</item> </item> </item> </argument> </arguments> </block> </referenceContainer> </referenceBlock> </referenceContainer> </body> </page>
We have created a custom block under the cart summary which takes jsLayout arguments data. Within the jsLayout argument, we’ve also defined a component, which will be used to trigger the modal. We will proceed step by step.
So start with creating a template file cart-summary-action.phtml under templates directory.
app/code/Know/OrderSummaryModal/view/frontend/templates/cart-summary-action.phtml
<?php /** * Shopping Cart Summary Modal template * @var $block \Magento\Framework\View\Element\Template */ ?> <div id="summary-modal" data-bind="scope: 'summary-modal-component'"> <!-- ko template: getTemplate() --><!-- /ko --> <script type="text/x-magento-init"> { "#summary-modal": { "Magento_Ui/js/core/app": <?= /* @noEscape */ $block->getJsLayout() ?> } } </script> </div>
Now create the summary-modal component:
app/code/Know/OrderSummaryModal/view/frontend/web/js/view/cart/summary-modal.js
define([ 'uiComponent' ], function (Component) { 'use strict'; return Component.extend({ defaults: { template: 'Know_OrderSummaryModal/cart/summary-modal' } }); });
Inside the component we have specified a path to its template file. So go ahead and create the template file:
app/code/Know/OrderSummaryModal/view/frontend/web/template/cart/summary-modal.html
<a href="#" data-bind="text: 'View Summary', click: viewTotalsSummary" class="btn btn-primary center-block text-center"></a>
Inside the template we have created an anchor element with click binding specified. Furthermore we need to create the viewTotalsSummay method inside component.
Instead of creating a standalone method we will create mixin for component and push this function inside. We opt for this approach because we require similar functionality for a summary component at checkout page as well. This method allows us to prevent redundant code duplication.
So go ahead and create requriejs-config.js file inside the front-end directory.
app/code/Know/OrderSummaryModal/view/frontend/requirejs-config.js
var config = { config: { mixins: { 'Know_OrderSummaryModal/js/view/cart/summary-modal': { 'Know_OrderSummaryModal/js/view/summary-mixin': true } } } };
Create summary-mixin.js mixin file according to specified path.
app/code/Know/OrderSummaryModal/view/frontend/web/js/view/summary-mixin.js
define([ 'ko', 'jquery', 'Magento_Ui/js/modal/modal' ], function ( ko, $, modal ) { 'use strict'; var mixin = { defaults: { popUp: { element: '.order-summary-modal', options: { 'type': 'popup', 'responsive': true, 'innerScroll': true, 'title': 'Order Summary', 'trigger': 'order-summary-modal', 'buttons': { 'cancel': { 'text': 'Close', 'class': 'action secondary' } } } } }, popUpObj: null, isPopUpVisible: ko.observable(false), getPopUp: function () { if (!this.popUpObj) { let buttons = this.popUp.options.buttons; this.popUp.options.buttons = [{ text: buttons.cancel.text, class: buttons.cancel.class, click: this.onClosePopUp.bind(this) }]; this.popUp.options.closed = this.afterClosePopUp.bind(this); this.popUp.options.modalCloseBtnHandler = this.onClosePopUp.bind(this); this.popUp.options.keyEventHandlers = { escapeKey: this.onClosePopUp.bind(this) }; this.popUpObj = modal(this.popUp.options, $(this.popUp.element)); } return this.popUpObj; }, onClosePopUp: function () { this.getPopUp().closeModal(); return this; }, afterClosePopUp: function () { this.isPopUpVisible(false); return this; }, viewTotalsSummary: function () { this.getPopUp().openModal(); this.isPopUpVisible(true); } }; return function (target) { return target.extend(mixin); } });
In the code above, the order-summary-modal class is crucial. It will contain the summary information that becomes visible when the popup modal is triggered. This implies that we should encompass the entire order summary with an element bearing this class.
So inside the checkout_cart_index.xml layout file we will create a div container with same class order-summary-modal, and subsequently relocate the cart shipping, cart totals and coupon elements into it.
app/code/Know/OrderSummaryModal/view/frontend/layout/checkout_cart_index.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> <referenceContainer name="content"> <referenceBlock name="checkout.cart"> <referenceContainer name="cart.summary"> <block class="Magento\Framework\View\Element\Template" name="checkout.cart.summary.modal" template="Know_OrderSummaryModal::cart-summary-action.phtml" after="checkout.cart.summary.title"> <arguments> <argument name="jsLayout" xsi:type="array"> <item name="components" xsi:type="array"> <item name="summary-modal-component" xsi:type="array"> <item name="component" xsi:type="string">Know_OrderSummaryModal/js/view/cart/summary-modal</item> </item> </item> </argument> </arguments> </block> <container name="cart.summary.modal" label="Cart Summary Modal" htmlTag="div" htmlClass="order-summary-modal" after="-" /> </referenceContainer> </referenceBlock> </referenceContainer> <move element="checkout.cart.shipping" destination="cart.summary.modal" before="-" /> <move element="checkout.cart.totals.container" destination="cart.summary.modal" after="checkout.cart.shipping" /> <move element="checkout.cart.coupon" destination="cart.summary.modal" after="-" /> </body> </page>
Now open the cart-summary-action.phtml template file and hide the order-summary-modal class.
app/code/Know/OrderSummaryModal/view/frontend/templates/cart-summary-action.phtml
... <style> .order-summary-modal { display: none; } </style> ...
The complete code in template file:
<?php /** * Shopping Cart Summary Modal template * @var $block \Magento\Framework\View\Element\Template */ ?> <div id="summary-modal" data-bind="scope: 'summary-modal-component'"> <!-- ko template: getTemplate() --><!-- /ko --> <script type="text/x-magento-init"> { "#summary-modal": { "Magento_Ui/js/core/app": <?= /* @noEscape */ $block->getJsLayout() ?> } } </script> </div> <style> .order-summary-modal { display: none; } </style>
Flush the cache and clear the static content, and then let’s check the output:
Clicking View Summary will display the summary in a modal dialog.
2. Customizing the checkout layout
Next we need to add anchor element and wrap the entire summary content in summary template file. To achieve this we need to customize the summary template file. So go ahead and create checkout_index_index.xml layout file.
app/code/Know/OrderSummaryModal/view/frontend/layout/checkout_index_index.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> <referenceContainer name="content"> <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="config" xsi:type="array"> <item name="template" xsi:type="string">Know_OrderSummaryModal/checkout/summary</item> </item> </item> </item> </item> </item> </item> </item> </argument> </arguments> </referenceBlock> </referenceContainer> </body> </page>
Create the custom summary template file.
app/code/Know/OrderSummaryModal/view/frontend/web/template/summary.html
<div class="opc-block-summary" data-bind="blockLoader: isLoading"> <span data-bind="i18n: 'Order Summary'" class="title"></span> <a href="#" data-bind="text: 'View Summary', click: viewTotalsSummary" class="btn btn-primary"></a> <div class="order-summary-modal" data-bind="visible: isPopUpVisible"> <!-- ko foreach: elems() --> <!-- ko template: getTemplate() --><!-- /ko --> <!-- /ko --> </div> </div>
Next step is to create mixin for summary component. So open the requirejs-config.js file and specify the mixin for summary component.
var config = { config: { mixins: { 'Know_OrderSummaryModal/js/view/cart/summary-modal': { 'Know_OrderSummaryModal/js/view/summary-mixin': true }, 'Magento_Checkout/js/view/summary': { 'Know_OrderSummaryModal/js/view/summary-mixin': true } } } };
You’ll observe that the same mixin is applied to the summary component. This approach allows us to achieve the desired functionality without making alterations to the component code.
Now time to see the output. First 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/*
1. At shipping section
2. At payment section
GitHub: Code on Github