Read this article to learn about basic requirements for implementing shopping cart recovery in the theme and different ways of doing it.

For more information about shopping cart recovery, see our user guide.

There are two components connected to implementing shopping cart recovery in the theme:

  • The email template for the shopping cart recovery message – /themes/email/THEME/cart-recovery.html

    The new default email theme MyCashflow 2018 comes with a readymade email template. There is no such template in the old email theme.

    If you use your own email template for shopping cart recovery, make sure that it works well on mobile devices too.

  • The form in which customers can indicate their email addresses for shopping cart recovery messages.

    The functionality can work in the online store without the form as well but only in certain cases (for more information see our user guide).

    The form can be added to the theme by using the {CartRecoveryNotificationForm} tag.

Possible ways of implementation

In this section, you'll learn about different ways of implementing shopping cart recovery in the theme.

No form for collecting email addresses or a static form

There is no need for the online store to separately collect email addresses for sending shopping cart recovery messages. The message can be sent if any of the following conditions has been met:

  • The customer has accepted the shipping conditions and proceeded to payment but the shopping cart has been abandoned nevertheless. In such case, an error may have occurred in the payment service, and the order couldn’t be processed.

  • The logged-in customer has agreed to receive marketing emails and has proceeded to checkout after adding products to the shopping cart.

  • The customer has subscribed to cart recovery messages (the form for doing so needs to be added separately to your store theme).

You can also add a static form to the theme, for instance to the footer, checkout or shopping cart page. This solution is non-distracting but it may not necessarily motivate visitors to give out their email addresses.

Pop-up

Alternatively, you can place the form for collecting email addresses inside a pop-up window (modal) to make sure that the visitors to your store notice it. In this section, you'll learn how to place the form inside a pop-up in the Barebones theme.

Adding a pop-up has been implemented with the jQuery plugin cart-recovery.js. cart-recovery.js performs the desired function based on the set delay. The delay is counted from the visitor's last visit to the checkout (with products in the shopping cart) or the moment when the contents of the shopping cart were last modified.

In this chapter, we use the Barebones theme's tools.

The cart-recovery.js plugin used in this article can be downloaded at the end of this article.

  1. First, add the cart-recovery.js plugin to the theme and initialize it.

    See detailed instructions at the end of the article.

  2. Add a content page to the store on which you'll encourage visitors to give out their email addresses.
  3. Add the helper file helpers/modals/cart-recovery.html to the theme.

    Here you can see the contents of the file used in our example:

    <h1>{InfoPageTitle}</h1>
    {InfoPageText}
    {CartRecoveryNotificationForm}
  4. Retrieve the contents of the content page into the modal while initializing the cart-recovery.js plugin.

    The content of the showRecovery() hook function is executed after the delay time defined for the plugin has passed. In this example, the theme's file helpers/modals/cart-recovery.html is displayed to the visitor in the modal. The file displays the contents of the content page with the id 12.

    MCF.CartRecovery.init({
    	showRecovery: function () {
    		$.magnificPopup.open({
    			type: 'ajax',
    			closeBtnInside: false,
    			items: { src: '/interface/Helper?file=helpers/modals/cart-recovery&infopage=12' },
    			callbacks: {
    				parseAjax: function (mfpResponse) {
    					mfpResponse.data = $('<div class="mfp-ajax-content" />').append(mfpResponse.data);
    					return mfpResponse;
    				}
    			}
    		});
    	}
    });

Below you can see an example of a content page and email form displayed in the modal.

Opening the modal when the visitor is leaving the page is an aggressive strategy that may annoy them. While it might work in some cases, it may also discourage visitors from visiting your store for good.

If you use Magnific Popup's functions directly in the theme, the modals.js plugin's layout styles won't be applied to them by default. Nevertheless, you can still enable the styles by adding the wrapper <div class="mfp-ajax-content"> to the modal window.

The cart-recovery.js plugin

In this section, you'll learn how to add the cart-recovery.js plugin to the theme.

cart-recovery.js performs the desired function based on the set delay. The delay is counted from the visitor's last visit to the checkout (with products in the shopping cart) or the moment when the contents of the shopping cart were last modified.

Place the script file in the same location as the other theme scripts. Maintaining the theme is easier in this way.

