Code Integration Shipping protection only
Overview
In this guide we will be cloning your live theme for code editing. Then we will locate the Subtotal Container on your Cart page, which will be used to house the Shipping Protection Offer Element. Once identified both on page and in your Cart page's code you will then add in the code necessary to populate the Shipping Offer within the Cart page.
Estimated time of completion: 1 Hour
Configuration
Follow this guide to setup and run your theme locally using Stencil CLI here
Shipping Protection Snippet
Create extend-integration
folder within templates/components
and create 2 files:
extend-integration
folder within templates/components
and create 2 files:- extend-checkoutSP.html
- extend.js
extend-checkoutSP.html
<!-- Extend script tags - these can be moved into script manager to apply only to product and cart pages -->
<script src='https://sdk.helloextend.com/extend-sdk-client/v1/extend-sdk-client.min.js'></script>
<script src='https://sdk.helloextend.com/extend-sdk-client-bigcommerce-addon/v1/extend-sdk-client-bigcommerce-addon.min.js'></script>
<script>Extend.config({ storeId: 'STORE_ID_GOES_HERE', environment: 'production' })</script>
<!-- Extend script tags end -->
<!-- Extend - checkout SP offers -->
<script>
'use strict';
let listeners = [], doc = window.document, MutationObserver = window.MutationObserver || window.WebKitMutationObserver, observer;
const productList = '.productList' // Products container inside the order summary at checkout
const singleProduct = '.product' // Line item in order summary at checkout
const productTitle = '.product-title' // Product title in order summary used to check if title equals Extend Protection Plan
const productImageContainer = '.product-figure' // Product in order summary Adds Extend logo to Extend line item
const shippingSection = '#checkout-shipping-options' // Shipping step in checkout - code will wait until we find this selector
const shippingMethods = '#checkout-shipping-options' // Shipping methods container - we insertBefore the continue button after this query
function ready(selector, fn) {
// Store the selector and callback to be monitored
listeners.push({
selector: selector,
fn: fn
});
if (!observer) {
// Watch for changes in the document
observer = new MutationObserver(check);
observer.observe(doc.documentElement, {
childList: true,
subtree: true
});
}
// Check if the element is currently in the DOM
check();
}
function check() {
// Check the DOM for elements matching a stored selector
for (let i = 0, len = listeners.length, listener, elements; i < len; i++) {
listener = listeners[i];
// Query for elements matching the specified selector
elements = doc.querySelectorAll(listener.selector);
for (let j = 0, jLen = elements.length, element; j < jLen; j++) {
element = elements[j];
// Make sure the callback isn't invoked with the same element more than once
if (!element.ready) {
element.ready = true;
// Invoke the callback with the element
listener.fn.call(element, element);
}
}
}
}
function renderShippingProtectionOffer(spCart) {
if (spCart) {
const itemsMapped = ExtendBigCommerce.formatCartItemsForSp(spCart);
if (Extend.shippingProtection._instance !== null) {
Extend.shippingProtection.update({ items: itemsMapped });
} else {
Extend.shippingProtection.render({
selector: '#extend-shipping-offer',
items: itemsMapped,
isShippingProtectionInCart:
ExtendBigCommerce.isShippingProtectionInCart(spCart),
onEnable: function (quote) {
const callback = (error) => {
if (error) {
console.error('EXTEND: ', error)
return;
} else {
window.location.reload();
}
};
return ExtendBigCommerce.addSpPlanToCart(
{ quote, cart: spCart },
callback
);
},
onDisable: function (quote) {
const callback = (error, res) => {
if (error) {
console.error('EXTEND: ', error)
return;
} else {
window.location.reload();
}
};
return ExtendBigCommerce.removeSpPlanFromCart(
{ quote, cart: spCart },
callback
);
},
onUpdate: function (quote) {
const callback = (error, data) => {
if (error) {
console.error('EXTEND: ', error)
return;
} else if (data.spPlanUpdated) {
window.location.reload();
}
};
return ExtendBigCommerce.getCart((error, cart) => {
if (cart) {
ExtendBigCommerce.updateSpPlanInCart({quote, cart}, callback);
}
else {
if (error) {
console.error('Error: ', error)
}
}
});
},
});
}
}
}
window.addEventListener('load', () => {
if (window.Extend && window.ExtendBigCommerce) {
/**********************/
/* Global Variables */
/**********************/
// Create shipping protection empty div
const shippingProtectionOffer = document.createElement('div');
shippingProtectionOffer.id = 'extend-shipping-offer';
shippingProtectionOffer.style.marginTop = '50px';
shippingProtectionOffer.style.marginBottom = '-50px';
// Get's updated cart object
ExtendBigCommerce.getCart(function (error, cart) {
if (cart) {
// Wait for shipping section to be found on DOM before running SP Code
ready(shippingSection, () => {
// Run normalization and handle shipping protection
ExtendBigCommerce.updateExtendLineItems(
{ balanceCart: true },
function (error, data) {
if (data && (data.updates || data.additions)) {
window.location.reload();
} else if(error) {
console.error('EXTEND: ', error)
}
// Find the shippingSpot querySelector
let shippingSpot = document.querySelector(shippingMethods).parentElement;
// Append Shipping protection offer to shippingSpot before form-actions and renderShippingProtectionOffer
shippingSpot.insertBefore(shippingProtectionOffer, shippingSpot.querySelector('.form-actions'));
renderShippingProtectionOffer(data.cart);
}
);
})
// Wait for product list to be found
ready(productList, () =>{
const products = document.querySelectorAll(singleProduct);
if(products){
const warrantyProducts = Array.from(products).filter((item) => {
const productTitle = item.querySelector(productTitle).textContent;
// Conditionally render product image if Extend product protection or Extend shipping protection
if(productTitle.includes('Extend Protection') && item.querySelector(productImageContainer)){
item.querySelector(productImageContainer).innerHTML = `<img alt='${productTitle}' data-test='cart-item-image' src='{{cdn 'img/extend_logo.png'}}'>`
} else if(productTitle.includes('Extend Shipping') && item.querySelector('.product-figure')){
item.querySelector('.product-figure').innerHTML = `<img alt='${productTitle}' data-test='cart-item-image' src='{{cdn 'img/extend_shipping.png'}}'>`
}
});
}
})
}
});
}
});
</script>
<!-- Extend - End Extend Code -->
Configure Extend storeID
At the top of the snippet you pasted in, ensure you update your Extend StoreID. If you need assistance locating your StoreID refer to this guide on Finding your StoreID
Configure Extend Shipping Protection Offer Placement
- On the checkout page, right click on the summary box and click “Inspect element”
- Find the element that contains the cart-section element
- Copy the class name
- In the snippet you pasted, near the top of the 'load' event, set this to the class or selector of where you would like the Extend Shipping Protection offer appended.
Add extend.js
In extend-integration
folder within templates/components
Create a file called extend.js and paste the snippet from below into the file
// Import stencil utils
import utils from '@bigcommerce/stencil-utils';
// Handles removing item from cart and hard refreshes page
const removeCartItem = (itemId) => {
// Remove passed in itemId from the cart
utils.api.cart.itemRemove(itemId, (error, response) => {
if (response.data.status === 'succeed') {
window.location.reload();
} else if(error) {
console.error('EXTEND: ', error)
}
});
}
// initializeCartOffers() - Handles cart normalization and balancing
export function initializeCartOffers() {
if (window.Extend && window.ExtendBigCommerce) {
ExtendBigCommerce.getCart(function (error, cart) {
if (cart) {
// If there is customItems in the cart
if(cart.lineItems.customItems.length >= 1){
// Check if custom item is Extend Shipping Protection and if so, remove it from cart
if(cart.lineItems.customItems.filter(itm => itm.name === 'Extend Shipping Protection Plan')[0]){
const spItemToRemove = cart.lineItems.customItems.filter(itm => itm.name === 'Extend Shipping Protection Plan')[0].id
// cartRemoveItem(spItemToRemove) - Removes SP from cart
removeCartItem(spItemToRemove)
}
}
} else if(error) {
console.error('EXTEND: ', error);
}
});
}
}
Import and invoke initializeCartOffers()
Locate assets/js/theme/cart.js
a. Import initializeCartOffers
at the top of cart.js, below all other imports:
// Extend - Import initializeCartOffers from extend.js
import { initializeCartOffers } from './extend';
// Extend - End code
b. within the same file locate the onReady()
function and add the snippet below:
// Extend - invokes initializeCartOffers on cart load
initializeCartOffers();
// Extend - End Code
c. within the same file locate the getContent()
function and add the following snippet at the bottom of the function:
// Extend - invokes initializeCartOffers on cart load
initializeCartOffers();
// Extend - End Code
Hide Shipping Protection Line Item
Now we will add some additional code to ensure that the Shipping Protection Line Item is hidden on the preview cart and main cart pages. This is meant to clean up the Cart page experience overall.
Locate content.html
- Navigate to templates/components/cart/content.html
Edit
- Find where the code is looping through each cart item and at the top of the loop add the following snippet:
<!-- Extend Hide SP Items -->
{{#if name '!==' 'Extend Shipping Protection Plan'}}
- Scroll down to the bottom of the file and find where the loop is ending, add the following snippet below:
{{/if}}
<!-- Extend - End code -->
Great job, you have implemented the code pieces needed to facilitate Shipping Protection Offers on your BigCommerce Store. Next we will go over some Verification steps needed to complete the project.
If you run into any issues during this integration process or have questions please reach out to our team through your Merchant Portal.
Checklist
Updated 11 months ago