Gifting overview
Stay.AI offers merchants the ability to stand up a gifting platform. Meaning your customers can now both subscribe to your products for themselves or send a set amount of shipments to others. Let your product be a gift to your customers' loved ones!
General guidelines
Gifts will be configured in the Stay.AI merchant portal.
Only prepaid selling plans can be configured as gifts.
The out-of-the-box gifting solution will populate in the buy box, but customizations can be made per the merchant’s request
Getting started
In the Merchant Portal:
Navigate to the Stay.AI merchant portal
Open your Shopify Admin store
Go to Apps
Select “Stay.AI Subscriptions”
Ensure the products you would like to setup for Gifting are setup in Shopify. If so, you are ready to setup Gifts!
Navigate to the Selling Plans page
In the Stay.AI Merchant Portal, navigate to the Settings section
Open “Selling Plans”
To setup a NEW selling plan for gifting, create a “New Prepaid Selling Plan Group”
Select “New Prepaid Selling Plan Group”
Select the products you would like to be available as prepaid gifts in this selling plan group
Provide Selection and Checkout Cart Labels, the desired discount amount for the selling plan, the shipping schedule, and the amount of shipments desired for the prepaid plan.
NOTE: If you select a shipping schedule of every 1 month, and 2 shipments in this section, your customers will be charged for the price of the product, minus the established discount for the plan, times the number of shipments. They will receive the shipments every month.
Setup as many frequencies as desired. For instance, if you would like to offer a monthly prepaid subscription for 2 shipments, 3 shipments, and 4 shipments, these can all be configured within this view.
Select the “Allow Gifting for this Selling Plan Group” checkbox on the selling plan
This will enable an option on the customer portal to select the prepaid subscription as a gift. The customers will then go through the gifting flow on the customer portal.
Provide the Storefront Selling Plan Group labels
NOTE: Pick something here that will make it clear to your users that they are paying for a prepaid subscription. These labels are customer facing.
Submit your changes!
In your Shopify Store:
Confirm whether gifting has already been set up for your Shopify store.
Some stores are already set up for full gifting support. You will need to navigate to a product with a selling plan group that you have set up for gifting. Confirm whether the gifting options are already displayed or not.
If the gifting options are present and performing as expected then you’re all set!
If it has not been set up, start by navigating to your Shopify Admin Panel
On the main navigation (on the left-hand side of the screen), Click “Sales Channels” and then select “Online Store”
It is recommended to create a backup / duplicate of your current theme before proceeding. To do this, locate your current published theme, and click the “…” menu, and then select “Duplicate”
After creating a backup, select the “…” menu on the published theme again, and select “Edit Code”
From the Code view, find the search bar in the left panel. Type “rtx-pdp” in the search and locate the file “rtx-pdp.liquid” underneath the “snippets” folder. Select this file by clicking on it.
If there is no “rtx-pdp.liquid” file, please follow the Buy Box installation guide within the Stay.AI App.
In the right-hand side of the screen will appear the code. Replace the contents of the entire file with the following code.
{% comment %} v1.0.0 {% endcomment %} {%- if product.selling_plan_groups.size > 0 -%} {%- comment -%} Shorthand Variables {%- endcomment -%} {%- liquid assign currentVariant = variant | default: product.selected_or_first_available_variant assign requiresPlan = product.requires_selling_plan assign selectedAllocation = product.selected_or_first_available_selling_plan_allocation assign currentAllocations = currentVariant.selling_plan_allocations -%} {%- comment -%} Buy Box Styles {%- endcomment -%} <style type="text/css"> .rtx-subscription-box { display: none; } .rtx-subscription-box.is-visible { display: block; } .rtx-gift-box { display: none; } .rtx-gift-box.is-visible { display: block; } </style> <div data-rtx-subscription-{{ product.id }}-{{ section.id }}-{{ block.id }}> {%- comment -%} Subscription type toggle {%- endcomment -%} {%- unless requiresPlan -%} <div> <input type="radio" id="purchaseTypeOneTime" name="purchaseType" value="purchaseTypeOneTime" {% if selectedAllocation == blank %}checked{% endif %} /> <label for="purchaseTypeOneTime">One Time Purchase</label> <input type="radio" id="purchaseTypeSbubscription" name="purchaseType" value="purchaseTypeSubscription" {% if selectedAllocation != blank %}checked{% endif %} /> <label for="purchaseTypeSbubscription">Subscription Purchase</label> </div> {%- endunless -%} {%- comment -%} Subscription Box {%- endcomment -%} <div data-retextion-subscription-box class=" rtx-subscription-box {% if requiresPlan or selectedAllocation != blank %} is-visible {% endif %} "> <p>Subscription</p> {%- comment -%} Subscription Gift Box Toggle {%- endcomment -%} <div> <input id="subscriptionGift" type="checkbox" name="properties[_gifted-subscription]" /> <label for="subscriptionGift">Gift Subscription</label> </div> {%- comment -%} Gift Box {%- endcomment -%} <div data-retextion-gift-box class="rtx-gift-box"> <div> <label for="subscriptionEmail">Recipient's Email</label> <input id="subscriptionEmail" type="email" name="properties[Gift Recipient Email]" placeholder="Enter the recipient's email" /> </div> <div> <label for="subscriptionFirstName">Recipient's First Name</label> <input id="subscriptionFirstName" type="text" name="properties[Gift Recipient First Name]" placeholder="Enter the recipient's first name" /> </div> <div> <label for="subscriptionLastName">Recipient's Last Name</label> <input id="subscriptionLastName" type="text" name="properties[Gift Recipient Last Name]" placeholder="Enter the recipient's last name" /> </div> <div> <label for="subscriptionMessage">Gift Message</label> <textarea id="subscriptionMessage" name="properties[Gift Message]" maxlength="1024" placeholder="Enter a short message"></textarea> </div> <p> You will provide the shipping information during checkout. </p> </div> {%- comment -%} Selling Plan Options {%- endcomment -%} <select name="selling_plan"> {%- liquid for allocation in currentAllocations assign plan = allocation.selling_plan echo '<option' if plan.selected or sellectedAllocation == blank and forloop.first echo ' selected' endif echo ' value="' | append: plan.id | append: '">' echo plan.name | escape echo '</option>' endfor -%} </select> </div> </div> <script type="text/javascript"> ((api) => { const boxId = "{{ product.id }}-{{ section.id }}-{{ block.id }}"; const boxProduct = {{ product | json }}; const elementRoot = document.querySelector('[data-rtx-subscription-' + boxId + ']'); const productForm = elementRoot.closest('form[action="/cart/add"]') || elementRoot.closest('form') || document.querySelector('form[action="/cart/add"]') || document.documentElement; const elementSubscriptionBox = elementRoot.querySelector('[data-retextion-subscription-box]'); const elementGiftBox = elementRoot.querySelector('[data-retextion-gift-box]'); const elementGiftCheckbox = elementRoot.querySelector('[name="properties[_gifted-subscription]"]'); const elementSellingPlan = elementRoot.querySelector('[name="selling_plan"]'); const elementQuantitySelector = productForm.querySelector('[name="quantity"]'); const elementsPurcahseTypeRadio = elementRoot.querySelectorAll('[name="purchaseType"]'); const elementsVariantSelectors = productForm.querySelectorAll('[name="id"]'); const elementsInputs = productForm.querySelectorAll('button,input,textarea,select,option,datalist,optgroup'); let selectedVariantId = {{ currentVariant.id | json }}; const queryParamsGet = () => { let [ origin, searchAndHash ] = window.location.toString().split('?'); searchAndHash = searchAndHash || ""; let [ search ] = searchAndHash.split('#'); return (search||'').split('&').reduce((o,e) => { let [ key, value ] = e.split('=').map(x => decodeURIComponent(x)); if(!key || !value) return o; o[key] = value; return o; },{}); }; const queryParamsGenerate = (qp) => { qp = qp || {}; //Remove undefined Object.keys(qp).forEach(key => { if(typeof qp[key] !== typeof undefined) return; delete qp[key]; }); return Object.keys(qp).reduce((x,key,i) => { let value = qp[key]; if(i != 0) x += '&'; return x += encodeURIComponent(key)+'='+encodeURIComponent(value); }, ''); }; const subscriptionBoxHide = () => { elementSubscriptionBox.classList.remove('is-visible'); } const subscriptionBoxShow = () => { elementSubscriptionBox.classList.add('is-visible'); } const subscriptionGiftShow = () => { elementGiftBox.classList.add('is-visible'); } const subscriptionGiftHide = () => { elementGiftBox.classList.remove('is-visible'); } const sellingPlanQueryUpdate = () => { const queryParams = queryParamsGet(); if(elementSubscriptionBox.classList.contains('is-visible')) { queryParams['selling_plan'] = sellingPlanSelectionGet() || undefined; } else { delete queryParams['selling_plan']; } const qs = queryParamsGenerate(queryParams); try { let hash; hash = (hash = window.location.toString().split('#')).length > 1 ? hash[1] : null; const url = window.location.toString().split('?')[0] + '?' + qs + (hash ? '#' + hash : ''); history.pushState(queryParams, '', url); } catch(e) { // Catching since older browsers and iOS can have issues console.error(e); } } const sellingPlanSelectionGet = () => { return parseInt(elementSellingPlan.value); } const sellingPlanSelectionSet = (sellingPlan) => { sellingPlan = sellingPlan && sellingPlan.id ? sellingPlan.id : sellingPlan; elementSellingPlan.value = sellingPlan.toString(); } const sellingPlanPropertiesGet = () => { const formData = new FormData(productForm); return Array.from(formData.entries()); } const sellingPlanUrlGenerate = () => { const props = sellingPlanPropertiesGet(); let strProperties = ''; sellingPlanPropertiesGet().forEach(prop => { const key = prop[0]; if(!key.startsWith('properties[')) return; const val = prop[1]; if(!val || !val.toString().length) return; strProperties += '&items[][' + encodeURIComponent(key) + ']=' + encodeURIComponent(val); }); return window.location.origin + '/cart/clear?return_to=' + encodeURIComponent('/cart/add' + '?items[][id]=' + selectedVariantId + '&items[][quantity]=' + (elementQuantitySelector ? elementQuantitySelector.value : 1) + strProperties + '&items[][selling_plan]=' + sellingPlanSelectionGet() + '&return_to=/checkout' ); } const sellingPlanUpdate = () => { sellingPlanQueryUpdate(); console.log(sellingPlanUrlGenerate()); } const sellingPlanUpdateVariant = () => { const variant = ( boxProduct.variants.find(v => v.id == selectedVariantId) || boxProduct.variants.find(v => v.available) || boxProduct.variants[0] ); let newOptions = ''; // Determine the selected option let selected = sellingPlanSelectionGet(); if(!variant.selling_plan_allocations.some(spa => { return spa.selling_plan_id == selected; })) { selected = variant.selling_plan_allocations[0].selling_plan_id; } // Generate new options variant.selling_plan_allocations.forEach((spa,i) => { const sellingGroup = boxProduct.selling_plan_groups.find(spg => spg.id === spa.selling_plan_group_id); const sellingPlan = sellingGroup.selling_plans.find(sp => sp.id === spa.selling_plan_id); const opt = document.createElement('option'); if(sellingPlan.id == selected) { opt.setAttribute('selected', 'selected'); } opt.value = sellingPlan.id; opt.textContent = sellingPlan.name; newOptions += opt.outerHTML; }); // Update select elementSellingPlan.innerHTML = newOptions; sellingPlanUpdate(); } // Event Listeners elementsPurcahseTypeRadio.forEach(el => { el.addEventListener('change', e => { if(el.value === 'purchaseTypeSubscription') { subscriptionBoxShow(); } else { subscriptionBoxHide(); } sellingPlanUpdate(); }); }); elementGiftCheckbox.addEventListener('change', e => { if(e.target.checked) { subscriptionGiftShow(); } else { subscriptionGiftHide(); } sellingPlanUpdate(); }); elementSellingPlan.addEventListener('change', e => { sellingPlanUpdate(); }); elementsVariantSelectors.forEach(vs => { vs.addEventListener('change', e => { selectedVariantId = e.target.value; sellingPlanUpdateVariant(); }); }); elementsInputs.forEach(inp => { inp.addEventListener('change', e => { sellingPlanUpdate(); }); }); // Public API return Object.assign(api, { [boxId]: { boxId, boxProduct, subscriptionBoxHide, subscriptionBoxShow, subscriptionGiftShow, subscriptionGiftHide, sellingPlanUrlGenerate } }); })((window.retextionBuyBox = {})); </script> {%- endif -%}
Select “save” and perform additional testing to ensure functionality is matching expectations.
You’re All Set! Now What Will Your Customers See?
You’re officially ready to be gifted! A few guidelines about what your customers will see and experience as they decide to send gifts.
Checkout Process
Customers will have to opt in to sending the gift. This will be configured per merchant in the buy box.
Once customers select to send a gift, they will have to provide the following information:
Gift Recipient First Name
Gift Recipient Last Name
Gift Recipient Email
Gift message for the recipient
Upon checkout, they will provide the following information:
Their OWN email address
The shipping address for the recipient
Billing information
Notifications
Once the customer has succesfully checked out, we let them know it! The following notifications are triggered for the gifter and the gift recipient.
Gifter:
You have sent a gift! This is a confirmation email, letting the gifter know that we have successfully processed their order, and their gift is on the way.
Your gift is shipped! This is an email alerting the gifter that one of the prepaid shipments is on the way
Your last order has shipped! This alerts the gifter that the last order has been shipped for the prepaid subscription.
Gift Recipient:
You have been sent a gift! This is an email to the gift recipient, alerting them that they have a prepaid subscription gift, and giving them access to the customer portal to manage their subscriptions.
Your gift is shipped! This is an email alerting the gift recipient that one of the prepaid shipments is on the way.
Your last order has shipped! This alerts the gift recipient that the last order has been shipped for the prepaid subscription.
Customer Portal Access
Both the gift recipient and the gifter will now have access to manage the subscription on their customer portal. Some awesome notes from our team:
Let’s say your gift recipient has other subscriptions to the same email on your site - they will be able to manage them all from the same portal
Gifts are gifts! Because of that, we hide the price of the subscription for the recipient
To prevent any mistakes, permissions are limited on both the recipient and the gifter’s portal (swaps, and skip next orders are not available for gifts!)