Create subscription bundling with Shopify Checkout Integration
Note
This guide is specifically for custom bundling solutions, not the Recharge Bundles feature. For the Recharge Bundles feature review the Help Center guide.

You can let customers bundle subscriptions with Recharge, allowing them to "build-a-box," mixing and matching different products. Adding this feature can help increase average order value and annual revenue, move inventory, and provide a better customer experience.
This guide will walk you through the steps for creating bundling functionality on a store using custom HTML, JavaScript, and liquid. The final portion of the guide will walk you through making the necessary changes within the Recharge Theme Engine.
Prerequisites
- Shopify Dawn theme
- This guide uses the Recharge Theme Engine, which is only available on the Recharge Pro plan. Contact us to upgrade your plan.
Key concepts
- This example features a customizable 12-pack of soda, where customers can choose which twelve individual cans of soda they’d like to include in their pack.
- Each distinct bundle option is set up as a separate SKU in Shopify. Each bundle option is a different variant (flavor) of an overarching product.
- When a customer adds the selected bundle to the cart, 12 line items are added to the cart: one for each item in the bundle.
- In order to tie the bundle items together, you will create a unique identifier (a bundle ID) and set it as a custom line item property for each item. You will reference this bundle ID when grouping the bundle items together within the Shopify cart and Recharge customer portal.
Note
This guide and the code samples below should serve as an example demonstrating one way to achieve bundling. The following snippets are meant to serve as a reference and are not intended for use in a production environment.
Setup parent subscription product in Shopify
First, you'll need to create a base product in Shopify that will be the "parent" product for the build-a-box. This product will have all six variants, one for each flavor.
- Create a product called "Build-a-Box" in Shopify and add a flavor variant with six options: "Apple," "Cherry," "Cola," "Peach," "Raspberry," and "Vanilla". The total box price is $24, therefore set each individual
variant price to $2. When a customer adds twelve flavors to their bundle, the total will equal $24.

Create the product in Recharge
After you've created the bundle product and variants in Shopify, you will need to add the product to Recharge.
- Within Recharge, navigate to Products > Add Products and select the "Build-a-box" product.
- Select the subscription type you’d like to offer, then add a discount, order frequency,
and any other subscription options and save.
Adding an active product to Recharge
You can only add an active product to Recharge. If you want to add a hidden product, make the product active in Shopify, add it to Recharge, then set it back to inactive.
Build a product display page in Shopify
Now that the product is configured in Shopify and Recharge, next you will edit the
Shopify theme files to create a custom product page template.
Creating a new product display template
This template will display each
bundle option and allow customers to choose which 12 flavors they’d like in their bundle.
- Create a new section called
product-bundle.liquid
. - Copy the contents of the
main-product.liquid
file and paste them into the new
product-bundle.liquid
section. You'll use this as a base for the new product display section. - Create a new JSON product template called
product.bundle.json
. - Copy the contents of the
product.json
template and paste them into the new
product.bundle.json
template. You'll use this as a base for the new JSON required to build the new template. - Update the section to point to this newly created product bundle file by
updating the sections.main.type value to ‘product-bundle’.

Note
Set the
show_dynamic_checkout
buy button setting tofalse
. You don’t want users to be able to use
other dynamic buy buttons outside of the add-to-cart button on the product page.
- Finally, update the product template in Shopify to use the
bundle
file.

