Side Cart

What is a Side Cart?

A side cart (also called a drawer cart or slide cart) is a cart that can be viewed and modified by the customer from any page on the site, allowing the user to make changes to their cart without interrupting the purchase journey flow.

Prerequisites

  • Listed Shopify app is installed
  • Shipping Protection has been approved and enabled for the store
  • Existing merchant with warranty offers on the site

Getting Started

You will need to navigate into your Shopify Store's backend to access the liquid files where you will make the changes listed below.

  1. Go to the Shopify Script Editor.
  2. Create a duplicate of your Current Theme :
    We strongly advise working in a separate, non-live copy of your theme, to ensure your changes aren't visible to customer until you are ready to publish them.
    1. Select the theme you'd like to use, then click Actions -> Duplicate
      Under the duplicate of the theme, usually labelled Copy of {live_theme_name} click Actions -> Rename
    2. Replace Copy of with Extend -
    3. Click Actions -> Edit Code

You will want to use this newly Copied theme to integrate the code changes below.


Code Integration

  1. Add this render to the bottom of your 'extend-configuration.liquid' file:

    <!-- Extend -- Load side cart integration script -->
    {% render 'extend-side-cart-integration' %}
    <!-- Extend -- End Extend code -->
    
  2. Create a new file in the snippets folder and name it extend-side-cart-integration.liquid

  3. Add this code to the contents of this new file:

    <script>
      // Run scripts on DOMContentLoaded to avoid affecting site load time
      window.addEventListener('DOMContentLoaded', function () {
    
        // Only run ajax integration if Extend and ExtendShopify is defined, and the currency is set to USD
        if (window.Extend && window.ExtendShopify && window.Shopify && window.Shopify.currency && window.Shopify.currency.active === 'USD') {
    
          /***********************/
          /* Variables to Change */
          /***********************/
    
          // Example of a selector : 
          // let shippingOfferLocation = '#mini-cart .mini-cart__drawer-footer'
    
          // For help grabbing a CSS selector, use the document located here:
          // https://helloextend.atlassian.net/l/cp/1djs2knw
    
          // DO NOT CHANGE ANY CODE ABOVE THIS LINE
    
          // Replace the value in quotations with: Selector for side cart location where Shipping Offer should go, typically the footer or bottom of the side cart
          let shippingOfferLocation = ''
    
          // Replace the value in quotations with: Selector for side cart toggle button
          let cartToggle = ''
    
          // Replace the value in quotations with: Selector for side cart increase quantity buttons
          let quantityUp = ''
    
          // Replace the value in quotations with: Selector for side cart decrease quantity buttons
          let quantityDown = ''
    
          // Replace the value in quotations with: Selector for side cart remove buttons
          let removeButton = ''
    
          // Troubleshooting: Set to change the word 'false' to 'true' to begin troubleshooting
          // When finished, change 'true' back to 'false' (with no quotations)
    
          let troubleShooter = false;
    
          // DO NOT CHANGE ANY CODE BELOW THIS LINE
    
          /******************/
          /* Util Functions */
          /******************/
          // findAll(element) - querySelectorAll to search for children in document OR a parentElement
          function findAll(elementToFind, parentElement) {
            const items = parentElement ? parentElement.querySelectorAll(elementToFind) : document.querySelectorAll(elementToFind);
            return items;
          }
    
          function extendTroubleShooter() {
    
            let objectToLog = {
              "shippingOfferLocation": shippingOfferLocation ? document.querySelector(shippingOfferLocation) : 'None Specified',
              "cartToggle": cartToggle ? document.querySelector(cartToggle) : 'None Specified',
              "quantityUp": quantityUp ? document.querySelector(quantityUp) : 'None Specified',
              "quantityDown": quantityDown ? document.querySelector(quantityDown) : 'None Specified',
              "removeButton": removeButton ? document.querySelector(removeButton) : 'None Specified'
            }
    
            function returnSelector() {
              let returnString = '';
              Object.keys(objectToLog).forEach(function (each, index) {
                if (Object.values(objectToLog)[index] === 'None Specified') {
                  returnString = returnString + `\n• No element was specified for ${each}.\n`
                } else {
                  returnString = returnString + `\n• The element found for ${each}:\n`
                    + 'Tag Name: ' + Object.values(objectToLog)[index].nodeName
                    + '\nID: ' + Object.values(objectToLog)[index].id
                    + '\nClass List: ' + Object.values(objectToLog)[index].classList + '\n'
                }
              })
              return returnString
            }
    
            alert("Hello, here is your Extend troubleshoot message.\nRemember to set troubleShooter back to false before pushing this theme live!\nThis message can also be viewed in the console.\n"
              + returnSelector())
    
            console.log("Hello, here is the console portion of your Extend troubleshoot message.\nRemember to set troubleShooter back to false before pushing this theme live!\n"
              + returnSelector())
          }
    
          /***********************/
          /* Shipping Protection */
          /***********************/
          const shippingProtectionOfferId = 'extend-drawer-shipping-offer' // This is the ID that will be assigned to the Extend Shipping Protection Offer
    
          function renderOrUpdateSP(spcart) {
            const mappedCartItems = ExtendShopify.spCartMapper(spcart.items)
            if (document.querySelector('#extend-drawer-shipping-offer') && document.querySelector('#extend-drawer-shipping-offer div')) {
              document.querySelector('#extend-drawer-shipping-offer div').remove()
            }
            const shippingProtectionOffer = document.createElement('div')
            shippingProtectionOffer.id = shippingProtectionOfferId;
            if (document.querySelector(shippingOfferLocation)) document.querySelector(shippingOfferLocation).prepend(shippingProtectionOffer)
    
            const isShippingProtectionInCart = ExtendShopify.shippingProtectionInCart(spcart.items);
    
            if (window.location.href.indexOf("cart") === -1) {
              Extend.shippingProtection.destroy()
            }
    
            Extend.shippingProtection.render({
              selector: '#extend-drawer-shipping-offer',
              items: mappedCartItems,
              isShippingProtectionInCart,
              onEnable(quote) {
                ExtendShopify.addSpPlanToCart({
                  quote,
                  callback(err, resp) {
                    if (err) {
                      return;
                    } else window.location.reload();
                  },
                })
              },
              onDisable(quote) {
                ExtendShopify.updateSpPlanInCart({
                  action: 'remove',
                  quote,
                  callback(err, resp) {
                    // an error occurred
                    if (err) {
                      return;
                    } else if (resp.isUpdated) window.location.reload();
                  },
                })
              },
              onUpdate(quote) {
                ExtendShopify.updateSpPlanInCart({
                  action: 'update',
                  quote,
                  callback(err, resp) {
                    // an error occurred
                    if (err) {
                      return;
                    } else if (resp.isUpdated) window.location.reload();
                  },
                })
              },
            });
          }
    
          // initializeCartOffer should be the called at the very top of initializeCartOffers()
          function initializeCartOffer() {
            ExtendShopify.updateExtendLineItems({
              balanceCart: true,
              callback(err, data) {
                if (!err && data && (data.updates || data.additions)) {
                  window.location.reload()
                }
                renderOrUpdateSP(data.cart)
              },
            })
          }
    
          if (troubleShooter) {
            window.setTimeout(function () { extendTroubleShooter() }, 1000)
          }
    
          /*******************************/
          /* Cart Change Detection Start */
          /*******************************/
    
          var cartChangeListeners = function (e) {
    
            var el = e.target
    
            if ((cartToggle && document.querySelector(cartToggle) && el.matches(cartToggle))
              || (quantityUp && document.querySelector(quantityUp) && el.matches(quantityUp))
              || (quantityDown && document.querySelector(quantityDown) && el.matches(quantityDown))
              || (removeButton && document.querySelector(removeButton) && el.matches(removeButton))) {
              window.setTimeout(function () {
                initializeCartOffer();
              }, 1000)
            }
          }
    
          //Adds event listener with event delegation to listen for button click
          document.addEventListener('click', cartChangeListeners, true);
    
        }
    
      });
    
    </script>
    
    <style>
      #extend-drawer-shipping-offer {
        text-align: center !important;
        height: 120px !important;
      }
    
      .extend-warranty-info {
        font-size: 13px;
        color: #424242B3;
      }
    
      #sp-learn-more-modal-iframe {
        z-index: 9999999999 !important;
      }
    </style>
    
  4. In the section between lines 21 - 33, insert the 5 necessary CSS selectors to complete this integration. Those selectors are for the following:

    1. shippingOfferLocation - Location where the shipping offer will be inserted
    2. cartToggle - Element that must be clicked to open the side cart
    3. quantityUp (If applicable) - Button on each product to increase its quantity
    4. quantityDown (If applicable) - Button on each product to decrease its quantity
    5. removeButton (If applicable) - Button on each product to remove it from the cart

📘

Please use this guide on how to get an CSS selector if additional context is needed.

You should not modify any code outside of lines 21 - 38

Below are some general appearance examples for these locations. Keep in mind that they may differ in appearance, and some side carts may not even feature product removal and quantity change options. In these cases, simply ignore the lines requesting those selectors.



Troubleshooting

There is a troubleshooting tool built into the snippet.

To use it simply change the word false to true on line 38.

Remember to change this back to false before publishing the theme!

The tool will display information about which Elements are being grabbed with the CSS Selectors you have added.

If you run into any issues during this integration process or have questions please reach out to our team through your Merchant Portal.