Use the script below to see an example on how to add a "add to cart" button to the recommendation widget on a Shopify site
<script>
/* CalllBacks START */
var isp_related_options = {
isp_related_callback: function (data) {
for (const key in ISP_RELATED_PRODUCTS) {
const product = ISP_RELATED_PRODUCTS[key];
const $divItem = $jquery_isp(
`.isp_related_product[isp_product_id="${key}"]`
);
/* +QuickAdd btn */
AddToCart.create(product, $divItem);
}
}, // Recommendations rendered
};
/* CalllBacks END */
const ButtonType = {
Single: "single",
Options: "options",
SelectColor: "select color",
SelectSize: "select size",
SoldOut: "sold out",
};
function getFirstVariantID(product) {
return product.vra && product.vra.length > 0 ? product.vra[0][0] : product.id;
}
function isSoldOut (product) {
return ("iso" in product && product.iso);
}
function findVariantOption(variant, optionName) {
const data = variant[1].find((option) => option[0] === optionName);
return data ? data[1][0] : null;
}
const AddToCart = {
create: (product, $gridItem) => {
const type = AddToCart.getButtonType(product);
const isFrom = AddToCart.checkFrom($gridItem);
AddToCart.removePrice($gridItem);
switch (type) {
case ButtonType.Single: {
AddToCart.setAddToCart(product, $gridItem, "ADD TO CART", isFrom);
break;
}
case ButtonType.SoldOut: {
AddToCart.setSoldOut($gridItem);
break;
}
case ButtonType.SelectColor: {
AddToCart.setRedirectToProduct(
product,
$gridItem,
"SELECT COLOR",
isFrom
);
break;
}
case ButtonType.SelectSize: {
AddToCart.setRedirectToProduct(
product,
$gridItem,
"SELECT SIZE",
isFrom
);
break;
}
case ButtonType.Options: {
AddToCart.setRedirectToProduct(
product,
$gridItem,
"SELECT OPTIONS",
isFrom
);
}
}
},
getButtonType: (product) => {
if (isSoldOut(product)) {
return ButtonType.SoldOut;
}
if (!product.vra || product.vra.length < 2) {
return ButtonType.Single;
}
const options = AddToCart.getOptions(product);
if (options.sizes.size > 1 && options.colors.size === 1) {
return ButtonType.SelectSize;
} else if (options.sizes.size === 1 && options.colors.size > 1) {
return ButtonType.SelectColor;
} else {
return ButtonType.Options;
}
},
getOptions: (product) => {
const colors = new Set();
const sizes = new Set();
for (const variant of product.vra) {
const color = findVariantOption(variant, COLOR_FACET_NAME);
const size = findVariantOption(variant, SIZE_FACET_NAME);
if (color) colors.add(color);
if (size) sizes.add(size);
}
return {
colors: colors,
sizes: sizes,
};
},
checkFrom: ($gridItem) => {
return $gridItem
.find(".isp_product_price_wrapper")
.text()
?.includes("from");
},
removePrice: ($gridItem) => {
$gridItem.find(".isp_product_price_wrapper").remove();
},
setSoldOut: ($gridItem) => {
const HTML = `
<div class="isp-product-add-to-cart sold-out">
<div class="add-to-cart-text">SOLD OUT</div>
</div>
`;
if ($gridItem.find(".isp_add_to_cart_form").length === 0) {
$gridItem.find(".isp_product_info").after(HTML);
} else {
$gridItem.find(".isp_add_to_cart_form").replaceWith(HTML);
}
},
setAddToCart: (product, $gridItem, text, useFrom) => {
const price = parseFloat(product.p);
const comparePrice = parseFloat(product.p_c);
const fromClass = useFrom ? "from-included" : "";
const compareClass = comparePrice ? "compare-included" : "";
const HTML = `
<div class="isp-product-add-to-cart">
<div class="isp-product-price-wrapper">
<span class="price-container actual ${fromClass} ${compareClass}">$${price.toFixed(2)}</span>
<span class="price-container compare">${comparePrice ? "$" + comparePrice.toFixed(2) : "" }</span>
</div>
<span class="atc-break"/>
<div class="add-to-cart-text">${text}</div>
</div>`;
if ($gridItem.find(".isp_add_to_cart_form").length === 0) {
$gridItem.find(".isp_product_info").after(HTML);
} else {
$gridItem.find(".isp_add_to_cart_form").replaceWith(HTML);
}
$gridItem.find(".isp-product-add-to-cart").click(function () {
AddToCart.addToCartAjax(product, $gridItem.attr("position"));
});
},
setRedirectToProduct: (product, $gridItem, text, useFrom) => {
const price = parseFloat(product.p);
const comparePrice = parseFloat(product.p_c);
const fromClass = useFrom ? "from-included" : "";
const compareClass = comparePrice ? "compare-included" : "";
const HTML = `<a class="isp-product-add-to-cart" href="${product.u}">
<div class="isp-product-price-wrapper">
<span class="price-container actual ${fromClass} ${compareClass}">$${price.toFixed(2)}</span>
<span class="price-container compare">${comparePrice ? "$" + comparePrice.toFixed(2) : ""}</span></div>
<span class="atc-break"/>
<div class="add-to-cart-text">${text}</div>
</a>`;
if ($gridItem.find(".isp_add_to_cart_form").length === 0) {
$gridItem.find(".isp_product_info").after(HTML);
} else {
$gridItem.find(".isp_add_to_cart_form").replaceWith(HTML);
}
},
addToCartAjax: (product, product_position) => {
if (product.vra.length > 2) {
QuickView.create(product);
return;
}
document.body.style.cursor = "wait";
const data = {
id: getFirstVariantID(product),
};
try {
localStorage.setItem("isp_add_to_cart_serp_product_id", product.id);
ispStoreProductPosition(product.id);
} catch (e) {}
$.ajax({
type: "POST",
url: "/cart/add.js",
data,
dataType: "json",
cache: false,
product_id: product.id,
form_id: `form_${product.id}`,
is_quick_view: false,
})
.done(function (data) {
onAddToCartFinish(this.product_id, false);
})
.fail(function (jqXHR, textStatus) {
console.log("error jqXHR: " + jqXHR + " | textStatus: " + textStatus);
})
.always(function () {
$jquery_isp("#" + this.form_id).removeClass("isp_add_to_cart_disable");
});
},
};
</script>