The plugin requires jQuery to function properly.To add jQuery to a page, use the {SupportScripts} tag. The default theme includes jQuery by default.

  1. Add the plugin source code presented below to the theme's file scripts/plugins/modals/cart-recovery.js.
    ;(function ($) {
    	'use strict';
    
    	var KEY_PREFIX = 'mcf.cartRecovery.';
    	var RECOVERY_SHOWN_KEY = KEY_PREFIX + 'recoveryShown';
    	var ITEMS_COUNT_KEY = KEY_PREFIX + 'itemsCount';
    	var ITEMS_CHANGED_KEY = KEY_PREFIX + 'itemsChanged';
    	var CHECKOUT_VISITED_KEY = KEY_PREFIX + 'checkoutVisited';
    
    	var defaults = {
    
    		/* Time indicated in seconds after which the showRecovery() function is executed */
    		maxIdleSeconds: 30,
    		showRecovery: function () {},
    	};
    
    	var CartRecovery = {
    		init: function (options) {
    			var config = $.extend({}, defaults, options);
    
    			this._helper = config.helper;
    			this._showRecoveryCallback = config.showRecovery;
    			this._recoveryShown = this._loadKey(RECOVERY_SHOWN_KEY) || false;
    			this._maxIdleSeconds = config.maxIdleSeconds * 1000;
    
    			if (this._recoveryShown) {
    				return;
    			}
    
    			var self = this;
    			this._fetchItemsCount()
    				.then(function (newItemsCount) {
    					
    					var oldItemsCount = self._loadKey(ITEMS_COUNT_KEY);
    					var itemsChanged = self._loadKey(ITEMS_CHANGED_KEY);
    					
    					if (window.location.href.match(/\/checkout\//)) {
    						self._saveKey(CHECKOUT_VISITED_KEY, true);
    					} else if (self._loadKey(CHECKOUT_VISITED_KEY)) {
    						self._showRecovery();
    					} else if (itemsChanged) {
    						self._startIdleTimer();
    						self._saveKey(ITEMS_COUNT_KEY, newItemsCount);
    					} else if (newItemsCount && oldItemsCount !== newItemsCount) {
    						self._startIdleTimer();
    						self._saveKey(ITEMS_COUNT_KEY, newItemsCount);
    						self._saveKey(ITEMS_CHANGED_KEY, true);
    					}
    				});
    		},
    
    		_showRecovery: function () {
    			this._showRecoveryCallback();
    			this._recoveryShown = true;
    			this._saveKey(RECOVERY_SHOWN_KEY, true);
    		},
    
    		_saveKey: function (key, value) {
    			window.sessionStorage.setItem(key, value);
    		},
    
    		_loadKey: function (key) {
    			return JSON.parse(window.sessionStorage.getItem(key));	
    		},
    
    		_fetchItemsCount: function () {
    			return $.get('/interface/CartTotalItems')
    				.then(function (res) {
    					return parseInt(res);
    				});
    		},
    
    		_startIdleTimer: function () {
    			var self = this;
    			this._idleTimer = window.setTimeout(function () {
    				self._showRecovery();
    			}, this._maxIdleSeconds);
    		},
    
    		_stopIdleTimer: function () {
    			window.clearTimeout(this._idleTimer);
    		}
    	};
    
    	$.extend(true, window, { MCF: { CartRecovery: CartRecovery }});
    })(jQuery);

    In the defaults object, you can define the number of seconds after which the plugin should execute the desired code in the showRecovery() function.

  2. Make sure that the plugin is loaded in the helpers/scripts.html file.
    {MinifyJS(
    	mode: 'development',
    	support_scripts: 'true',
    	files: '
    		vendor/jquery/jquery.js|
    		vendor/jquery.finger/dist/jquery.finger.js|
    		vendor/hc-sticky/jquery.hc-sticky.js|
    		vendor/magnific-popup/dist/jquery.magnific-popup.js|
    		vendor/slick-carousel/slick/slick.js|
    		scripts/locales.js|
    		scripts/theme.js|
    		scripts/plugins/cart.js|
    		scripts/plugins/cart-recovery.js|
    		scripts/plugins/checkout.js|
    		scripts/plugins/drawers.js|
    		scripts/plugins/images.js|
    		scripts/plugins/klarna-checkout.js|
    		scripts/plugins/loaders.js|
    		scripts/plugins/modals.js|
    		scripts/plugins/navigations.js|
    		scripts/plugins/notifications.js|
    		scripts/plugins/search.js|
    		scripts/plugins/sliders.js|
    		scripts/plugins/spinners.js|
    		scripts/plugins/tabs.js|
    		scripts/plugins/variations.js|
    		scripts/custom.js'
    )}
  3. Finally, initialize the plugin in the theme's file scripts/custom.js.

    During the initialization you can define the code that the plugin should execute in the showRecovery() function after the defined time has passed.

    MCF.CartRecovery.init({
    	showRecovery: function () {
    		$.magnificPopup.open({
    			type: 'ajax',
    			closeBtnInside: false,
    			items: { src: '/interface/Helper?file=helpers/modals/cart-recovery&infopage=12' },
    			callbacks: {
    				parseAjax: function (mfpResponse) {
    					mfpResponse.data = $('<div class="mfp-ajax-content" />').append(mfpResponse.data);
    					return mfpResponse;
    				}
    			}
    		});
    	}
    });

    The content of the showRecovery() hook function is executed after the delay time defined for the plugin has passed. In this example, the theme's file helpers/modals/cart-recovery.html is displayed to the visitor in the modal. The file displays the contents of the content page with the id 12.