The script below shows how to add a sold out badge in Shopify
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<script>
var ispQuickShopProducts = {};
var flcktQuickShopGallery;
var __isp_options = __isp_options || {};
__isp_options.isp_serp_with_product_attributes = 1;
__isp_options.isp_serp_callback = function (data) {
$jquery_isp( ".isp_grid_product" ).each(function( index ) {
// attributes for quickshop functionality
let $this = $jquery_isp(this);
const isp_id = $this.attr('product_id'),
product = ISP_PRODUCTS[isp_id];
if ( !$this.hasClass('readyForQuickshop') ) {
$jquery_isp.ajax({
dataType: 'json',
url: (product.u).split('?variant=')[0] + '.js',
success: function(p){
let imagesString = '';
if (p.media) {
p.media.forEach(function(e, i){
if ( i > 0 ) imagesString += '~'
imagesString += e.src.replace('https:','');
imagesString += '^';
imagesString += e.alt;
imagesString += '^';
imagesString += e.id;
});
}
ispQuickShopProducts[isp_id] = {
'handle': p.handle,
'id': p.id, // another ID?
'singleVariant': p.variants.length > 0 ? false : true,
'url': p.url,
'title': p.title,
'fullDescription': p.description,
'regularDescription': shorten($jquery_isp(p.description).text(), 300).replace('Description', '')
.replace('Dimensions', '').replace('Details', '').replace('Specs', '').replace('Shipping', '').replace('Size', ''),
'collectionHandles': 'all',
'images': imagesString,
'json': p,
'isp_id': isp_id
}
function shorten(str, maxLen, separator = ' ') {
if (str.length <= maxLen) return str;
return str.substr(0, str.lastIndexOf(separator, maxLen));
}
let swatchesHTML = '';
p.options.forEach(function(e,i){
const name = e.name,
nameLowerCase = name.toLowerCase(),
position = e.position,
values = e.values,
id = p.id;
swatchesHTML += `<div class="swatch clearfix" data-option-index="${ i }">`
swatchesHTML += `<div class="option_title">${ name }</div>`;
e.values.forEach(function(value, index){
const valueLowerCase = value.toLowerCase(),
valueHandled = valueLowerCase.replace(' ', '-');
const findFirst = p.variants.find((e)=>e.options.includes(value))
swatchesHTML +=
`<input id="swatch-${ i }-${ valueLowerCase }-${ id }-collection-template"
type="radio" name="option-${ i }"
value="${ value }" ${ index == 0 ? 'checked=""' : ''}
>`;
swatchesHTML +=
`<div data-value="${ value }"
data-id="${ findFirst ? findFirst.id : '' }"
class="swatch-element ${ nameLowerCase } ${ valueHandled }-swatch
"> <!-- ${ findFirst ? 'available' : 'soldout' } -->
${ name === 'Color' ? '<div class="tooltip">'+ value +'</div>' : '' }
<label for="swatch-${ i }-${ valueLowerCase }-${ id }-collection-template"
style="${ name === 'Color' ? 'background-image: url(https://cdn.shopify.com/s/files/1/0169/1192/5348/t/39/assets/'+ valueHandled +'_50x.png); background-color: '+ valueHandled : '' }">
${ name !== 'Color' ? value : ''}
<img class="crossed-out" src="//cdn.shopify.com/s/files/1/0169/1192/5348/t/39/assets/soldout.png">
</label>
</div>`
})
swatchesHTML += `</div>`
})
function optionsHTML() {
let html = '';
p.variants.forEach(function(e,i){
const id = e.id,
title = e.title,
sku = e.sku;
html += `<option value="${ id }" data-sku="${ sku }">${ title }</option>`
})
return html
}
let $info = $jquery_isp(`<div class="info">
<span class="quick_shop ss-icon" onclick="ispQuickShop.click(${ isp_id })">Quick View</span>
<div class="quickshop-forms__container js-quickshop-forms__container js-quickshop-forms--${ p.id }">
<div class="clearfix product_form init smart-payment-button--true product_form_options product_form--swatches"
id="product-form-${ p.id }"
data-product-form
data-money-format="${{amount}}"
data-shop-currency="USD"
data-select-id="product-select-${ p.id }collection-template"
data-enable-state="false"
data-product="${ JSON.stringify(p).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """) }"
data-variant-inventory=""
data-product-id="${ p.id }"
>
<form method="post" action="/cart/add" id="product_form_${ p.id }" accept-charset="UTF-8" class="shopify-product-form" enctype="multipart/form-data">
<input type="hidden" name="form_type" value="product">
<input type="hidden" name="utf8" value="✓">
<div class="select">
<select id="product-select-${ p.id }collection-template" name="id" class="multi_select">
${ optionsHTML() }
</select>
</div>
<div class="swatch_options">
${ swatchesHTML }
</div>
<div class="purchase-details">
<div class="purchase-details__quantity product-quantity-box">
<label for="quantity">Qty</label>
<span class="ss-icon product-minus js-change-quantity" data-func="minus"><span class="icon-minus"></span></span> <input type="number" min="1" size="2" class="quantity" name="quantity" id="quantity" value="1"> <span class="ss-icon product-plus js-change-quantity" data-func="plus"><span class="icon-plus"></span></span></div> <div class="purchase-details__buttons purchase-details__spb--true">
<button type="submit" name="add" class="action_button add_to_cart" data-label="Add to Cart"> <span class="text">Add to Cart</span> <svg x="0px" y="0px" width="32px" height="32px" viewBox="0 0 32 32" class="checkmark"> <path fill="none" stroke-width="2" stroke-linecap="square" stroke-miterlimit="10" d="M9,17l3.9,3.9c0.1,0.1,0.2,0.1,0.3,0L23,11"></path></svg></button>
<!-- TODO removed id="shopify-svg-symbols" -->
{{ form | payment_button }}
</div>
</div>
</div>`);
$info.appendTo( $this.find('.isp_product_image_wrapper') );
$('<div class="thumbnail-overlay"></div>').insertBefore( $info );
//$span.wrap('</div>');
},
cache:false,
});
}
$this.addClass('readyForQuickshop');
}); // end each product
};
const ispQuickShop = {
click: (id) => {
if ( $jquery_isp('.js-quick-shop').length === 0 ) $jquery_isp('body').append(
`<div class="js-quick-shop">
<div class="quick-shop js-product_section">
<div class="quick-shop__container container section js-quick-shop-container">
<div class="quick-shop__gallery eight columns gallery-wrap js-gallery-wrap bottom-thumbnails gallery-arrows--true">
<div class="gallery product_gallery js-gallery-modal
product--gallery
transparentBackground--false
slideshow_animation--slide" data-zoom="false"></div>
<div class="gallery product_gallery_nav js-gallery-carousel product_gallery_nav--bottom-thumbnails"></div>
</div>
<div class="quick-shop__text-wrap six columns text-modal-wrap"> <!--Product banners inserted with JS - populateProductInfo() --> <div class="sale_banner_product js-sale-banner"></div> <div class="new_banner_product js-new-banner"></div> <div class="new_banner_product js-pre-order-banner"></div> <h3 class="quick-shop__title js-product-title"></h3> <div class="feature_divider"></div> <!-- Yotpo Star Rating | quick view > --> <div class="yotpo bottomLine" data-product-id="" data-yotpo-element-id="25"> <div class="yotpo-display-wrapper" style="visibility: hidden;"> <div class="standalone-bottomline" data-source="default" tabindex="-1"> <div class="yotpo-bottomline pull-left star-clickable" tabindex="0"> <span class="yotpo-stars"> <span class="yotpo-icon yotpo-icon-star rating-star pull-left"></span><span class="yotpo-icon yotpo-icon-star rating-star pull-left"></span><span class="yotpo-icon yotpo-icon-star rating-star pull-left"></span><span class="yotpo-icon yotpo-icon-star rating-star pull-left"></span><span class="yotpo-icon yotpo-icon-star rating-star pull-left"></span><span class="sr-only">4.8 star rating</span> </span> <a href="javascript:void(0)" class="text-m" aria-label="2838 reviews" tabindex="-1">2838 Reviews</a> <div class="yotpo-clr"></div> </div> <div class="yotpo-clr"></div> </div> <div class="yotpo-clr"></div> </div></div> <style>
.yotpo .pull-left {
padding-bottom: 5px;
}
.yotpo .text-m {
padding-left: 5px;
}</style> <!-- End of Yotpo --> <p class="modal_price"> <span class="sold_out js-sold-out"></span> <span class="current_price js-current-price"><span class="money"></span></span> <span class="was_price js-was-price"><span class="money"></span></span> <span class="sale savings js-savings"></span></p> <span class="js-product-form"></span> <span class="js-notify-form"></span> <p> <span class="js-regular-description"></span> <span class="js-product-details"></span></p></div>
</div>
</div>
</div>`);
ispQuickShop.init(ispQuickShopProducts[id]);
},
init: (p) => {
console.log('quishop init p')
console.log(p)
const productData = {
handle: p.handle,
product_id: p.id,
single_variant: p.singleVariant,
product_in_collection_url: p.url,
escaped_title: p.title,
details_text: "View full details",
full_description: p.fullDescription,
regular_description: p.regularDescription,
image_array: quickShop.createImageObjects(String(p.images)),
collection_handles: (p.collectionHandles).trim(',').split(','),
money_format: $jquery_isp('body').data('money-format'),
json: p.json,
isp_id: p.isp_id
}
//Find current product and notify forms TODO
const $notifyForm = $('[product_id="'+ p.isp_id +'"]').find('.js-quickshop-forms__container .notify_form');
const $productForm = $('[product_id="'+ p.isp_id +'"]').find('.js-quickshop-forms__container .product_form');
try {
openQuickshop(productData.product_id);
} catch (e) {
let s = document.createElement('script');
s.setAttribute('src', 'https://cdnjs.cloudflare.com/ajax/libs/fancybox/3.5.7/jquery.fancybox.min.js');
document.body.append( s );
s.onload = function(){
console.log('fancybox is loaded');
openQuickshop(productData.product_id);
}
}
function openQuickshop(id) {
$.fancybox.open($('.js-quick-shop'), {
baseClass: 'quick-shop__lightbox product-' + id,
hash: false,
infobar : false,
toolbar: false,
loop: true,
smallBtn : true,
mobile: {
preventCaptionOverlap: false,
toolbar: true,
buttons: [
"close"
]
},
beforeLoad: function(){
quickShop.beforeOpen(productData);
},
afterLoad: function(){
//quickShop.afterContent($productForm, $notifyForm, productData);
ispQuickShop.afterContent($productForm, $notifyForm, productData);
},
beforeClose: function(){
//quickShop.beforeClose(productData);
ispQuickShop.beforeClose(productData, productData.isp_id);
}
})
console.log('created')
}
},
afterContent: ($productForm, $notifyForm, productData) => {
quickShop.retrieveProductInfo(productData);
let prevNext = false;
let draggable = false;
if (productData.image_array.length > 1) {
prevNext = true;
draggable = true;
} else {
prevNext = false;
draggable = false;
}
//Add main gallery
flcktQuickShopGallery = new Flickity( ('.js-gallery-modal'), {
"adaptiveHeight": true,
"wrapAround": "true",
"cellAlign": "left",
"draggable": draggable,
"contain": true,
"imagesLoaded": true,
"lazyLoad": 2,
"pageDots": false,
"dragThreshold": 10,
"arrowShape": arrowSize
});
//Copy form data to modal
$('.quick-shop__lightbox .js-notify-form').append($notifyForm);
$('.quick-shop__lightbox .js-product-form').append($productForm);
//Initiate selectCallback
if($productForm.hasClass("product_form_options") && $productForm.hasClass("viewed") == false) {
//If form hasn't been viewed previously, run OptionSelectors function
new Shopify.OptionSelectors($productForm.data("select-id"),
{
product: $productForm.data("product"),
onVariantSelected: selectCallback,
enableHistoryState: $productForm.data("enable-state")
});
} else {
//If form has been previously viewed, just convert currencies
}
//Link sold out options when there is more than one option available (eg. S is selected and Yellow option appears as sold out)
const JSONData = $productForm.data('product');
const productID = productData.section_id;
//const productSection = '.product-' + productID + ' .js-product_section';
const productSection = '.quick-shop js-product_section';
const swatchOptions = $productForm.find('.swatch_options .swatch');
if (swatchOptions.length > 1){
console.log('apply Shopify.linkOptionSelectors')
Shopify.linkOptionSelectors(JSONData, productSection);
}
$('.js-quick-shop select[name="id"]').trigger('change');
utils.initializeTabs();
try {
$('.js-quick-shop .text-modal-wrap iframe[src*=youtube], .js-quick-shop .text-modal-wrap iframe[src*=vimeo]').mediaWrapper({
intrinsic: true
});
} catch (e) {
console.error('mediaWrapper is not initialized?')
}
productPage.productSwatches();
},
beforeClose: (productData, isp_id) => {
const $insertedNotifyForm = $('.quick-shop__lightbox .notify_form');
const $insertedProductForm = $('.quick-shop__lightbox .product_form');
//Copy form data back to product loop and add .viewed
$('[product_id="'+ isp_id +'"] .js-quickshop-forms--'+ productData.product_id).append($insertedProductForm);
$('[product_id="'+ isp_id +'"] .js-quickshop-forms--'+ productData.product_id).append($insertedNotifyForm);
$('[product_id="'+ isp_id +'"] .js-quickshop-forms--'+ productData.product_id +' .product_form').addClass('viewed');
$('[product_id="'+ isp_id +'"] .js-quickshop-forms--'+ productData.product_id +' .notify_form').addClass('viewed');
//Find gallery and carousel
const $gallery = $('.js-gallery-modal');
const $carousel = $('.js-gallery-carousel');
$('.js-gallery-carousel .gallery-cell').off('click');
//Remove image slides from gallery
//$gallery.flickity( 'remove', $('.gallery-cell', $gallery));
flcktQuickShopGallery.remove( document.querySelectorAll('.gallery-cell, .js-gallery-modal') );
//Destroy sliders when modal closes
//$gallery.flickity('destroy');
flcktQuickShopGallery.destroy();
if ($carousel.hasClass('flickity-enabled')){
$carousel.flickity( 'remove', $('.gallery-cell', $carousel) );
$carousel.flickity('destroy');
} else {
$carousel.find('.gallery-cell').remove();
}
const variantPrice = $('.js-current-price .money').text();
$('.js-quick-shop-link[data-id=' + productData.product_id + ']').attr('data-initial-modal-price', variantPrice);
$('.js-current-price, .js-was-price, .js-savings').empty();
}
}
</script>