In this tutorial, we will learn to create Magento 2 module which adds a free shipping progress bar on magento2 shopping cart page to promote increased order value.
Let's start it by creating custom module.
You can find complete module on Github.
Create folder inside app/code/Magelearn/FreeShippingProgressBar
Add registration.php file in it:
1 2 3 4 5 6 7 8 | <?php /** * Copyright © All rights reserved. * See COPYING.txt for license details. */ use Magento\Framework\Component\ComponentRegistrar; ComponentRegistrar::register(ComponentRegistrar::MODULE, 'Magelearn_FreeShippingProgressBar' , __DIR__); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | { "name" : "magelearn/module-freeshippingprogressbar" , "description" : "Display a progress bar on the shopping cart based on order total to encourage users to spend more to get free shipping" , "type" : "magento2-module" , "license" : "OSL-3.0" , "authors" : [ { "email" : "info@mage2gen.com" , "name" : "Mage2Gen" }, { "email" : "vijaymrami@gmail.com" , "name" : "vijay rami" } ], "minimum-stability" : "dev" , "require" : { "magento/module-quote" : "*" , "magento/module-checkout" : "*" }, "autoload" : { "files" : [ "registration.php" ], "psr-4" : { "Magelearn\\FreeShippingProgressBar\\" : "" } } } |
1 2 3 4 | <? xml version = "1.0" ?> < config xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation = "urn:magento:framework:Module/etc/module.xsd" > < module name = "Magelearn_FreeShippingProgressBar" setup_version = "1.0.0" /> </ config > |
Now, We will give system configuration options and default configurations values for this module.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | <? xml version = "1.0" ?> <!-- /** * Copyright All rights reserved. * See COPYING.txt for license details. */ --> < config xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation = "urn:magento:module:Magento_Config:etc/system_file.xsd" > < system > < section id = "checkout" > < group id = "cart" > < field id = "freeshipping_progress_enable" sortOrder = "110" translate = "label" showInDefault = "1" showInWebsite = "1" showInStore = "1" type = "select" > < label >Enable Free Shipping Progress Bar</ label > < source_model >Magento\Config\Model\Config\Source\Yesno</ source_model > < comment >Display a free shipping progress bar in cart to promote higher order values.</ comment > </ field > < field id = "freeshipping_progress_color_field" sortOrder = "120" translate = "label" showInDefault = "1" showInWebsite = "1" showInStore = "1" type = "text" > < label >Background Color</ label > < comment > <![CDATA[Background color]]> </ comment > < frontend_model >Magelearn\FreeShippingProgressBar\Block\Color</ frontend_model > < depends > < field id = "freeshipping_progress_enable" >1</ field > </ depends > </ field > < field id = "use_freeshipping_method_config" sortOrder = "130" translate = "label" showInDefault = "1" showInWebsite = "1" showInStore = "1" type = "select" > < label >Use Free Shipping Method Configuration</ label > < comment >If set to yes, the free shipping progress bar will be based on if the core free shipping method is available or not. If set to no, you can use a custom configuration using the fields that will appear below this field.</ comment > < source_model >Magento\Config\Model\Config\Source\Yesno</ source_model > < depends > < field id = "freeshipping_progress_enable" >1</ field > </ depends > </ field > < field id = "freeshipping_progress_min_total" sortOrder = "140" translate = "label" showInDefault = "1" showInWebsite = "1" showInStore = "1" type = "text" > < label >Free Shipping Progress Bar Minimum Order Total</ label > < comment >Enter the value an order has to be equal to or over to be eligible for free shipping.</ comment > < depends > < field id = "use_freeshipping_method_config" >0</ field > </ depends > </ field > </ group > </ section > </ system > </ config > |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | <?php namespace Magelearn\FreeShippingProgressBar\Block; class Color extends \Magento\Config\Block\System\Config\Form\Field { public function __construct( \Magento\Backend\Block\Template\Context $context , array $data = [] ) { parent::__construct( $context , $data ); } protected function _getElementHtml(\Magento\Framework\Data\Form\Element\AbstractElement $element ) { $html = $element ->getElementHtml(); $value = $element ->getData( 'value' ); $html .= '<script type= "text/javascript" > require ([ "jquery" ], function ($) { $(document).ready( function (e) { $( "#' . $element->getHtmlId() . '" ).css( "background-color" , "#' . $value . '" ); $( "#' . $element->getHtmlId() . '" ).colpick({ layout: "hex" , submit: 0, colorScheme: "dark" , color: "#' . $value . '" , onChange: function (hsb, hex, rgb, el, bySetColor) { $(el).css( "background-color" , "#" + hex); if (!bySetColor) $(el).val(hex); } }).keyup( function () { $(this).colpickSetColor(this.value); }); }); }); </script>'; return $html ; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <? xml version = "1.0" ?> <!-- /** * Copyright All rights reserved. * See COPYING.txt for license details. */ --> < config xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation = "urn:magento:module:Magento_Store:etc/config.xsd" > < default > < checkout > < cart > < freeshipping_progress_enable >0</ freeshipping_progress_enable > < freeshipping_progress_color_field >00b052</ freeshipping_progress_color_field > < use_freeshipping_method_config >1</ use_freeshipping_method_config > </ cart > </ checkout > </ default > </ config > |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | <? xml version = "1.0" ?> <!-- /** * Copyright All rights reserved. * See COPYING.txt for license details. */ --> < config xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation = "urn:magento:framework:Acl/etc/acl.xsd" > < acl > < resources > < resource id = "Magento_Backend::admin" > < resource id = "Magento_Backend::stores" > < resource id = "Magento_Backend::stores_settings" > < resource id = "Magento_Config::config" > < resource id = "Magelearn_FreeShippingProgressBar::config" title = "Free Shipping Progress Bar" /> </ resource > </ resource > </ resource > </ resource > </ resources > </ acl > </ config > |
Create layout file checkout_cart_index.xml file inside app/code/Magelearn/FreeShippingProgressBar/view/frontend/layout folder.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <? xml version = "1.0" ?> <!-- /** * Copyright All rights reserved. * See COPYING.txt for license details. */ --> < page xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" layout = "1column" xsi:noNamespaceSchemaLocation = "urn:magento:framework:View/Layout/etc/page_configuration.xsd" > < head > < css src = "Magelearn_FreeShippingProgressBar::css/custom.css" rel = "stylesheet" type = "text/css" /> </ head > < body > < referenceContainer name = "cart.summary" > < block name = "checkout.cart.freeshipping.progress.bar" before = "checkout.cart.shipping" template = "Magelearn_FreeShippingProgressBar::cart/freeshipping_progress_bar.phtml" ifconfig = "checkout/cart/freeshipping_progress_enable" > < arguments > < argument name = "viewModel" xsi:type = "object" >Magelearn\FreeShippingProgressBar\ViewModel\Cart\ProgressBar</ argument > </ arguments > </ block > </ referenceContainer > </ body > </ page > |
Create template file freeshipping_progress_bar.phtml file inside app/code/Magelearn/FreeShippingProgressBar/view/frontend/templates/cart folder.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | <? php /** * Copyright All rights reserved. * See COPYING.txt for license details. */ declare( strict_types = 1 ); use Magelearn\FreeShippingProgressBar\ViewModel\Cart\ProgressBar; use Magento\Framework\View\Element\Template; /** @var Template $block */ /** @var ProgressBar $viewModel */ $viewModel = $block->getData('viewModel'); $shippingLabel = 'FREE SHIPPING'; ?> < div class = "freeship-progress" > <? php if (!$viewModel->isFreeShippingEligible()): ?> <? php $freeshippingProgress = $viewModel->getFreeShippingCompletionPercent(); $freeshippingProgresscolor = $viewModel->getProgressbarBackground(); $background = "background: linear-gradient(to right, #".$freeshippingProgresscolor." 0%, #".$freeshippingProgresscolor." ". $freeshippingProgress . "%, lightgreen);"; if ($freeshippingProgress > 90) { $background = "background: linear-gradient(to right, #".$freeshippingProgresscolor." 0%, #".$freeshippingProgresscolor." 95%, lightgreen);"; } ?> < p class = "upsell" > <?= /* @noEscape */ __( 'Add < span class = "freeship-price" >%1</ span > more to get < span class = "freeship-bold" >%2!</ span >', $viewModel->getFormattedPrice($viewModel->getFreeShippingDifference()), $shippingLabel ) ?> </ p > < div class = "freeship-progress-bar-wrapper" > < span class = "min" ><?= /* @noEscape */ $viewModel->getFormattedPrice(0, 0) ?></ span > < div class = "freeship-progress-bar" > < div class = "freeship-progress-bar-bg" > < div class = "freeship-progress-bar-fill freeship-progress-bar-progress" style="width: <?= /* @noEscape */ $viewModel->getFreeShippingCompletionPercent() ?>%; <?= /* @noEscape */ $background ?>"> </ div > </ div > </ div > < span class = "max" > <?= /* @noEscape */ $viewModel->getFormattedPrice($viewModel->getFreeShippingMinValue(), 0) ?> </ span > </ div > <? php else: ?> < div class = "freeship-text" > < p > <?= /* @noEscape */ __( 'Your order is eligible for < span class = "freeship-bold" >%1!</ span >', $shippingLabel ) ?> </ p > </ div > <? php endif; ?> </ div > |
Create ViewModel file ProgressBar.php inside app/code/Magelearn/FreeShippingProgressBar/ViewModel/Cart folder.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | <?php /** * Copyright All rights reserved. * See COPYING.txt for license details. */ declare (strict_types=1); namespace Magelearn\FreeShippingProgressBar\ViewModel\Cart; use Magento\Checkout\Model\Session; use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\Pricing\PriceCurrencyInterface; use Magento\Framework\View\Element\Block\ArgumentInterface; use Magento\Store\Model\ScopeInterface; class ProgressBar implements ArgumentInterface { /** * System XML config path for Magelearn_FreeShippingProgressBar - Uses default checkout cart section */ protected const CHECKOUT_CART_XML_CONFIG_PATH = 'checkout/cart/' ; /** * System XML config path for core Free Shipping method */ protected const CARRIERS_FREE_SHIPPING_XML_CONFIG_PATH = 'carriers/freeshipping/' ; /** * @var ScopeConfigInterface $scopeConfig */ protected $scopeConfig ; /** * @var Session $session */ protected $session ; /** * @var PriceCurrencyInterface $priceCurrency */ protected $priceCurrency ; /** * Countdown constructor. * * @param ScopeConfigInterface $scopeConfig * @param Session $session * @param PriceCurrencyInterface $priceCurrency */ public function __construct( ScopeConfigInterface $scopeConfig , Session $session , PriceCurrencyInterface $priceCurrency ) { $this ->scopeConfig = $scopeConfig ; $this ->session = $session ; $this ->priceCurrency = $priceCurrency ; } /** * Get minimum order total required to be eligible for free shipping * * @return float */ public function getFreeShippingMinValue(): float { if ( $this ->scopeConfig->getValue(self::CHECKOUT_CART_XML_CONFIG_PATH . 'use_freeshipping_method_config' , ScopeInterface::SCOPE_STORE) && $this ->scopeConfig->getValue(self::CARRIERS_FREE_SHIPPING_XML_CONFIG_PATH . 'active' , ScopeInterface::SCOPE_STORE) ) { return $this ->getFreeShippingMethodMinValue(); } return (float) $this ->scopeConfig->getValue(self::CHECKOUT_CART_XML_CONFIG_PATH . 'freeshipping_progress_min_total' , ScopeInterface::SCOPE_STORE); } public function getFreeShippingMethodMinValue(): float { return (float) $this ->scopeConfig->getValue(self::CARRIERS_FREE_SHIPPING_XML_CONFIG_PATH . 'free_shipping_subtotal' , ScopeInterface::SCOPE_STORE); } /** * Get current quote/cart total * * @return float * @throws LocalizedException * @throws NoSuchEntityException */ public function getCurrentTotal(): float { return (float) $this ->session->getQuote()->getSubtotalWithDiscount(); } /** * Validate if current order total is free shipping eligible * * @return bool * @throws LocalizedException * @throws NoSuchEntityException */ public function isFreeShippingEligible(): bool { $currentTotal = $this ->getCurrentTotal(); if ( $this ->scopeConfig->getValue(self::CHECKOUT_CART_XML_CONFIG_PATH . 'use_freeshipping_method_config' , ScopeInterface::SCOPE_STORE)) { if ( $this ->scopeConfig->getValue( self::CARRIERS_FREE_SHIPPING_XML_CONFIG_PATH . 'active' , ScopeInterface::SCOPE_STORE )) { return ( $currentTotal >= $this ->getFreeShippingMethodMinValue()); } return false; } return ( $currentTotal >= $this ->getFreeShippingMinValue()); } /** * Get difference between minimum order total for free shipping current order total * * @return float * @throws LocalizedException * @throws NoSuchEntityException */ public function getFreeShippingDifference(): float { return $this ->getFreeShippingMinValue() - $this ->getCurrentTotal(); } /** * Get percentage completed towards free shipping * * @return float * @throws LocalizedException * @throws NoSuchEntityException */ public function getFreeShippingCompletionPercent(): float { return ( $this ->getCurrentTotal() / $this ->getFreeShippingMinValue()) * 100; } /** * @param float $price * @param int $precision * * @return string */ public function getFormattedPrice(float $price , int $precision = 2): string { return $this ->priceCurrency->format( $price , false, $precision ); } public function getProgressbarBackground(): string { return $this ->scopeConfig->getValue(self::CHECKOUT_CART_XML_CONFIG_PATH . 'freeshipping_progress_color_field' , ScopeInterface::SCOPE_STORE); } } |
Finally add CSS file custom.less file inside app/code/Magelearn/FreeShippingProgressBar/view/frontend/web/css folder to apply final effects.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | .freeship-progress { padding : 15px ; background-color : transparent ; border-top : 1px solid #ccc ; @media screen and ( min-width : 768px ) { padding : 16px 0 ; } .freeship-text { color : #000 ; margin-bottom : 0 ; max-width : 100% ; p { margin-bottom : 0 ; } } p { &.upsell { text-align : center ; @media screen and ( min-width : 768px ) { text-align : left ; } } .freeship-price { color : red ; font-weight : 600 ; } .freeship- bold { font-weight : 600 ; } } .freeship-progress-bar-wrapper { color : #000 ; span { display : inline- block ; &.min { width : 17px ; } &.max { width : 33px ; text-align : right ; } } .freeship-progress-bar-bg { background-color : rgba( 0 , 0 , 0 , . 1 ); height : 8px ; border-radius: 3px ; overflow : hidden ; position : relative ; width : 100% ; } .freeship-progress-bar-fill { height : 8px ; display : block ; border-radius: 3px ; animation-name: shippingProgressBar; animation-duration: 1.25 s; animation-timing-function: ease; animation-delay: 0 s; animation-iteration-count: 1 ; animation- direction : normal ; animation-fill-mode: none ; animation-play-state: running; -webkit-animation: shippingProgressBar 1.25 s 1 ; animation: shippingProgressBar 1.25 s 1 ; transition: width . 667 s cubic-bezier(. 37 , . 16 , . 22 , . 89 ); } .freeship-progress-bar-progress { background : #00b052 ; } .freeship-progress-bar { margin : 0 auto ; width : ~ 'calc(100% - 58px)' ; display : inline- block ; } } @-webkit-keyframes shippingProgressBar { 0% { -webkit-transform: translateX( -100% ); transform: translateX( -100% ) } to { -webkit-transform: translateX( 0 ); transform: translateX( 0 ) } } @keyframes shippingProgressBar { 0% { -webkit-transform: translateX( -100% ); transform: translateX( -100% ) } to { -webkit-transform: translateX( 0 ); transform: translateX( 0 ) } } } |
0 Comments On "Adds a free shipping progress bar on Magento2 shopping cart page to promote increased order value"