After trying numerous different approaches, including the previous answers, this is the only thing I found that worked. The strategy is to set a cookie containing the desired information (in this case the number of items in the cart) on the parent domain, so that it can be accessed by another web site that has the same parent domain.
It requires a custom domain on the Shopify store, i.e. will not work with xxxx.myshopify.com.
Add a new Javascript file (e.g. cart.js
) into the Shopify code Assets:
function extractDomain(host) {
let parts = host.split(".");
parts.shift();
return parts.join(".");
}
function updateCartCountCookie() {
fetch('/cart.json')
.then((data) => {
data.json().then((cart) => {
let myDate = new Date();
myDate.setMonth(myDate.getMonth() + 1);
document.cookie = 'kh_cart_item_count=' + cart.item_count.toString() + ';expires=' + myDate
+ ';domain=.' + extractDomain(location.hostname) + ';path=/';
});
});
}
/*
This event fires after cart changes. This is theme dependent and may need to be different.
*/
document.addEventListener("theme:loading:end", () => {
updateCartCountCookie();
});
/* update on initial load */
document.addEventListener('DOMContentLoaded', () => {
updateCartCountCookie();
}
Include this in your theme template:
<script src="{{ 'cart.js' | asset_url }}" defer></script>
Now the cookie kh_cart_item_count
will be set on the parent domain with the number of items in the cart.
In your external website hosted on a sibling domain add this html snippet wherever you want the cart to appear:
<script>
function getCookieValue(a) {
var b = document.cookie.match('(^|;)\\s*' + a + '\\s*=\\s*([^;]+)');
return b ? b.pop() : '';
}
document.addEventListener("DOMContentLoaded", () => {
let count = getCookieValue("kh_cart_item_count");
let el = document.getElementById("kh-cart-count")
if (el) {
el.innerText = count.toString();
if (!!count && parseInt(count) !== 0)
el.classList.remove("invisible");
}
});
</script>
<style>
</style>
<a href="https://shop.example.com/cart" class="kh-cart-count ml-auto mr-1">
<svg class="icon icon--cart" viewBox="0 0 27 24" role="presentation">
<g transform="translate(0 1)" stroke-width="2" stroke="grey" fill="none" fill-rule="evenodd">
<circle stroke-linecap="square" cx="11" cy="20" r="2"></circle>
<circle stroke-linecap="square" cx="22" cy="20" r="2"></circle>
<path d="M7.31 5h18.27l-1.44 10H9.78L6.22 0H0"></path>
</g>
</svg>
<span id="kh-cart-count" class="kh-cart-count invisible">0</span>
</a>
And add this css in an appropriate css file:
/* shopping cart icon style */
.kh-cart-count {
width: 4rem;
height: 4rem;
display: flex;
justify-content: right;
span {
font-size: 0.8rem;
font-weight: bold;
background: #ff0000;
color: #fff;
padding: 1px 1px 1px;
-webkit-border-radius: 20px;
-moz-border-radius: 20px;
border-radius: 20px;
height: 1.2rem;
width: 1.2rem;
margin-left: 1.5rem;
justify-content: center;
align-items: center;
position: absolute;
}
svg {
width: 2rem;
height: 2rem;
position: absolute;
}
}
This won't automatically update if the website is open in a window when the cart is updated in a different window, but will update on each page refresh (or you could poll it with e.g. window.setInterval(updateCartCount, 10000);
- there is a draft spec for a cookie change event but it's not yet available.)
The result looks like this:
You could obviously extend this to pass other data besides just the cart item count.