Shopify themes, liquid, logos, and UX
If you have products that are out of stock, you can sell them as pre-orders. This is done by creating an alternate product template, and editing your payment settings. You can also use this customization to continue selling products that are on back-order.
Note: This customization isn't compatible with dynamic checkout buttons. If your theme supports dynamic checkout, then prevent the buttons from showing by following the steps to hide dynamic checkout buttons on product pages.
Sectioned and non-sectioned themes
The steps for this tutorial differ depending on whether you are using a sectioned or a non-sectioned theme. A sectioned theme is a newer theme that lets you drag and drop to arrange the layout of your store's pages.
To figure out whether your theme supports sections, go to the theme's Edit code page. If there are files in the Sections directory, you are using a sectioned theme. Non-sectioned themes were released before October 2016, and do not have files in the Sections directory.
If you are using a sectioned theme, then click the Sectioned themes button and follow the instructions. If you are using an older, non-sectioned theme, then click the Non-sectioned themes button and follow the instructions.
TyW | Online Community Manager @ Shopify
- Was my reply helpful? Click Like to let me know!
- Was your question answered? Mark it as an Accepted Solution
- To learn more visit the Shopify Help Center or the Shopify Blog
I have done all the steps for the debut theme, however when I click my pre-order product the product won't open. It says "Liquid error: Error in tag 'section' - 'product-pre-order-template' is not a valid section type".
Any ideas on where I made a mistake and how to fix it.
Did you ever get an answer? This is the issue with mine
Hi! Yes i solved this today!!
(Hat tip to @John_G2 for the inspiration to loop through the variants for their policy and quantity in liquid INSIDE the JS)
You can check the example on my development shop:
https://aimhuge-dev-dec20.myshopify.com/products/product-preorder
Password is 123456 (check the catalog → product-preorder)
How to do it?!
1. Followed the tutorial linked on the first page of this thread to create a new template option for products that allow preorder
2. BUT skip this part of the tutorial
3) Replace the product strings bit of script in product.pre-order.liquid
<script>
theme.productStrings = {
addToCart: {{ 'products.product.add_to_cart' | t | json }},
unavailable: {{ 'products.product.unavailable' | t | json }},
sold_out: {{ 'products.product.sold_out' | t | json }}
}
</script>
with the following:
<script>
// Override default values of shop.strings for each template.
// Alternate product templates can change values of
// add to cart button, sold out, and unavailable states here.
// | t filter translates from strings files
// there is no Pre-order string my default, so we add it without the t filter
theme.productStrings = {
addToCart: {{ 'products.product.add_to_cart' | t | json }},
unavailable: {{ 'products.product.unavailable' | t | json }},
sold_out: {{ 'products.product.sold_out' | t | json }},
preorder: {{ 'Pre-order' | json }}
}
// inventory quantity and policy were depercated from liquid
// https://community.shopify.com/c/API-Announcements/Deprecated-Notice-inventory-quantity-and-inventory-policy-fields/m-p/419770
// but can be accessed by reading the product into a variable
// and backfilling the inventory quanity & policy into the product
const product = {{ product | json}}
let v;
{% for variant in product.variants %}
v = getVariantById({{ variant.id}})
v.inventory_quantity = {{ variant.inventory_quantity | json }}
v.inventory_policy = {{ variant.inventory_policy | json }}
{% endfor %}
// then we just change the text of the CTA when the select is changed
document.querySelector('.single-option-selector').onchange = ()=>{
const selectEl = document.querySelector('[name="id"]') // the select
const cta = document.querySelector('.product-form__cart-submit') // the CTA
setTimeout(()=>{ // requires a little delay for some reason
const [options] = getSelectedOptions(selectEl)
const variant = getVariantById(parseInt(options.value))
if(variant.inventory_quantity > 0 ){
cta.textContent = theme.productStrings.addToCart
} else if( variant.inventory_policy === "continue" ){
cta.textContent = theme.productStrings.preorder
} else {
cta.textContent = theme.productStrings.sold_out
}
},5)
};
// fire the event on page load (check if it's pre-order)
document.querySelector('.single-option-selector').onchange()
// helper functions
function getVariantById(id){
const [variant] = product.variants.filter( (v) => v.id === id )
return variant
}
function getSelectedOptions(selectEl) {
const result = [];
const options = selectEl.getElementsByTagName('option');
for (let i = 0; i < options.length; i++) {
if (options[i].selected)
result.push(options[i]);
};
return result;
}
</script>
CC @Jennifer42
Script updated to handle products with only one variant (aka no variant selector)
<script>
// Override default values of shop.strings for each template.
// Alternate product templates can change values of
// add to cart button, sold out, and unavailable states here.
// | t filter translates from strings files
// there is no Pre-order string my default, so we add it without the t filter
theme.productStrings = {
addToCart: {{ 'products.product.add_to_cart' | t | json }},
unavailable: {{ 'products.product.unavailable' | t | json }},
sold_out: {{ 'products.product.sold_out' | t | json }},
preorder: {{ 'Pre-order' | json }}
}
// inventory quantity and policy were depercated from liquid
// https://community.shopify.com/c/API-Announcements/Deprecated-Notice-inventory-quantity-and-inventory-policy-fields/m-p/419770
// but can be accessed by reading the product into a variable
// and backfilling the inventory quanity & policy into the product
const product = {{ product | json}}
let v;
{% for variant in product.variants %}
v = getVariantById({{ variant.id}})
v.inventory_quantity = {{ variant.inventory_quantity | json }}
v.inventory_policy = {{ variant.inventory_policy | json }}
{% endfor %}
const selectEl = document.querySelector('[name="id"]') // the select
const cta = document.querySelector('.product-form__cart-submit') // the CTA
const currentVariant = getVariantById({{product.selected_or_first_available_variant.id}})
// fire the event on page load (check if it's pre-order)
updateCTA(currentVariant, cta)
// then we just change the text of the CTA when the select is changed
document.querySelector('.single-option-selector').onchange = ()=>{
setTimeout(()=>{ // requires a little delay for some reason
const [options] = getSelectedOptions(selectEl)
const variant = getVariantById(parseInt(options.value))
updateCTA(variant, cta)
},5)
};
// helper functions
function getVariantById(id){
const [variant] = product.variants.filter( (v) => v.id === id )
return variant
}
// update the cta based on the inventory quantity and policy
function updateCTA(variant, ctaEl){
if(variant.inventory_quantity > 0 ){
return ctaEl.textContent = theme.productStrings.addToCart
} else if( variant.inventory_policy === "continue" ){
return ctaEl.textContent = theme.productStrings.preorder
} else {
return ctaEl.textContent = theme.productStrings.sold_out
}
}
function getSelectedOptions(selectEl) {
const result = [];
const options = selectEl.getElementsByTagName('option');
for (let i = 0; i < options.length; i++) {
if (options[i].selected)
result.push(options[i]);
};
return result;
}
</script>
Hi @Alex-Miller ,
Thank you for providing the tutorial for adding pre-order function for variants! I'm using debut theme (Shop Link) and was able to follow the steps until step 3 as I have a much longer code than yours with the "theme.productStrings" part of product.pre-order.liquid and I'm not sure which part should be replaced. I attached the full script of my product.pre-order.liquid below. Grateful for your advice the steps forward, please. Thanks in advance!
Yours:
Mine:
{% comment %}
The contents of the product.liquid template can be found in /sections/product-template.liquid
{% endcomment %}
{% section 'product-pre-order-template' %}
{% section 'product-recommendations' %}
<div id="backToCollection"></div>
<script>
// Override default values of shop.strings for each template.
// Alternate product templates can change values of
// add to cart button, sold out, and unavailable states here.
theme.productStrings = {
addToCart: {{ 'Pre-order' | json }},
soldOut: {{ 'products.product.sold_out' | t | json }},
unavailable: {{ 'products.product.unavailable' | t | json }}
};
if(sessionStorage.backToCollection) {
theme.backToCollection = {};
theme.backToCollection.collection = JSON.parse(sessionStorage.backToCollection);
var productCollections = {{ product.collections | json }};
var showCollection = false;
if (productCollections) {
productCollections.forEach(function(collection) {
if (collection.title === theme.backToCollection.collection.title) {
showCollection = true;
}
});
}
if(showCollection) {
var backToCollectionHTML = '<div class="text-center return-link-wrapper page-width"><a href="' + theme.backToCollection.collection.link + '" class="btn btn--secondary btn--has-icon-before">{% include 'icon-arrow-left' %}{{ 'products.product.back_to_collection' | t }} ' + theme.backToCollection.collection.title + '</a></div>';
var backToCollectionContainer = document.getElementById('backToCollection');
backToCollectionContainer.insertAdjacentHTML('afterbegin', backToCollectionHTML);
}
}
</script>
{% assign current_variant = product.selected_or_first_available_variant %}
<script type="application/ld+json">
{
"@context": "http://schema.org/",
"@type": "Product",
"name": {{ product.title | json }},
"url": {{ shop.url | append: product.url | json }},
{%- if product.featured_media -%}
{%- assign media_size = product.featured_media.preview_image.width | append: 'x' -%}
"image": [
{{ product.featured_media | img_url: media_size | prepend: "https:" | json }}
],
{%- endif -%}
"description": {{ product.description | strip_html | json }},
{%- if current_variant.sku != blank -%}
"sku": {{ current_variant.sku | json }},
{%- endif -%}
"brand": {
"@type": "Thing",
"name": {{ product.vendor | json }}
},
"offers": [
{%- for variant in product.variants -%}
{
"@type" : "Offer",
{%- if variant.sku != blank -%}
"sku": {{ variant.sku | json }},
{%- endif -%}
"availability" : "http://schema.org/{% if variant.available %}InStock{% else %}OutOfStock{% endif %}",
"price" : {{ variant.price | divided_by: 100.00 | json }},
"priceCurrency" : {{ cart.currency.iso_code | json }},
"url" : {{ shop.url | append: variant.url | json }}
}{% unless forloop.last %},{% endunless %}
{%- endfor -%}
]
}
</script>
Leatheraholicx
hello @leatheraholicx
The product strings appear to be the same. I think you can just replace that part of the script. If you need support, please feel free to DM or email me.
Hi,
I've implemented this and have the pre-order working as it's supposed to, but we have just noticed that the product codes and collection names are not showing up on the product pages for pre-orderable items. Any ideas as to how to solve this? Do I possibly also need to create a 'product-details-pre-order-template.liquid as well? We have sites using the Mobilia theme and also some using the Envy theme, so I need to fix it on both themes as we've found that the issue is the same in both.
I just changed the translation: add to cart ---> Pre-order
What's the different? I need the pre-order to appear once i've not products on stock.
If I change my payment to manually capture payment, will this affect all other purchases outside of the pre-order style?
@YuriLee I asked this along with several other operational and procedural questions a while back and got zero response from the OP or anyone else. Hopefully you'll have better luck...
Thank you for this tutorial. I have implemented the solution for Sectioned themes. I have 3 product variants, S, M and L. I tested this out by indicate S and L at 0 inventory and M at 1 inventory, but when I select M on the front end, the button still says Pre-order. Do you have any inkling where I may have gone wrong in my implementation?
Hi TyW,
Thank you for your easy-to-follow instructions. Do you happen to have an updated or applicable to "brooklyn" theme version by chance? Your codes don't work fo my store. Store url is www.ootdnewyork10.com and the theme, again, is brooklyn.
TyW,
I am following your instructions to the Tee. Maybe I am missing something the line code for the style for the boost template does not have the following below for me to replace.
addToCart: {{ 'products.product.add_to_cart' | t | json }}, to addToCart: {{ 'Pre-order' | json }},
instead I have the following code.
<script type="application/json" class="ProductJson-{{ product.id }}">
{{ product | json }}
</script>
Do you have any updated instructions?
Good Day I have followed instructions and everything works great! I have one question though, how can products that are in stock show an "in stock" or "add to cart" to show that they are in stock and not on preorder, and then switch to pre-order if the inventory stock hits 0? Would one have to change the Template suffix or is there a script that can be included?
Great instructions! Very easy to follow! I did everything exactly as you said, but I'm getting this error on most of my items. Do you have any insight on this "Translation missing"?
You'll see it worked for the Pebble color in the pants, but not for the white.
Thank you for the solution, this worked for my debut theme shop!
Thank you for the tip! I managed to do the pre-order and get it to work. However I would like to add a message in the section to inform the customer about delayed shipping.
May I know how I should do that?
Sections > product template liquid > line 152 > <div class="free_ship"><img width="50px" src="https://cdn0.iconfinder.com/data/icons/e-commerce-69/512/delivery-512.png"><span style="font-size: 20px;padding-left: 5px;">type your message about delayed shipping here</span></div>
This is the only way I could think of doing it.
Hi there, thank you so much for this tutorial, it worked perfectly!
Im just wondering how to get the quantity picker showing when you have pre order template enabled. As its currently only the 'preorder' button available
thanks so much!
Henrietta
Please help! After following all steps and disabling dynamic checkout, I cannot find the code/script:
<span data-add-to-cart-text>
{% unless current_variant.available %}
{{ 'products.product.sold_out' | t }}
{% else %}
{{ 'products.product.add_to_cart' | t }}
{% endunless %}
</span>
anywhere !! I'm stuck at step 11 😞 I have the style narrative if that helps!
I'm also using Narrative and can't find the add-to-cart code to replace. My website is www.perfectdd.com, can you help enable pre-order please?
I am excited about having a way for my customers to pre-order an item when it is out of stock. Will this automatically change to pre-order when an item is out of stock? Or do I have to manually mark each item to pre-order? Can I keep the variety out of stock that I want to change to pre-order in with the other same items? or do they have to be somewhere completely else on my website?
@Alex-Miller Any chance you could help!? I have multiple items on pre order, new shirts. Every time a customer has to check out with each item. Is there a way to have the customer add items to their cart and check out with multiple pre orders?
Sure it's possible. I checked your site - there seems to be a bug.
Please feel free to email me 🙂
These changes work great to change the Product Page. But many users will also be using the Featured Product widget on their Home page and thus also need to make the same change in the file:
featured-product.liquid
This worked great!
Do you know if there is a way that inventory stock will show as Add to Cart, whilst the "allow to purchase whilst out of stock" will show as the Pre-Order button?
When selling products as pre-orders, you should not capture payment immediately unless the customer is aware that they are purchasing something that is not currently available. Instead, you can authorize a payment without capturing the funds immediately. Authorizing a payment at the time of checkout allows you to capture the funds at a later date, when the product is available and you are ready to fulfill the order.
Note: If you communicate to your customers that you are charging them in advance for an item that will ship at a later date, then you can capture funds immediately for a pre-order product.
Caution: Authorization periods expire after a certain period of time. After an authorization expires, you may no longer legally capture payment for that order. Shopify Payments has an authorization period of 7 days. To authorize payments for a longer period, you must use a third-party payment gateway.
To change the Add to cart button text for your pre-order products, you must create a new product template.
pre-order
:product.pre-order.liquid
template will open in the code editor.<span data-add-to-cart-text>
{% unless current_variant.available %}
{{ 'products.product.sold_out' | t }}
{% else %}
{{ 'products.product.add_to_cart' | t }}
{% endunless %}
</span>
Replace it with:
<span data-add-to-cart-text>
{{ 'Pre-order' | json | remove: '"' }}
</span>
In the same file, look for a <script> tag that contains this line of code:
addToCart: {{ 'products.product.add_to_cart' | t | json }},
Replace it with:
addToCart: {{ 'Pre-order' | json }},
Every theme is different, and the code used for the Add to cart button text may vary. If you replace instances of
products.product.add_to_cart
with Pre-order
(leaving all other punctuation intact), then your Add to cart button text should change to read Pre-order instead.
If you are tracking inventory for a product, then you might want to allow customers to purchase pre-order products even if they have an inventory amount of 0.
To edit the inventory settings for a product:
Note: This setting is available for each variant, so you must change the setting for each one that you would like to be available for pre-order. You can edit all the variants of a product at the same time by using bulk editing.
TyW | Online Community Manager @ Shopify
- Was my reply helpful? Click Like to let me know!
- Was your question answered? Mark it as an Accepted Solution
- To learn more visit the Shopify Help Center or the Shopify Blog
Hi,
This worked for me, except that now it made the order text boxes wider, thus making the product image smaller. How can I get the layout back to how it was (red shirt), with the Pre-Order changes? See images below
I cannot find the Add to cart section in the code to edit for the pre-order?
I have followed the instructions and am using Debut theme. Pre-order button is working, but for the variant that I have in stock, it still says pre-order. How do I adjust this so it actually shows as an add to cart variant? Thanks for the info so far.
I've followed all intrucstion and using the Debut theme. It works well on the product page, showing Pre-Order Button. But once testing to place the order, i got the error message : "Your cart has been updated and the items you added can’t be shipped to your address. Remove the items to complete your order."
The shipping rules have been set same as all other products... so I'm on sure where the problem is ?
I am also having this issue, did you ever resolve it?
hi did you get any response to this ?
are you still searching as well?
All of my items are now on prep-order even the one that are in stock
hi i searched through the file and i dont have this
addToCart: {{ 'products.product.add_to_cart' | t | json }},
in there
This worked for me but my variants currently in stock now show as 'Pre-order'.
How do I fix this?
Thanks in advance!
Has anyone use Pre Order Now or other plugins? My concern is the access level that those plugins require to your account. I am curious why Shopify just doesn't allow this as their base functionality in there platform.
I have the Venture theme and the code is not the same as the instructions, and based on comments it appears that variants will not work?
Has anyone done this with the venture theme?
This is my question too. I've been asked to review this process to see if we can offer pre-order for out of stock products in our shop. Looking over the steps it seems that the end result of following this tutorial would have your product page always show the preorder button regardless of stock quantities.
This code discriminates based on availability:
<span data-add-to-cart-text>
{% unless current_variant.available %}
{{ 'products.product.sold_out' | t }}
{% else %}
{{ 'products.product.add_to_cart' | t }}
{% endunless %}
</span>
This code just always shows the same Preorder text:
<span data-add-to-cart-text>
{{ 'Pre-order' | json | remove: '"' }}
</span>
Additionally, why does this snippet hard-code the Pre-order text rather than using the settings data? And why is it piped through the json filter and removing quotes. I'm probably just missing something here so I feel like there needs to be a bit more explanation around this thinking.
I get that this would only happen for products where you change the template from `product` to `product.pre-order`, but is that the expected workflow here, that you have to manually change the template whenever you notice that you're out of stock?
Wouldn't it be better to replace the text with similar logic?
<span data-add-to-cart-text>
{% unless current_variant.available %}
{{ 'Pre-order' | json | remove: '"' }}
{% else %}
{{ 'products.product.add_to_cart' | t }}
{% endunless %}
</span>
Also the tutorial doesn't mention anything about what the practical implications are, if any, of switching from automatically to manually capturing payments. Does this affect the way orders are placed? Charged? The workflow around order completion?
Again, I'm sure I'm missing something here, so if anyone can answer any of these questions I'd appreciate it. Thanks!
Hi, I followed all the instructions on this and I replaced the code with the one you said because mine all said pre-order disregarding the availability. However, once I changed it, I test it and set an item to no stock and it still says add to cart? How do I fix this? I have the debut theme btw.
I can't seem to find the Themes Templates sidebar section. I followed the instructions in 1 and 2, but see no reference to Theme Templates on the product page.
Where is this?
Thanks.
Is it possible to create a confirmation email specifically for when a pre-ordered item is purchased?
I followed all the steps ,however the products image became smaller and some coding text appeared at the bottom of product description
so I deactivated the product on preorder
I followed the instructions for the pre-order template and now have one. But the product images don't show up as a grid. What do I need to change? I'm on Brooklyn theme (sectioned). Thanks!
I got this to work using some of the tips in the comments; however, I have 1 weird issue remaining:
When you load the product page, it says "add to cart," but when you switch the variant, it swaps over to "pre-order" and stays that way for all of the variants. How can I get it to read "pre-order" when you land on the page rather than having the awkward swap?
Thank you!
Sorry for the slow response here. Yes this is possible. You'll want to set the button text as well for the product. Please feel free to email or DM me.
Hi there,
Thanks so much for sharing this! I've gone through and edited all the code as you said to do- but when I go to the product to change the "Theme Template" it still only have the option of 'default product' and don't give me the option for 'product-pre-order'. I have everything saved exactly as the instructions stated and I've tried twice now! Hoping you can help me with this!
Hi everyone,
Just adding to this thread as Dawn will be the new default template in Shopify soon.
A lot of the same applies, but app blocks/sections-everywhere is a big change.
I put together this guide over the last couple of weeks on integrating with and without an app.
Cheers,
Oli
——————————
Founder @ www.preproduct.io
The smarter way to launch products.
Hi,
I'm using narrative theme and have followed the sectioned theme instructions. I have changed all of my products to the pre order template (after recoding with your guide), I disabled the dynamic checkout buttons, changed the capture setting to manual, turned the quantity to 0, and allowed the product to be sold after selling out and the preorder button still doesn't appear. Do you have any other suggestions?
Thank you!
-Hana
Does this work with subscription too? I'm using ReCharge shopify app for reocurring subscription.
Starting a B2B store is a big undertaking that requires careful planning and execution. W...
By JasonH Sep 23, 2024By investing 30 minutes of your time, you can unlock the potential for increased sales,...
By Jacqui Sep 11, 2024We appreciate the diverse ways you participate in and engage with the Shopify Communi...
By JasonH Sep 9, 2024