In this tutorial, we show you how to reorganize the placement of your cart upsell item in Shopify without cluttering the top of the cart. This simple adjustment enhances the customer experience while increasing average order value.
Compatible Themes: This code should work on all free Shopify themes (Dawn, Refresh, Craft, Studio, Publisher, Crave, Origin, Taste, Colorblock, Sense, Ride, Spotlight).
Edit settings_schema.json
{
"name": "Cart Re-Position Item",
"settings": [
{
"type": "checkbox",
"id": "enable_reordering",
"label": "Enable Re-ordering",
"default": false
},
{
"type": "text",
"id": "positioned_variant_id",
"label": "Positioned Variant ID",
"placeholder": "Enter Variant ID"
},
{
"type": "select",
"id": "variant_position",
"label": "Variant Position",
"options": [
{ "value": "first", "label": "First" },
{ "value": "last", "label": "Last" }
],
"default": "last"
}
]
}
Edit CartItems class in cart.js
Edit constructor method
this.enableReordering = this.dataset.enableReordering === 'true';
this.positionedVariantId = this.dataset.positionedVariant || null;
this.variantPosition = this.dataset.variantPosition || null;
Edit connectedCallback method
if (this.enableReordering) {
this.reorderCartItemsInDOM();
}
Edit onCartUpdate method
let newHtml = sourceElement.outerHTML;
if (this.enableReordering) {
newHtml = this.reorderCartItems(newHtml);
}
const reorderedElement = new DOMParser()
.parseFromString(newHtml, 'text/html')
.querySelector(selector);
targetElement.replaceWith(reorderedElement);
let newInnerHTML = sourceQty.innerHTML;
if (this.enableReordering) {
newInnerHTML = this.reorderCartItems(newInnerHTML);
}
this.innerHTML = newInnerHTML;
Add new methods
reorderCartItemsInDOM() {
if (!this.positionedVariantId || !this.variantPosition) return;
const cartItems = Array.from(this.querySelectorAll('.cart-item'));
if (!cartItems.length) return;
const itemToReposition = cartItems.find((item) => {
const variantId = item.querySelector('[data-quantity-variant-id]')?.dataset.quantityVariantId;
return variantId === this.positionedVariantId;
});
if (itemToReposition) {
itemToReposition.parentNode.removeChild(itemToReposition);
const container = this.querySelector('tbody');
if (!container) return;
if (this.variantPosition === 'first') {
container.insertBefore(itemToReposition, container.firstChild);
} else if (this.variantPosition === 'last') {
container.appendChild(itemToReposition);
}
}
}
reorderCartItems(html) {
if (!this.positionedVariantId || !this.variantPosition) return html;
const parser = new DOMParser();
const doc = parser.parseFromString(html, 'text/html');
const cartItems = Array.from(doc.querySelectorAll('.cart-item'));
if (!cartItems.length) return html;
const itemToReposition = cartItems.find(item => {
const variantId = item.querySelector('[data-quantity-variant-id]')?.dataset.quantityVariantId;
return variantId === this.positionedVariantId;
});
if (itemToReposition) {
itemToReposition.remove();
const container = doc.querySelector('tbody');
if (!container) return html;
if (this.variantPosition === 'first') {
container.insertBefore(itemToReposition, container.firstChild);
} else {
container.appendChild(itemToReposition);
}
}
return doc.body.innerHTML;
}
Edit cart-items
element in main-cart-items.liquid and cart-drawer-items
cart-drawer.liquid
data-enable-reordering="{{ settings.enable_reordering }}"
data-positioned-variant="{{ settings.positioned_variant_id }}"
data-variant-position="{{ settings.variant_position }}"