Build a Custom Subscription Extension

🛍️Build a Custom Subscription Extension

📖 Shopify Docs Reference ↗
Object types: variant selling_plan_group selling_plan input / form

📱 UI Preview — Annotated

🗂️ Purchase Option static label
Regular purchase static / theme
variant.price input name="id"
€90.00 EUR
each
Subscribe & Save autocancel selling_plan_group.name
group.name
from
€85.50 EUR
/each
Delivery Frequency
Delivery every 2 Week selling_plan.name
radio value = selling_plan.id hidden input selling_plan
€85.50 EUR €90.00 EUR SAVE 5%
price_adjustments
Delivery every 1 Week selling_plan.name
€90.00 EUR
Delivery every 3 Week selling_plan.name
€81.00 EUR €90.00 EUR SAVE 10%
💡 Hover over colored tags to see tooltip descriptions. Tags show the Shopify object/field powering each label.

🔵 Regular Purchase Label

UI Label
"Regular purchase"
Source
static / theme text
Price shown
€90.00 EUR
Source
variant.price | money
Form input
name="id"
Value
variant.id
{%- comment -%} Liquid snippet {%- endcomment -%} {{ product.selected_or_first_available_variant.price | money }} <input type="hidden" name="id" value="{{ variant.id }}">

📦 Subscribe & Save Label

UI Label
"Subscribe & Save"
Source
selling_plan_group.name
{% for group in product.selling_plan_groups %} {{ group.name }} ← "Subscribe & Save" {% endfor %}

🔁 Delivery Frequency Labels

UI Label
"Delivery every 2 Week"
Source
selling_plan.name
Radio input value
987654321
Source
selling_plan.id
Discount shown
SAVE 5% / 10%
Source
selling_plan.price_adjustments
{% for plan in group.selling_plans %} <input type="radio" name="selling_plan_option" value="{{ plan.id }}"> ← selling_plan.id {{ plan.name }} ← "Delivery every 2 Week" {% endfor %}

⚙️ Selling Plan Input — JS Injection

When a delivery plan is selected, a hidden input is dynamically appended to the product form so the cart receives the correct selling_plan.id.

function setSellingPlan(planId) { let input = form.querySelector( 'input[name="selling_plan"]' ); if (!input) { input = document.createElement('input'); input.type = 'hidden'; input.name = 'selling_plan'; form.appendChild(input); } input.value = planId; // ← selling_plan.id } // Attach to radio change document.querySelectorAll( '[name="selling_plan_option"]' ).forEach(radio => { radio.addEventListener('change', () => { setSellingPlan(radio.value); }); });

📊 Complete Data Source Summary

UI Label / Input Shopify Object Field / Value Purpose
Regular purchase price variant variant.price Display base price
Subscribe & Save [text] selling_plan_group selling_plan_group.name Subscription group label
Delivery every X Week selling_plan selling_plan.name Frequency label text
Discounted price / SAVE % selling_plan selling_plan.price_adjustments Discount display
Radio value (plan selector) selling_plan selling_plan.id Input value for cart
Hidden input name="id" variant variant.id Required for cart line item
Hidden input name="selling_plan" selling_plan selling_plan.id (JS injected) Activates subscription cart

🛒 Final Cart POST Payloads

Regular Purchase
{ "id": 123456789 }
Subscription Purchase
{ "id": 123456789, "selling_plan": 987654321 }
⚠️ Important: Only submit selling_plan when a plan is selected. Remove the hidden input on switch back to one-time purchase.