Product pages - Allow pre-orders for products

TyW
Community Manager
Community Manager
435 50 1182

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.

pre01.png


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

Replies 119 (119)
Jennifer42
Tourist
11 0 4

I would be so grateful If you have time to send me code modification please, that's the only thing missing for me !!! thank you so much @Alex-Miller 

 

San_Sio
Visitor
1 0 0

I am using Warehouse Theme. I cannot find these codes,

addToCart: {{ 'products.product.add_to_cart' | t | json }}, 
<span data-add-to-cart-text>
{% unless current_variant.available %}
{{ 'products.product.sold_out' | t }}
{% else %}
{{ 'products.product.add_to_cart' | t }}
{% endunless %}
</span> 

 Hope you can help me. Thanks.

ShopMaster99
Excursionist
31 0 25

This pre-order option looks like it could work really well for me. For those of you who have tried it, please let me know how the buttons work. If I change my product to the pre-order template but only set one variant to allow ordering when out of stock, do my other variants still show the 'buy now' and 'out of stock' buttons?

stellar97
Visitor
2 0 1

This was so helpful! Thank you for doing this! if anyone is looking for how they can delete the buy it now button here's a link to that! https://community.shopify.com/c/Shopify-Design/Removing-quot-Buy-it-Now-quot-button-on-some-of-my-pr...

Cloxy16
Tourist
4 0 2

Hello I followed this and it worked thank you! Can someone explain additionally how to add a ship date message to appear along with the pre order button so customers know when to expect shipping?

JerneDesign
Tourist
4 0 2

I managed to get around this by replacing the text between the comment tags below

{%- comment -%}
Live region for announcing updated price and availability to screen readers
{%- endcomment -%}

with 


This product is temporarily out of stock, but you can PRE-ORDER it now and we will put it into production and deliver it to you as soon as possible. Payment is due at the time of purchase, and you will receive a shipping notification once the order is on its way to you.

 

in the product-pre-order-template.liquid code in the debut theme

 

Just replace the message with whatever you feel is appropriate.

ecompro
Tourist
57 0 2

Nice tutorial

A 1 second decrease in load speed can increase conversions by 1% – 7%. Get your store optimized by a Shopify expert
neeka_feh
Tourist
7 0 1

Where / when will this message pop up? Thanks for the comment btw! I successfully have added the pre-order button & removed the BIN button but now I want to make sure the customer knows the item is on pre-order. 

Valerossa
Visitor
2 0 0

My template doesn't seem to have 

<span data-add-to-cart-text>
{% unless current_variant.available %}
{{ 'products.product.sold_out' | t }}
{% else %}
{{ 'products.product.add_to_cart' | t }}
{% endunless %}
</span>

instead it has

  <link itemprop="availability" href="http://schema.org/{% if current_variant.available %}InStock{% else %}OutOfStock{% endif %}">
{% include 'product-form' %}

What can i do?

ruddygoodpizza
Visitor
1 0 1

I have the new Express Theme and I can't find this code

addToCart: {{ 'products.product.add_to_cart' | t | json }},

Help anyone ?

kkkkate
Visitor
1 0 0

 I am using minimal and this part isn't there..

addToCart: {{ 'products.product.add_to_cart' | t | json }},

In fact this is the only code I have..

{% 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' %}

 

(It's also not in the sections)

 

Anyone able to help please?

ClarkL
Visitor
3 0 0

did you ever get an answer to this? 

wearejewels
Visitor
1 0 0

I followed the step by step instruction but i could not find the following script that need to look for in product.pre-order.liquid file.

 

addtocart {{ 'Pre-order' | json }},

My template is Canopy please can you help. 

samueldthomas
Tourist
7 0 3

For anyone looking to find the "missing code" I finally found the answer.

 

You can usually find the script in theme.liquid - but you cannot use the same code listed here as it will change ALL buttons to pre-order. 

Instead replace it with the line:

addToCart: {%- if template.suffix == 'pre-order' -%}{{ 'Pre-order' | json }}{%- else -%}{{ 'products.product.add_to_cart' | t | json }}{%- endif -%}

 

SaraSteapedSlow
Tourist
9 1 8

This is in response to comment:

 

Thank you this worked for me. One thing to note, when I copied and replaced this line of code verbatim it broke my nested menu. When I added the "," to the end of the line of code it worked perfectly. 

SydneyRugsOnlin
Visitor
3 0 0

Hi There 

Thank you for you help , notes for pre -order , 

I have a problem from the begin , 

I have created a pre-order-templet  but there is no  add_to_cart  line at all  after  <script>  line there is nothing instead of lines for other Apps.

I will appreciate very much if you could help me as I donot like to add another app for pre order .

Thanks 

bsidesmetal
Visitor
1 0 0

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.

sellysells
Visitor
1 0 1

Did you ever get an answer? This is the issue with mine

Alex-Miller
Excursionist
18 2 4

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

https://community.shopify.com/c/Shopify-Design/Product-pages-Allow-pre-orders-for-products/m-p/62591...

2.  BUT skip this part of the tutorial

Alex-Miller_0-1613025289763.png

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 

AIMHUGE GROWTH CONSULTING
Alex@aimhuge.com
Alex-Miller
Excursionist
18 2 4

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>

 

AIMHUGE GROWTH CONSULTING
Alex@aimhuge.com
leatheraholicx
Tourist
10 0 4

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:

Screenshot 2021-07-05 at 1.35.08 PM.jpg

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

 

Alex-Miller
Excursionist
18 2 4

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.

AIMHUGE GROWTH CONSULTING
Alex@aimhuge.com
Sarah07
Visitor
1 0 0

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.

Mattia234
Tourist
4 0 1

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. 

YuriLee
Visitor
1 0 0

If I change my payment to manually capture payment, will this affect all other purchases outside of the pre-order style?

rnickerson
Tourist
3 0 2

@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...

tangeklang55
Visitor
1 0 0

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?

ootdnewyork10
Excursionist
19 0 8

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. 

NormaLili
Visitor
2 0 0

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?

NevWally_31
Visitor
1 0 2

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?

jocelynkellner
Excursionist
27 0 1

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. 

 

Screen Shot 2021-01-26 at 12.43.30 PM.pngScreen Shot 2021-01-26 at 12.43.35 PM.png

luxuriaistanbul
Excursionist
33 0 4

Thank you for the solution, this worked for my debut theme shop!

zeffire
Visitor
2 0 1

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.

zeffire_0-1614241718955.png

 

May I know how I should do that?

hasheleyc
Excursionist
12 0 28

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.

henriettaprice
New Member
6 0 0

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