How can I display the membership selling plans on my membership product?
Once you've configured your membership perks and pricing, you'll want to add the selling plans (pricing options) to your membership product within Shopify. There are 3 ways to do this, all explained in detail on the Installation tab of the membership details page, as well as in the tutorial below. If you have any trouble at all with the installation process, don't hesitate to contact us for additional assistance.
App Embed
The easiest way to add selling plans to your membership product page is via an App Embed. This is a special widget that you enable within your Shopify theme that will attempt to automatically add selling plans to your membership product. You can access the App Embed directly by clicking the button on the Installation tab.
Note that the button will open a generic product page. Be sure to select your membership product so you can see how the selling plans look. Make sure to save your changes after you're done editing!
To return to the App Embeds directly in the future, start by going to your theme customizer and selecting App Embeds on the left-hand side menu.
Below is an example of where the App Embed shows up and what it may look like within your theme.
Online Store 2.0
If your theme supports Shopify's new Online Store 2.0 format, you can add the selling plans into your theme the same way you would add blocks and sections.
Start by opening your theme's Customize section and navigating to your membership product. On the left side, click either "Add section" or "Add block" and select "Membership Selling Plans".
You can also optionally add a "Membership Price" block that will update the price based on the selling plan selected.
Below is an example of where the App block shows up and what it may look like within your theme.
Advanced
If you'd prefer to add selling plans directly using HTML, you can use the code below. Paste it inside your product form within your product template to display the selling plans.
Also, if you're having issues with the featured product sections or quick buy buttons, the snippet below might help you fix it since it will bring the needed selling plan values from the product object and update the add-to-cart form accordingly.
<script type="application/json" id="selling-plan-json-{{ block.id }}"> {{ all_products[product.handle] | json }} </script> {% assign selling_plan_selected = blank %} {% assign has_selling_plans = false %} {% for variant in product.variants %} {% if variant.id == product.selected_or_first_available_variant.id %} {% for allocation in variant.selling_plan_allocations %} {% assign selling_plan_selected = allocation.selling_plan.id %} {% break %} {% endfor %} {% endif %} {% if variant.selling_plan_allocations.size > 0 %}{% assign has_selling_plans = true %}{% endif %} {% if selling_plan_selected != blank %}{% break %}{% endif %} {% endfor %} {% if has_selling_plans %} <fieldset class="selling-plan-fieldset" id="selling-plan-fieldset-{{ block.id }}" data-id="{{ block.id }}"> <legend>Plans</legend> {% for variant in product.variants %} <div data-variant="{{ variant.id }}" class="selling-plans {% if variant.id != product.selected_or_first_available_variant.id %}selling-plan-hide{% endif %}"> {% for allocation in variant.selling_plan_allocations %} {% assign selling_plan_frequency = blank %} {% for option in allocation.selling_plan.options %} {% if option.name == 'Charged every' %} {% capture selling_plan_frequency %}every {{ option.value }}{% endcapture %} {% endif %} {% endfor %} {% assign initial_price = '' %} {% assign recurrent_price = '' %} {% for adjustment in allocation.price_adjustments %} {% if forloop.length == 1 %} {% capture recurrent_price %}{{ adjustment.price | money }}{% endcapture %} {% elsif forloop.first %} {% if adjustment.price == 0 %} {% capture initial_price %}Free trial, then {% endcapture %} {% else %} {% capture initial_price %}{{ adjustment.price | money }} upfront, then {% endcapture %} {% endif %} {% else %} {% capture recurrent_price %}{{ adjustment.price | money }}{% endcapture %} {% endif %} {% endfor %} {% assign per_delivery_price = allocation.per_delivery_price %} {% for adjustment in allocation.price_adjustments %} {% assign per_delivery_price = adjustment.price %} {% endfor %} <label for="selling_plan_{{ block.id }}_{{ allocation.selling_plan.id }}" class="selling-plan-label"> <input type="radio" name="selling_plan_option" id="selling_plan_{{ block.id }}_{{ allocation.selling_plan.id }}" value="{{ allocation.selling_plan.id }}" {% if selling_plan_selected == allocation.selling_plan.id %}checked="checked"{% endif %} data-price="{{ per_delivery_price | money_with_currency | replace:'"',"'" }} {{ selling_plan_frequency }}"> {{ initial_price }}{{ recurrent_price }} {{ selling_plan_frequency | replace: " 1 ", " " }} </label> {% endfor %} </div> {% endfor %} </fieldset> <input name="selling_plan" type="hidden" value="{{ selling_plan_selected }}" hidden> {% endif %} <script> (function () { function CMupdateProductForm(product_id, selling_plan_id, price) { document.querySelectorAll('.selling-plan-form-' + product_id).forEach(function(productForm) { if(productForm.querySelector('input[name="selling_plan"]')) { productForm.querySelector('input[name="selling_plan"]').value = selling_plan_id; } else { var selling_plan_input = document.createElement('input'); selling_plan_input.name = "selling_plan"; selling_plan_input.value = selling_plan_id; selling_plan_input.type = "hidden"; productForm.appendChild(selling_plan_input); } }); document.querySelectorAll('.selling-plan-price-' + product_id).forEach(function(priceContainer) { priceContainer.innerHTML = price; }); } document.addEventListener("DOMContentLoaded", function () { cmLoadScripts() }); cmLoadScripts() function cmLoadScripts() { // if this is an embedded app, dynamically add selling plans if(typeof CMSellingPlans == 'function') { CMSellingPlans(); } document.querySelectorAll('.selling-plan-fieldset').forEach(function(sellingPlanContainer) { var product = JSON.parse(document.getElementById('selling-plan-json-' + sellingPlanContainer.dataset.id).innerHTML); // Get all forms for this product for(var i in product.variants) { document.querySelectorAll('form[action*="/cart/add"]').forEach(function(productForm) { var variant_field = productForm.querySelector('[name="id"]'); var external_variant_field = false; if(!variant_field && productForm.getAttribute('id') !== undefined) { variant_field = document.querySelector('[name="id"][form="' + productForm.getAttribute('id') + '"]'); external_variant_field = true; } if(variant_field && (variant_field.value == product.variants[i].id || (variant_field.value == '' && variant_field.options !== undefined && variant_field.options[0].value == product.variants[i].id))) { // add a selector to make it easy to identify productForm.classList.add('selling-plan-form-' + product.id); // if it's an external variant field, add a change there if(window.getComputedStyle(variant_field).display == 'none' || external_variant_field) { variant_field.addEventListener('change', function (e) { setTimeout(function() { sellingPlanContainer.querySelectorAll('.selling-plans:not([data-variant="' + this.value + '"])').forEach(function(planGroup) { planGroup.classList.add('selling-plan-hide'); }); sellingPlanContainer.querySelectorAll('.selling-plans[data-variant="' + this.value + '"]').forEach(function(planGroup) { planGroup.classList.remove('selling-plan-hide'); }); var selling_plan = sellingPlanContainer.querySelector('.selling-plans[data-variant="' + this.value + '"] input[name="selling_plan_option"]'); selling_plan.checked = true; CMupdateProductForm(product.id, selling_plan.value, selling_plan.dataset.price); }.bind(this), 50); }); } // if it's a hidden field, it's complicated. if(window.getComputedStyle(variant_field).display == 'none' || (external_variant_field && variant_field.type == 'hidden')) { let previousValue = variant_field.value; setInterval(function() { // 1: check if value changed if (variant_field.value !== previousValue) { previousValue = variant_field.value; // 2: trigger `change` event variant_field.dispatchEvent(new Event('change')); } }, 500); } productForm.addEventListener('change', function (e) { if(e.srcElement.name != "selling_plan_option") { setTimeout(function() { var variant_field = this.querySelector('[name="id"]'); sellingPlanContainer.querySelectorAll('.selling-plans:not([data-variant="' + variant_field.value + '"])').forEach(function(planGroup) { planGroup.classList.add('selling-plan-hide'); }); sellingPlanContainer.querySelectorAll('.selling-plans[data-variant="' + variant_field.value + '"]').forEach(function(planGroup) { planGroup.classList.remove('selling-plan-hide'); }); var selling_plan = sellingPlanContainer.querySelector('.selling-plans[data-variant="' + variant_field.value + '"] input[name="selling_plan_option"]'); selling_plan.checked = true; CMupdateProductForm(product.id, selling_plan.value, selling_plan.dataset.price); }.bind(this), 50); } }); } }); } // Watch for selling plan option change to update the selected selling plan sellingPlanContainer.querySelectorAll('input[type="radio"]').forEach(function (radio) { radio.addEventListener('change', function () { CMupdateProductForm(product.id, this.value, this.dataset.price); }); }); // when the page first loads, make sure the selling plan id is added to the forms var selected_radio = sellingPlanContainer.querySelectorAll('input[type="radio"]:checked').forEach(function(radio) { CMupdateProductForm(product.id, radio.value, radio.dataset.price); }); }); } })(); </script> <style> label.selling-plan-label { display: flex; align-items: center; } label.selling-plan-label input[type="radio"] { margin-right: 10px; min-height: unset; } fieldset.selling-plan-fieldset { padding: 2px 12px 10px; max-width: 300px; margin: 0 auto 2.5rem 0; flex-basis: 100%; } .selling-plan-hide { display: none; } </style>