Fix dynamic bundles displaying incorrectly in the cart
When using bundles, a single product is typically added to the cart, along with its title, image, price, and contents.
However, dynamically priced bundles behave differently. Instead of adding one bundle product, the system adds the individual products to the cart so the total price can be calculated dynamically.
This can create two issues:
- Customers can edit individual item quantities, which may conflict with bundle rules
- Bundle items lose their grouped presentation and appear as separate products in the cart
To resolve this, you can use custom Liquid code to group bundle items and display them as a single product in the cart.
Before you start
These instructions require custom coding. Custom code is not supported by Recharge per the design and integration policy. Consider working with a developer or Recharge Partner Agency.
Install snippets manually when auto-install fails
Recharge automatically installs two snippets by detecting where cart.items is used in your theme.
However, automatic installation can fail if your theme:
- Uses a non-standard cart rendering method
- Has heavily customized cart logic
- Does not use Liquid to render cart items (for example, uses Jinja or another templating language)
In these cases, you must install the snippets manually. After installation:
- The dynamic bundle appears as a single item in the cart
- Customers cannot edit individual bundle item quantities from the cart
- Bundle contents display as a grouped product
Step 1 - Duplicate your theme
Before making changes:
- In Shopify, go to Online Store and select Themes
- Locate your theme
- Click Actions and select Duplicate
- Open the duplicated theme and click Edit code
Step 2 - Locate your cart file
Find the file responsible for rendering cart items. Common filenames include:
main-cart-items.liquidcart.liquid
Step 3 - Identify the cart items loop
Locate the loop that renders cart items. It typically looks like:
{%- for item in cart.items -%}Step 4 - Add bundle detection logic
Paste the following code before the cart items loop:
{%- assign rc_displayed_bundles = '' -%}
{%- assign rc_bundles = '' -%}
{%- for recharge_cart_item in cart.items -%}
{%- if recharge_cart_item.properties._rc_bundle -%}
{%- unless rc_bundles contains recharge_cart_item.properties._rc_bundle -%}
{%- assign rc_bundles = rc_bundles | append: ',' | append: recharge_cart_item.properties._rc_bundle -%}
{%- endunless -%}
{%- endif -%}
{%- endfor -%}
{%- assign rc_bundles = rc_bundles | remove_first: ',' -%}Step 5 - Render bundle items
Paste the following code inside the cart items loop, immediately after the opening tag:
{%- assign rc_bundle_id = item.properties["_rc_bundle"] -%}
{%- if rc_bundles contains item.properties._rc_bundle -%}
{%- unless rc_displayed_bundles contains item.properties._rc_bundle -%}
{%- assign rc_bundle_price = 0 -%}
{%- assign rc_bundle_original_price = 0 -%}
{%- assign rc_selling_plan_name = '' %}
{%- assign rc_bundle_product = '' -%}
{%- assign rc_bundle_contents = '' -%}
{%- assign rc_bundle_handle = '' -%}
{%- assign rc_bundle_url_to_remove = '/cart/update?' -%}
{%- assign rc_bundle_variant = '' -%}
{%- assign rc_bundle_variant_id = '' -%}
{%- for item in cart.items -%}
{%- if item.properties["_rc_bundle"] == rc_bundle_id -%}
{%- assign rc_bundle_price = rc_bundle_price | plus: item.final_line_price -%}
{%- assign rc_bundle_original_price = rc_bundle_original_price | plus: item.original_line_price -%}
{%- assign rc_bundle_contents = rc_bundle_contents | append: ', ' | append: item.quantity | append: 'x ' | append: item.title -%}
{%- if rc_selling_plan_name.size == 0 -%}
{%- assign rc_selling_plan_name = item.selling_plan_allocation.selling_plan.name -%}
{%- endif -%}
{%- assign rc_bundle_handle = item.properties._rc_bundle_parent -%}
{%- assign rc_bundle_variant_id = item.properties._rc_bundle_variant | plus: 0 -%}
{%- assign rc_bundle_url_to_remove = rc_bundle_url_to_remove | append: 'updates[' | append: item.key | append: ']=0&' -%}
{%- endif -%}
{%- endfor -%}
{%- assign rc_bundle_product = all_products[rc_bundle_handle] -%}
{%- assign rc_bundle_contents = rc_bundle_contents | remove_first: ', ' -%}
{%- assign rc_displayed_bundles = rc_displayed_bundles | append: ',' | append: item.properties._rc_bundle -%}
{%- for variant in rc_bundle_product.variants -%}
{%- if variant.id == rc_bundle_variant_id -%}
{%- assign rc_bundle_variant = variant -%}
{%- endif -%}
{%- endfor -%}
{%- comment -%}
Render bundle item
{%- endcomment -%}
<style>
.rc-bundle-item {
display: flex;
align-items: flex-start;
padding: 20px 0;
}
.rc-bundle-image-wrapper {
width: 150px;
padding-right: 1rem;
}
.rc-bundle-image {
max-width: 100%;
}
.rc-bundle-title {
display: block;
font-weight: bold;
}
.rc-bundle-variant,
.rc-bundle-contents,
.rc-bundle-price,
.rc-bundle-frequency {
display: block;
}
@media screen and (max-width: 749px) {
.rc-bundle-image-wrapper {
width: 33%;
}
.rc-bundle-content {
width: 66%;
}
}
</style>
<tr>
<td colspan="10">
<div class="rc-bundle-item">
<div class="rc-bundle-image-wrapper">
<img class="rc-bundle-image" src="{{ rc_bundle_product.featured_image | image_url: width: 150 }}">
</div>
<div class="rc-bundle-content">
<span class="rc-bundle-title">{{ rc_bundle_product.title }}</span>
{% if rc_bundle_product.variants.size > 1 %}
<span class="rc-bundle-variant">{{ rc_bundle_variant.title }}</span>
{% endif %}
<span class="rc-bundle-contents">Contents: {{ rc_bundle_contents }}</span>
<span class="rc-bundle-price">{{ rc_bundle_price | money }}</span>
<span class="rc-bundle-frequency">{{ rc_selling_plan_name }}</span>
<a href="{{ rc_bundle_url_to_remove }}">Remove</a>
</div>
</div>
</td>
</tr>
{%- comment -%}
End render bundle item
{%- endcomment -%}
{%- endunless -%}
{% continue %}
{%- endif -%}Step 6 (Optional) - Customize the bundle item layout
If you want to further customize the bundle display to match the layout of other items in your cart, you can use the following Liquid variables to control how bundle information is rendered.
| Variable | Description | How to use it |
|---|---|---|
| Bundle title | Your bundle product title | {{ rc_bundle_product.title }} |
| Variant title | The selected variant title | {{ rc_bundle_variant.title }} |
| Bundle image | The bundle product image | {{ rc_bundle_product.featured_image | image_url: width: 300 }} |
| Contents list | A comma-separated list of the product names in the bundle contents | {{ rc_bundle_contents }} |
| Bundle price | The total price of all items in the bundle, including any line-level discounts | {{ rc_bundle_price | money }} |
| Original bundle price | The original bundle price before discounts | {{ rc_bundle_original_price | money }} |
| Selling plan name | The selling plan name (for example, Delivery every 1 week) | {{ rc_selling_plan_name }} |
| Remove URL | A URL to remove the bundle from the cart, similar to line_item.url_to_remove | {{ rc_bundle_url_to_remove }} |
Example
<style>
.rc-bundle-item {
display: flex;
align-items: flex-start;
padding: 20px 0;
}
.rc-bundle-image-wrapper {
width: 150px;
padding-right: 1rem;
}
.rc-bundle-image {
max-width: 100%;
}
.rc-bundle-title {
display: block;
font-weight: bold;
}
.rc-bundle-variant,
.rc-bundle-contents,
.rc-bundle-price,
.rc-bundle-frequency {
display: block;
}
@media screen and (max-width: 749px) {
.rc-bundle-image-wrapper {
width: 33%;
}
.rc-bundle-content {
width: 66%;
}
}
</style>Customize the bundle layout
| Variable | Description |
|---|---|
{{ rc_bundle_product.title }} | Bundle product title |
{{ rc_bundle_variant.title }} | Selected variant title |
{{ rc_bundle_product.featured_image | image_url: width: 300 }} | Bundle image |
{{ rc_bundle_contents }} | Bundle contents |
{{ rc_bundle_price | money }} | Total bundle price |
{{ rc_bundle_original_price | money }} | Original price |
{{ rc_selling_plan_name }} | Selling plan |
{{ rc_bundle_url_to_remove }} | Remove URL |
Step 7 - Publish your duplicated theme
- Preview your duplicated theme
- Confirm the bundle displays as a single item
- Confirm customers cannot edit individual items
- Publish your theme when ready
Updated about 21 hours ago
