Default Bundle Template
The main Liquid template file for rendering bundle sections. The template handles two layout types (bundle and bundle_component) and includes loading skeleton states, product cards with variant selectors, pricing, and add-to-cart functionality.
Template Structure
The template is organized into these key sections:- Layout detection — assigns the correct settings based on
config.layout - Bundle component header — collapsible header for the
bundle_componentlayout - Loading skeleton — placeholder UI shown while bundle data loads
- Product cards — image, title, price, variant/option selectors for each product
- Pricing and ATC — total price display and add-to-cart container (component layout only)
Copy
{% assign productComponentTitle = template.translations.productComponentTitle | replace: "{{count}}", bundle.images.length %}
{% if config.layout == 'bundle_component' %}
{% assign setting = template.settings.bundleComponent %}
{% else %}
{% assign setting = template.settings.bundle %}
{% endif %}
{% if config.layout == 'bundle_component' %}
<div class='rk-b-c-head'>
<div class='rk-b-c-h-title'>
<svg width="23" height="25" viewBox="0 0 23 25" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_2869_1890)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.163574 15.9316L11.2747 21.9316L22.3858 15.9316V18.9316L11.2747 24.9316L0.163574 18.9316V15.9316ZM0.163574 9.93164L11.2747 15.9316L22.3858 9.93164V12.9316L11.2747 18.9316L0.163574 12.9316V9.93164ZM11.2747 0.931641L22.3858 6.93164L11.2747 12.9316L0.163574 6.93164L11.2747 0.931641Z" fill="black"/>
</g>
<defs>
<clipPath id="clip0_2869_1890">
<rect width="22.2222" height="24" fill="white" transform="translate(0.163574 0.931641)"/>
</clipPath>
</defs>
</svg>
<span>{{ template.translations.productComponentTitle | replace: '{{count}}', bundle.productComponents.length }}</span>
</div>
<svg class="rk-b-c-cheveron" width="25" height="25" viewBox="0 0 25 25" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.2959 15.9316L12.2959 8.93164L19.2959 15.9316" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</div>
{% endif %}
<div data-rk-bundle-id="{{ bundle.id }}" class="rk-bundle-card">
{% if loading %}
{% if bundle.optionsType == "product" and bundle.bundleType == "custom" %}
<span class="rk-total-product">
{% if config.layout == "bundle" %}
{{ template.translations.bundleSectionTitle | replace: "{{count}}", bundle.productComponents.length }}
{% endif %}
{% if config.layout == "bundle_component" %}
{{ bundle.title }}
{% endif %}
</span>
<div class="rk-bundle-container rk-bundle-{{ bundle.id }}-holder">
{% for component in bundle.productComponents %}
<div class="rk-p-c-container" data-rk-bundle-component-id="{{ product.id }}">
<div class="rk-p-c-product-image-container">
<img
class="rk-p-c-product-image rk-image-{{ product.id }}"
{% if image contains '?' %}
src="{{ component.image }}&width={{ setting.productCard.image.width | default: 110 }} }}&height={{ setting.productCard.image.height | default: 133 }} }}&crop=center&pad_color=121212"
{% else %}
src="{{ component.image }}?width={{ setting.productCard.image.width | default: 110 }} }}&height={{ setting.productCard.image.height | default: 133 }} }}&crop=center&pad_color=121212"
{% endif %}
alt="{{ component.image }} image" />
</div>
<div class="rk-p-c-product-details">
<div class="rk-p-c-head">
<div class="product-title-skeleton skeleton"></div>
<div class="product-price-skeleton skeleton"></div>
</div>
<div class="rk-p-c-footer">
<div class="selector-skeleton skeleton"></div>
</div>
</div>
</div>
{% if forloop.index < products.size %}
<span class="rk-plus" id="rk-plus-{{ forloop.index }}">+</span>
{% endif %}
{% endfor %}
</div>
{% endif %}
{% else %}
{% if bundle.optionsType == "product" and bundle.bundleType == "custom" %}
<div class='rk-bundle-head'>
<span class="rk-total-product">
{% if config.layout == "bundle" %}
{{ template.translations.bundleSectionTitle | replace: "{{count}}", components.length }}
{% endif %}
{% if config.layout == "bundle_component" %}
{{ bundle.title }}
{% endif %}
</span>
<div style="display: flex; align-items: center; justify-content: center">
{% if bundle.data.discountConfig.bundleDiscount %}
<span class='rk-discount'>
{{ template.translations.discountLabelText | replace: "{{percent}}", bundle.data.discountConfig.bundleDiscount }}
</span>
{% endif %}
</div>
</div>
<div class="rk-bundle-container rk-bundle-{{ bundle.id }}-holder">
{% for product in components %}
{% assign productIndex = forloop.index0 %}
<div class="rk-p-c-container" data-rk-bundle-component-id="{{ product.id }}">
{% if product.image %}
<div class="rk-p-c-product-image-container">
<img
class="rk-p-c-product-image rk-image-{{ product.id }}"
{% if product.image contains '?' %}
src="{{ product.image }}&width={{ setting.productCard.image.width | default: 110 }} }}&height={{ setting.productCard.image.height | default: 133 }} }}&crop=center&pad_color=121212"
{% else %}
src="{{ product.image }}?width={{ setting.productCard.image.width | default: 110 }} }}&height={{ setting.productCard.image.height | default: 133 }} }}&crop=center&pad_color=121212"
{% endif %}
alt="{{ product.title }} image" />
</div>
{% endif %}
<div class="rk-p-c-product-details">
<div class="rk-p-c-head">
<a href="/products/{{ product.handle }}?pr_ref_pid={{ bundle.id }}&pr_rec_id={{ product.id }}&pr_prod_strat=glood_bundle&pr_seq={% if config.layout == 'bundle_component'%}component_selector{% else %}bundle{% endif %}">
<span class='rk-bundle-comp-title {% if setting.productCard.title.multipleLines == false %} rk-truncate-title {% endif %}'>
{{ product.title }}
</span>
</a>
<span class='rk-product-price rk-price-{{ product.id }}'>{{ product.price }}</span>
</div>
<div class="rk-p-c-footer">
{% if setting.showProductOptions == true %}
<div class="rk-options-selector-{{ product.id }} rk-p-options-selector">
{% for pOption in product.productOptions %}
<div class="rk-option-selector-wrapper">
<span class="rk-option-name">
{{ pOption.name }}
</span>
<radiogroup data-option-index="{{ forloop.index0 }}" data-option-name="{{ pOption.name }}" data-option-type="{{ pOption.name | downcase }}">
{% assign idx = forloop.index0 %}
{% for value in pOption.values %}
<input data-component-index="{{productIndex}}" data-option-name="{{ pOption.name }}" data-option-index="{{ idx }}" name="{{product.id}}_option_{{ idx }}" value="{{ value }}" data-product-id="{{ product.id }}" type="radio" id="rk_{{ product.id }}_{{ pOption.name }}_{{ value | replace: ' ', '_' }}">
<label for="rk_{{ product.id }}_{{ pOption.name }}_{{ value | replace: ' ', '_' }}">
<div class="rk-option-select_wrapper">
<span class="rk-option-select__title">
{{ value }}
</span>
</div>
</label>
{% endfor %}
</radiogroup>
</div>
{% endfor %}
</div>
{% endif %}
{% if product.variants.length > 1%}
<select class="rk-p-c-variant-selector rk-variant-selector-{{ product.id }}">
{% for variant in product.variants %}
<option value="{{ variant.value }}" {% unless variant.available %}disabled{% endunless %}>
{{ variant.value }}
</option>
{% endfor %}
</select>
{% endif %}
</div>
</div>
</div>
{% if forloop.index < products.size %}
<span class="rk-plus" id="rk-plus-{{ forloop.index }}">+</span>
{% endif %}
{% endfor %}
{% if config.layout == "bundle_component" %}
<div class="rk-atc-container">
<div class="rk-price">
<span class="rk-{{ bundle.id }}-total-price rk-total-price"></span>
<span class="rk-cmp-price">
<strike class="rk-cmp-p-text"></strike>
</span>
{% if bundle.data.discountConfig.bundleDiscount %}
<span class="rk-p-d-text">
{{ template.translations.bundleDiscount | replace: "{{percent}}", bundle.data.discountConfig.bundleDiscount }}
</span>
{% endif %}
</div>
<div class="rk-bundle-atc-container"></div>
</div>
{% endif %}
</div>
{% endif %}
{% endif %}
</div>