The Plan Picker Liquid file renders the entire plan picker element server-side prior to page load, allowing nearly zero performance impact on your store. No delayed loading, no flashing on load!
Required on non-product pages, snippets only have access to the globally available product variable by default. If the product variable is defined locally, for example inside a for each product in a collection, the snippet will not have access to the product variable unless explicitly passed.
form_id
Required when plan picker isn't nested in a form[action="/cart/add"]. The form_id has to match the id on the form element. It is used to connect a form field that is outside of a form to it using the form attribute.
Passed in for uniqueness; defaults to product.id this is particularly useful when using multiple plan pickers on the same page.
start_onetime
for choosing whether the one-time option is selected on page load; defaults to true
onetime_first
for choosing whether the one-time option displays above the selling plan option; defaults to true
discount_format
for formatting selling plan discounts; either 'percent' or 'absolute'; defaults to 'percent'
Page-load & Asynchronous Javascript
In order to have a near-zero impact on store performance and page load speed, the plan picker runs a script to asynchronously load our larger JS file after the DOMContentLoaded event.
An eventListener is set on the window to wait until mouseover or focus on one of the following: the plan picker element (fieldset[skio-plan-picker]), a product variant selector on the page ([name="id"]), or .product-form__input for Dawn-based themes. Once triggered, it fires the window.SkioLoadJS function, which injects a <script> tag for the plan picker JS file into <head>, initializing the plan picker's JS functionality. The script will only auto-inject once, and any instances of the plan picker element that load after the initial injection will be auto-initialized once loaded.
skio-plan-picker.liquid
{% comment %} SCRIPT {% endcomment %} <script> const selector = 'fieldset[skio-plan-picker], [id="name"], .product-form__input'; // Only loads the script if a plan picker is on the page, and only once // the main element is hovered over. doesn't load multiple times if there is are multiple plan pickers. // Defer loading to reduce load impact if (window.skio_plan_picker_script_load === undefined) {window.skio_plan_picker_script_load =true; const script =document.createElement('script');script.type ='text/javascript';script.defer =true;script.src ='{{ 'skio-plan-picker.js' | asset_url }}';window.SkioLoadJS= (e) => {document.head.append(script);document.querySelectorAll(selector).forEach(el => {el.removeEventListener('mouseover',window.SkioLoadJS);el.removeEventListener('focus',window.SkioLoadJS, { capture:true }); }); }window.addEventListener('DOMContentLoaded', () => {document.querySelectorAll(selector).forEach(el => {el.addEventListener('mouseover',window.SkioLoadJS);el.addEventListener('focus',window.SkioLoadJS, { capture:true }); }); }); } // Handling async load of skio-plan-picker.liquid if (window.SkioPlanPickerAutoInit) {window.SkioPlanPickerAutoInit(); } else {document.querySelectorAll(selector).forEach(el => {el.addEventListener('mouseover',window.SkioLoadJS);el.addEventListener('focus',window.SkioLoadJS, { capture:true }); }); } </script>
CSS Styles
The CSS file skio-plan-picker.css is included immediately after the script, and should be placed in the assets/ folder of your theme. You can make changes to this file if you would like to customize the CSS stylings used.
Liquid logic determines the current_variant prior to page load via a URL parameter, as well as handling the optional snippet parameters: key, start_onetime, onetime_first, and discount_format .
The fieldset.skio-plan-picker is the plan picker element. It assigns a unique key as an identifier ([skio-plan-picker="key"]) to differentiate between other plan pickers on the page. [skio-auto-init] is an identifier used within the larger JS file.
To properly display the plan picker on page load, Liquid is used to determine the correct selling plan and related discount (if applicable).
Using the Product object's selected_selling_plan variable, it checks if there is a selling_plan_id specified in the URL. If so, that is the selling plan to render; else, it defaults to the first compatible selling plan. The selling_plan_id is stored as the value in a hidden input[name="selling_plan"], which is connected to the form[action="/cart/add"] via being embedded in the form or including the form_id Liquid parameter.
With the current selling plan determined, Liquid is used to calculate the discounted price (if any) of the selling plan checking the discount_format Liquid parameter to determine how to render the discounted value (i.e. % or using the Liquid money filter). The discount text to display in the cart and at checkout is stored as the value in a hidden input[name=“properties[Discount]”] , which is disabled unless the subscription option is selected and is connected to the form[action="/cart/add"] via being embedded in the form or including the form_id Liquid parameter.
The primary HTML and Liquid of the Onetime and Subscription radio buttons are captured as Liquid variables, the order of which gets determined by the value of the onetime_first Liquid parameter.
The onetime radio button isn’t rendered if the product requires a selling plan regardless of the other Liquid parameters. The entire snippet isn't rendered if the product has no selling plans.
The subscription selector uses Liquid logic to generate the selling plan selector for the variant loaded on page load. The same discount logic as earlier determines the amount to display, along with the slashed out non discounted price.
After the Liquid variables have been captured, there is a check of the onetime_first Liquid parameter; if true, the one-time option is rendered first, else the subscription option is rendered first.