Update liquid and HTML
Now that you've created the framework for a new product display page, it's time to add the new liquid and HTML to power the bundle product page. If you aren’t familiar with editing Shopify themes, check out Shopify’s guide for more information.
Create minimum and maximum count variables
These two variables represent the minimum and maximum counts the JavaScript functions will reference to manipulate the DOM when users add/remove items to their bundle, then add the bundle to cart.
{% assign bundle_min = 0 %}
{% assign bundle_max = 12 %}
Grid layout
- Structure the bundle options in a grid format with a plus and minus button for each option to allow customers to and or remove items from the bundle.
- Create the following key
div
classes on the page:- bundle - This class acts as a container for the variant grid. It will also act as the top-level item for most of the DOM traversal contained in the script.
- bundle-grid - This class holds data attributes for the minimum and maximum variables. You will use these values in the script functions to maintain constraint integrity when the user is clicking the plus and
minus buttons, as well as to determine when the user should be allowed to add the bundle to the cart. - bundle-item - This class represents each individual variant that is part of
the grid matrix. It holds data attributes forvariant_id
andquantity
. These two data attributes will be used per variant when you add the bundle to the cart to determine the quantity of each variant. - bundle-item-selector - This class represents the controls the user can interact with for each variant (i.e. the plus and minus buttons). There is also a quantity item within this
div
that will visually show the user how
much of this variant is currently selected.
Product information container
- Use the standard product information container in the Dawn theme with some adjustments.
- Price - Display the full bundle price rather than just one variant price by removing the content in the price
div
and adding thebundle_price
class. TheupdatePrice()
function in the next section will target this element and dynamically update the price as bundle items are selected. - Variant selector- You need to remove the variant selector section, because users will select variants in the custom bundle grid.
- Add to cart form - Use the standard Dawn add-to-cart form and add
id=‘bundle-add-to-cart‘
to the button element so the script can target this element.
- Price - Display the full bundle price rather than just one variant price by removing the content in the price
Full product page code
{% assign bundle_min = 0 %}
{% assign bundle_max = 12 %}
<link rel="stylesheet" href="{{ 'component-cart-notification.css' | asset_url }}" media="print" onload="this.media='all'">
<link rel="stylesheet" href="{{ 'component-deferred-media.css' | asset_url }}" media="print" onload="this.media='all'">
<section class="page-width">
<div class="product grid bundle grid--1-col {% if product.media.size > 0 %}grid--2-col-tablet{% else %}product--no-media{% endif %}">
<div class="grid__item product__media-wrapper">
<slider-component class="slider-mobile-gutter">
<div class="grid bundle-grid" data-bundle-min="{{ bundle_min }}" data-bundle-max="{{ bundle_max }}" data-subscription-price="{{ bundle_subscription_price }}" data-onetime-price="{{ bundle_onetime_price }}">
{% for variant in product.variants %}
<div class="grid__item bundle-product-grid-item">
<div class="grid bundle-item" data-variant-id="{{ variant.id }}" data-qty="0">
<img src="{{ variant.image.src | img_url: '200x200' }}" alt="{{ variant.title }}" class="bundle_img">
<div class="h3">{{ variant.title }}</div>
{% if variant.available == false %}
<span class="h6 block">Out of stock</span>
{% else %}
<div class="bundle-item-selector">
<span class="minus">
<button class="btn" disabled>-</button>
</span>
<span class="bundle_quantity">0</span>
<span class="plus">
<button class="btn">+</button>
</span>
</div>
{% endif %}
</div>
</div>
{% endfor %}
</div>
</slider-component>
</div>
<div class="product__info-wrapper grid__item">
<div id="ProductInfo-{{ section.id }}" class="product__info-container{% if
section.settings.enable_sticky_info %} product__info-container--sticky{% endif %}">
{%- assign product_form_id = 'product-form-' | append: section.id -%}
{%- for block in section.blocks -%}
{%- case block.type -%}
{%- when '@app' -%}
{% render block %}
{%- when 'text' -%}
<p class="product__text{% if block.settings.text_style == 'uppercase' %}
caption-with-letter-spacing{% elsif block.settings.text_style == 'subtitle' %} subtitle{% endif %}">
{{ - block.settings.text - }}
</p>
{%- when 'title' -%}
<h1 class="product__title">
{{ product.title | escape }}
</h1>
{%- when 'price' -%}
<div class="no-js-hidden bundle-price price--large" id="price-{{ section.id }}"></div>
<div class="bundle-qty">
Items:
<span class="current-qty">0</span>
of
{{ bundle_max }}
</div>
{%- form 'product', product, data-productid: product.id, id: 'product-form-installment',
class: 'installment caption-large' -%}
<input type="hidden" name="id" data-productid="{{ product.id }}" value="{{ product.selected_or_first_available_variant.id }}">
{{ form | payment_terms }}{%- endform -%}
{%- when 'description' -%}
{%- if product.description != blank -%}
<div class="product__description rte">
{{ product.description }}
</div>
{%- endif -%}
…
{%- when 'buy_buttons' -%}
<product-form class="product-form">
{%- form 'product', product, data-productid: product.id, id: product_form_id, class:
'form', novalidate: 'novalidate', data-type: 'add-to-cart-form' -%}
<input type="hidden" name="id" data-productid="{{ product.id }}" value="{{ product.selected_or_first_available_variant.id }}">
<div class="product-form__buttons bundle-add-to-cart">
<button id="bundle-add-to-cart" type="submit" name="add" class="product-form__submit button button--full-width {% if
block.settings.show_dynamic_checkout and product.selling_plan_groups == empty %}button--secondary{% else %}button--primary{% endif %}" disabled>
{%- if product.selected_or_first_available_variant.available -%}
{{ 'products.product.add_to_cart' | t }}
{%- else -%}
{{ 'products.product.sold_out' | t }}
{%- endif -%}
</button>
</div>
{%- endform -%}
</product-form</div> {%- endcase -%} {%- endfor -%}
</div>
</div>
Add script for bundling page to Shopify theme
The next step is creating the JavaScript file that will contain the logic for the bundling functionality. Create a new file in the assets directory called bundle.js
. View the commented code below for an explanation of how each function is used.
Full product page JS
Bundle = {
Defaults: {
// Convenience functions to reference various important divs within the build.
// If you structure your HTML differently than our example build, you can alter these
// functions to reference the correct divs.
getBundleDiv: function () {
return $(".bundle");
},
getBundleGridDiv: function () {
return Bundle.Defaults.getBundleDiv().find(".bundle-grid");
},
getBundleDetailsDiv: function () {
return Bundle.Defaults.getBundleDiv().find(".bundle-details");
},
getAddToCartDiv: function () {
return $("#bundle-add-to-cart");
},
getWidget: function () {
return ReChargeWidget.getWidgets()[0];
},
},
Utils: {
// Utilty functions used throughout the rest of the build
generateGuid: function () {
// Generates a unique guid to be used for the bundle_id
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(
/[xy]/g,
function (c) {
var r = (Math.random() * 16) | 0,
v = c == "x" ? r : (r & 0x3) | 0x8;
return v.toString(16);
}
);
},
calculateBundleQuantity: function ($bundle) {
// Calculates the total number of items selected on the page.
// Will loop through all grid items and sum up the total bundle
// quantity based on the data-qty attribute of each variant.
// 1.) $bundle = top level bundle div of the grid matrix
var bundle_qty = 0;
$bundle.find(".bundle-item").each(function () {
bundle_qty += Number($(this).attr("data-qty"));
});
return bundle_qty;
},
isSubscription: function (widget) {
// Determines whether the user has selected the One-time purchase
// or Subscribe and Save option on the ReCharge widget
return widget.subscriptionActive == true;
},
updateBundleQuantity: function ($item, increment) {
// Main function to handle quantity manipulation. Pass in the grid
// item along with the quantity to increment or decrement. Then it will
// determine the current and new item/bundle quantities. Then it checks
// constraints, and if valid, update all necessary data attributes,
// interface output, and enable/disable any buttons.
// 1.) $item = the clicked plus or minus .bundle-item parent div
// 2.) increment = the amount to increase or decrease the quantity
// Get bundle parent reference and min/max numbers
var $bundle = $item.closest(".bundle-grid");
var bundle_min = Number($bundle.attr("data-bundle-min"));
var bundle_max = Number($bundle.attr("data-bundle-max"));
// Calculate current item and bundle quantity
var bundle_qty = Bundle.Utils.calculateBundleQuantity($bundle);
var item_qty = Number($item.attr("data-qty"));
// Calculate the new bundle and item quantities with the increment added
var new_bundle_qty = bundle_qty + increment;
var new_item_qty = item_qty + increment;
// Check constraints to make sure we can perform the action
if (
Bundle.Constraints.isItemGreaterThanZero(new_item_qty) &&
Bundle.Constraints.isBundleGreaterThanMin(new_bundle_qty, bundle_min) &&
Bundle.Constraints.isBundleLessThanMax(new_bundle_qty, bundle_max)
) {
//Update quantities
$item.attr("data-qty", new_item_qty);
$item.find(".bundle_quantity").html(new_item_qty);
$(".current-qty").html(new_bundle_qty);
//Toggle the Add to Cart Button if max items is reached
var is_disabled = Bundle.Constraints.isBundleEqualMax(
new_bundle_qty,
bundle_max
)
? false
: true;
Bundle.Defaults.getAddToCartDiv().prop("disabled", is_disabled);
//Update plus/minus button's disabled property
$bundle.find(".bundle-item").each(function () {
var item_qty = $(this).attr("data-qty");
var is_disabled = Bundle.Constraints.isBundleEqualParam(
new_bundle_qty,
bundle_max
)
? true
: false;
$(this).find(".plus").find(".btn").prop("disabled", is_disabled);
var is_disabled =
Bundle.Constraints.isBundleEqualParam(new_bundle_qty, bundle_min) ||
Bundle.Constraints.isBundleEqualParam(item_qty, 0)
? true
: false;
$(this).find(".minus").find(".btn").prop("disabled", is_disabled);
});
}
},
updatePrice: function () {
var widget = Bundle.Defaults.getWidget();
var is_subscription = Bundle.Utils.isSubscription(widget);
var $bundle = Bundle.Defaults.getBundleGridDiv();
var bundle_subscription_price = $bundle.attr("data-subscription-price");
var bundle_onetime_price = $bundle.attr("data-onetime-price");
//If subscription option is clicked, display discounted subscription price
//Otherwise, display full bundle price
if (is_subscription) {
$(".bundle-price").html(bundle_subscription_price);
} else {
$(".bundle-price").html(bundle_onetime_price);
}
},
},
Constraints: {
// Requirement functions to determine whether the user is
// performing an action that is forbidden
isItemGreaterThanZero: function (qty) {
// Check that the item quantity doesn't fall below zero
// 1.) qty = item quantity of the variant
if (qty < 0) {
console.log("Item quantity cannot be less than 0.");
return false;
}
return true;
},
isBundleGreaterThanMin: function (qty, min) {
// Check that the bundle quantity doesn't fall below the minimum quantity
// 1.) qty = total bundle quantity of the page
// 2.) min = minimum value the bundle quantity can't fall below
if (qty < min) {
console.log("Quantity cannot be less than the minimum.");
return false;
}
return true;
},
isBundleLessThanMax: function (qty, max) {
// Check that the bundle quantity doesn't go above the maximum quantity
// 1.) qty = total bundle quantity of the page
// 2.) max = maximum value the bundle quantity can't rise above
if (qty > max) {
console.log("Quantity cannot be greater than maximum.");
return false;
}
return true;
},
isBundleEqualMax: function (qty, max) {
// Check that the bundle quantity is equal to the maximum quantity
// 1.) qty = total bundle quantity of the page
// 2.) max = maximum value the bundle quantity can't rise above
return qty == max ? true : false;
},
isBundleEqualParam: function (qty, param) {
// Check that the bundle quantity is equal to param
// 1.) qty = total bundle quantity of the page
// 2.) param = value to compare qty against
return qty == param ? true : false;
},
},
Cart: {
// Functions used when adding the bundle to the cart and removing a bundle from the cart
processAddToCart: function () {
// Top level function tied to the Add to Cart button.
// Function will check constraints to make sure we can
// add the bundle to the cart, then it will generate
// the cart array and make the AJAX call to Shopify's API.
// Once added to cart, we redirect to the /cart page.
// Get bundle parent, bundle max value, and total bundle quantity values
var $bundle = Bundle.Defaults.getBundleGridDiv();
var qty = Bundle.Utils.calculateBundleQuantity($bundle);
var bundle_max = Number($bundle.attr("data-bundle-max"));
// Ensure we can process the cart, and if not, break out of function
if (!Bundle.Constraints.isBundleEqualMax(qty, bundle_max)) {
console.log(
"Cannot process Add to Cart. Qty does not equal max total."
);
return;
}
//Generate the product array to pass to AJAX call
var widget = Bundle.Defaults.getWidget();
var items = Bundle.Cart.generateCart($bundle, widget);
// Ensure there are items to add to cart, and if so, make
// API call and redirect to /cart page
if (items.length > 0) {
Bundle.Cart.processToCart(items);
} else {
console.log("No items available to add to cart.");
}
},
generateCart: function ($bundle, widget) {
// Check that the bundle quantity is equal to param
// 1.) $bundle = top level bundle div of the grid matrix
// 2.) widget = the ReCharge widget object tied to the page
var cart = [];
var is_subscription = Bundle.Utils.isSubscription(widget);
// bundle_id that we will pass to each product object as a
// line item property to associate them to this bundle
var bundle_id = Bundle.Utils.generateGuid();
// Determine whether the user has the One-time purchase or
// Subscribe & Save purchase type option selected. If Subscribe
// & Save, generate the shipping interval unit_type and frequency
// that are passed through on ReCharge orders.
if (is_subscription) {
var selling_plan = widget.state.sellingPlanId;
}
// Loop through each product grid item
$bundle.find(".bundle-item").each(function () {
// If item's quantity is greater than 0, add
// to the cart array
var qty = $(this).attr("data-qty");
if (Number(qty) > 0) {
var variant_id = $(this).attr("data-variant-id");
// Pass the variant_id, quantity, and bundle_id
// for each grid item we process
var item = {
id: variant_id,
quantity: qty,
properties: {
bundle_id: bundle_id,
},
};
// If this is a Subscribe & Save bundle, pass in the
// ReCharge properties too
if (is_subscription) {
item["selling_plan"] = selling_plan;
}
cart.push(item);
}
});
return cart;
},
processToCart: function (items) {
// Makes API call to add bundle items to cart. If the
// call is successful, redirect to /cart page. If error,
// display the error to the console.
// 1.) items = the product array to be passed to the Shopify
// API. Bundle.Cart.generateCart() function builds this array.
$.ajax({
type: "POST",
url: "/cart/add.js",
data: {
items: items,
},
dataType: "json",
success: function () {
window.location.href = "/cart";
},
error: function (jqXHR, text_status, error_thrown) {
console.log(text_status, error_thrown);
},
});
},
removeBundleItems: function (bundle_id) {
// Removes all bundle items from cart when user clicks remove on cart page
// Get current cart contents
jQuery.getJSON("/cart.js", function (cart) {
// Create new updates object to send to cart update AJAX call
// Loop through each cart item
// If the item's bundle id matches the id passed in,
// add the cart item key along with quantity of 0 to the data object
let bundle_items = [];
let qty = 0;
let data = { updates: {} };
cart.items.forEach((item, i) => {
if (
item.properties.bundle_id &&
item.properties.bundle_id == bundle_id
) {
data.updates[item.key] = 0;
}
});
// API call to update the cart contents and set the bundle item quantities to 0
$.ajax({
type: "POST",
url: "/cart/update.js",
data: data,
dataType: "json",
success: function () {
window.location.href = "/cart";
},
});
});
},
},
init: function () {
// Initialization function to register all click handlers
// Registers each grid item's minus button
$("body").on("click", ".bundle .minus", function () {
var item = $(this).closest(".bundle-item");
Bundle.Utils.updateBundleQuantity(item, -1);
});
// Registers each grid item's plus button
$("body").on("click", ".bundle .plus", function () {
var item = $(this).closest(".bundle-item");
Bundle.Utils.updateBundleQuantity(item, 1);
});
// Registers the page's Add to Cart button
$("body").on("click", "#bundle-add-to-cart", function () {
event.preventDefault();
Bundle.Cart.processAddToCart();
});
// Registers function to handle price change when user changes subscription vs one-time
$("body").on("change", ".rc-widget input", function () {
Bundle.Utils.updatePrice();
});
// Registers each cart bundle item's remove button
$("body").on("click", ".cart__remove-bundle", function () {
var bundle_id = $(this)
.closest(".cart__remove-bundle")
.attr("data-bundle-id");
Bundle.Cart.removeBundleItems(bundle_id);
});
},
};
// Call the init() function to register click handlers
Bundle.init();
Updating the cart page
Cart
With the standard cart page, the customer would see all twelve variants listed out separately
and be able to adjust the quantity of each. In this step, bundle the items together on the cart page and add functionality to remove the bundle as a whole and restrict the ability to remove individual variants.
This example uses the existing structure in the main-cart-items.liquid
file, however, you’ll render an adjusted cart item snippet if the item is a part of a bundle.
Key concepts
- Bundles_displayed: In order to keep track of which bundles are already displayed, begin by creating a blank liquid variable,
bundles_displayed
. As you render each bundle on the cart page, you will add bundle IDs to this variable.
{% assign bundles_displayed = '' | split:',' %}
- Add logic to cart loop - Within the cart item table, the existing code loops through each
item in the cart to display a new row. Add the following conditional statements to this existing loop.- If the item is a part of a bundle (i.e. if it has a
bundle_id line
item property),
check to see if the bundle has already been displayed (i.e. check if the ID is in thebundles_displayed
list). - If it hasn’t been displayed, append it to the
bundles_displayed
list and
render a new liquid file,cart-item-bundle.liquid
. - If the item is not a part of a bundle, display the standard cart item row
found in themain-cart-items.liquid
file.
- If the item is a part of a bundle (i.e. if it has a
{%- for item in cart.items -%}
{%- if item.properties['bundle_id'] -%}
{%- unless bundles_displayed contains item.properties['bundle_id'] -%}
{%- assign bundles_displayed = item.properties['bundle_id'] | concat: bundles_displayed -%}
{%- render 'cart-item-bundle', item: item, cart: cart, current_bundle_id:
item.properties['bundle_id'] -%}
{%- endunless -%}
{%- else -%}
Create a new bundle cart item snippet
Create a new snippet called cart-item-bundle.liquid
, and copy/paste the table row
HTML from the main cart items file, making the following adjustments.
- Update the image - Because you are displaying the main bundle image rather than the
individual variant images, update the code to display the main Shopify product
image.
<img class="cart-item__image" src="{{ item.image | img_url: '150x' }}" alt="{{ item.image.alt | escape }}" loading="lazy" width="75" height="{{ 75 | divided_by: item.image.aspect_ratio | ceil }}">
- Display all variant titles and quantities - To show the contents of the bundle, replace
the existing variant loop,{%- for option in item.options_with_values -%}
, with the
following code which loops through the cart items and renders the variant titles and
quantities.
{%- for item in cart.items -%}
{%- if item.properties['bundle_id'] == current_bundle_id -%}
<div class="product-option">
<dt>{{ item.variant.title }}:
</dt>
<dd>{{ item.quantity }}</dd>
</div>
{%- endif -%}
{%- endfor -%}
- Hide the
bundle_id
line item property Hide thebundle_id
, as it isn’t
relevant to the customer.
{%- if property.last != blank and property_first_char != '_' and property.first != 'bundle_id' -%}
- Update the price - Display the total bundle price, rather than just the price of
one variant. Update the price sections in this snippet. Define a newbundle_price
variable set to0
and loop through each cart item. If the item is in the bundle, add the price to thebundle_price
variable. Rather than creating a new loop, add the liquid math filter to the loop in the
"Display all variant titles and quantities" section above. Update each price section with this new bundle_price variable.
{% assign bundle_price = 0 %}
...
{%- for item in cart.items -%}
{%- if item.properties['bundle_id'] == current_bundle_id -%}
{%- assign bundle_price = item.price | times: item.quantity | plus: bundle_price -%}
<div class="product-option">
<dt>{{ item.variant.title }}:
</dt>
<dd>{{ item.quantity }}</dd>
</div>
{%- endif -%}
{%- endfor -%}
...
<span class="price price--end">
{{ bundle_price | money }}
</span>
- Remove ability to update quantity - You don’t want customers to update the
quantity for bundles, because the bundle logic is only set on the product page. Replace the quantity input element with the following.
<input class="quantity__input" value="1" readonly>
- Update the cart remove button - When a customer clicks the remove button on a bundle
item, you must remove all of the bundle's contents. Add a new data attribute on
the element that contains the current bundle ID, so the function can identify which items to remove.
<cart-remove-button class="cart__remove-bundle" data-bundle-id="{{ current_bundle_id }}">
<a href="{{ item.url_to_remove }}" class="button button--tertiary" aria-label="{{ 'sections.cart.remove_title' | t: title: item.title }}">
{% render 'icon-remove' %}
</a>
</cart-remove-button>
Add a script to remove all bundle items
You need a function and event listener to handle the removal of all bundle items when a customer clicks the "remove" button on the cart page. Add the following items code to the existing bundle.js
file:
Bundle.Cart.removeBundleItems()
- Add a new function to the cart object that
accepts thebundle_id
of the bundle that should be removed from cart. Get the current cart contents, add the items that make up the current bundle to a data object, and make an AJAX call to remove these items from the cart. Note that you should use the Shopify item key in the updates object rather than the variant ID to ensure you are removing the correct variant associated with the bundle ID.
removeBundleItems : function (bundle_id) {
// Removes all bundle items from cart when user clicks remove on cart page
// Get current cart contents
jQuery.getJSON('/cart.js', function (cart) {
// Create the data object for the cart update AJAX call
// Loop through each cart item
// If the item's bundle id matches the id passed in, add the
// cart item key along with a quantity of 0 to the data object
let bundle_items = [];
let qty = 0;
let data = {
updates: {}
};
cart
.items
.forEach((item, i) => {
if (item.properties.bundle_id && item.properties.bundle_id == bundle_id) {
data.updates[item.key] = 0;
}
})
// API call to update the cart contents and set the
// bundle item quantities to 0
$
.ajax({
type: 'POST',
url: '/cart/update.js',
data: data,
dataType: 'json',
success: function () {
window.location.href = '/cart';
}
});
});
}
- Event listener on cart remove button - Add a new event listener to trigger the
Bundle.Cart.removeBundleItems(bundle_id)
function when a customer clicks the cart remove button on a bundle item.
// Registers each cart bundle item's remove button
$('body').on('click', '.cart__remove-bundle', function () {
var bundle_id = $(this).closest('.cart__remove-bundle').attr('data-bundle-id');
Bundle.Cart.removeBundleItems(bundle_id);
});
- Update event listener in
cart.js
- Because you've added an event listener for the bundle remove button, update the existing cart item removal event listener in thecart.js
file. Add anif
statement to only perform the action if it’s a non-bundle item.
class CartRemoveButton extends HTMLElement {
constructor() {
super();
this.addEventListener("click", (event) => {
event.preventDefault();
if (this.dataset.index) {
this.closest("cart-items").updateQuantity(this.dataset.index, 0);
}
});
}
}
Updated about 1 year ago