All pages
Powered by GitBook
1 of 15

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Product Views

Product Layouts

While building Product and Attribute Layouts, a large range of dynamic data is available- here is a full reference guide.

"This" Object Fields

The "this" object can be accessed on Product detail/item.liquid, list/item.liquid and attribute layout files. It contains the properties of the current Product and contains further relevant objects e.g. Price.

The entire "this" object can be outputted on the page for reference: {{this | json}} The following fields are available:

Accessing Custom Field Sets

Custom Field Set data linked to Products is available in Product detail/item.liquid, list/item.liquid and attribute layout files.

Any Custom Field Sets that have been associated with the product will be stored under: {{this.cfs_data}}

You can output the above liquid in the item.liquid file to see all of Custom Field Sets associated with the Product. Each of these will have the key "cfs_1", "cfs_2" etc. For example, a developer has created just one Custom Field Set to store information about the Guarantee on the Product. The field can be accessed via: {{this.cfs_data.cfs_1.Guarantee}}

See more information about Custom Field Sets .

The Price Object

The Price object contains all the information you need to display the Product's price in the format you want. It is available in Product detail/item.liquid, list/item.liquid and attribute layout files.

The Inventory Object

The Inventory object contains the fields related to the current Inventory of this Product. It is available in Product detail/item.liquid, list/item.liquid and attribute layout files.

The Attributes Object

These are available once Attributes have been added against the Product in Admin and you are inside a detail/item.liquid file or an Attribute layout file.

You can access the Attributes Object via the following liquid output: {{ this.product_attribute_options }}

Inside the Attribute Layout

Output Options for this Layout

Inside the Attribute Layout, you can access just the Options for that specific Attribute: {{ product_attribute_options }}

Output this Attribute's Name

You can also access the name of the Attribute this Layout is currently displaying: {{this_attribute.properties.name}}

Looping Over Attribute Options and Accessing Option Fields

As explained in the Attributes Layout Doc, we recommend you loop over the object and access the fields via the "option" liquid variable.

Assuming the above example liquid forloop has been implemented, you can access the fields in the table below. Remember the "option" liquid variable can be renamed, so if you have done this, replace "option" with the name you have given the variable. The Object contains Attribute Options and each of these contains information on the Attribute it is linked with.

Volume Pricing

Information about how to output information about volume pricing can be found here:

{{this.price.price_display}}

If the optional field Display Price was filled out when the Product was created, this will show that price as an integer, else, it will output null. This could be for example the RRP or price before tax.

Currency Symbol

{{this.price.currency_symbol}}

The HTML entity for the currency symbol. e.g. "£" outputted on the page will display "£" when HTML is rendered.

Price Display Formatted

{{this.price.price_display_formatted}}

If the optional field Display Price was filled out when the Product was created, this will show that price as an decimal number, else, it will output null. This could be for example the RRP or price before tax.

Price Charge Formatted

{{this.price.original_price_charge_formatted}}

This is the price that will be charged to the user, formatted into dollars and cents.

Price Charge Before Tax Formatted

{{this.price.price_charge_before_tax_formatted}}

This is the price before any tax is applied, formatted into dollars and cents.

{{this.inventory.inventory_type}}

The type of Inventory. Currently, only "Global" is available.

Display Type

{{this.inventory.display_type}}

This stores the policy on what to do when the Inventory reaches zero. Either the Product can not be ordered, or it should be hidden from view.

{{ option.price_display }}

Display price for this Attribute Option

Attribute Option Display Price Formatted

{{ option.price_display_formatted }}

Formatted display price for this Attribute Option

Attribute Option Image

{{ option.image}}

The image for this Attribute Option

Attribute ID

{{ option.product_attribute.id }}

The Unique ID of this Attribute

Attribute Name

{{ option.product_attribute.name }}

The Name of the Attribute e.g. Size or Colour

Attribute

{{ option.product_attribute.product_id }}

The Unique Product ID that this Attribute is associated with.

Field Name

Liquid Tag

Description

Item Name

{{this.name}}

The Product's name

Item Slug

{{this.slug}}

The part of the URL for this Product's Detail Page which refers directly to this Product

Creation Date

{{this.create_date}}

The date the Product was created in Admin

Last Edit Date

{{this.last_edit_date}}

The date this Product was last edited in Admin

Release Date

{{this.release_date}}

The date this Product is scheduled for release, or was first released on the Site. (A Product will not appear in the list if it has not been released.)

Expiry Date

{{this.expiry_date}}

The date this Product will be no longer visible on the Site. (A Product will not appear in the list if it has expired.)

Enabled

{{this.enabled}}

A "true" or "false" boolean value. If "false", the Product will not appear in the list.

Category Array

{{this.category_array}}

An array of ids of categories associated with this Product.

Description

{{this.Description}}

A description of the Product.

Image

{{this.Image}}

This is the main image for the Product, but more can be added with Custom Field Sets.

Field Name

Liquid Tag

Description

Price ID

{{this.price.id}}

The unique ID of this Product's price.

Product ID

{{this.price.product_id}}

The unique ID of the Product this Price belongs to.

Currency

{{this.price.currency}}

The currency code for the currency used by this Product e.g. "GBP".

Price Charge

{{this.price.price_charge}}

The price of the Product as an integer e.g. for the price "£200.00" this field will display "20000"

Field Name

Liquid Tag

Description

Inventory ID

{{this.inventory.id}}

The unique ID of the object containing the Product's Inventory.

Enabled

{{this.inventory.enabled}}

A "true" or "false" boolean, defaults to true.

Product ID

{{this.inventory.product_id}}

The unique ID of the Product this Inventory Object belongs to.

Quantity

{{this.inventory.quantity}}

The number of products in the inventory.

Field Name

Liquid Tag

Description

Attribute Option ID

{{ option.id }}

The unique ID of this Attribute Option

Attribute Option Name

{{ option.name }}

The name of this Attribute Option

Attribute Option Chargable Price

{{ option.price_charge }}

Chargable price for this Attribute Option

Attribute Option Chargable Price Formatted

{{ option.price_charge_formatted }}

Formatted chargable price for this Attribute Option

here
Volume Pricing

Display Price

Inventory Type

Attribute Option Display Price

<select name="attr1" class="form-control" data-attribute-control="{{product_attribute_id}}" onchange="s_e_update_price()">
  {% for option in product_attribute_options %}
    <option value="{{option.id}}" data-attribute-price-control="{{option.price_raw}}">{{option.name}} this.price.currency_symbol}}{{option.price}})</option>
  {% endfor %}
</select>

Attribute Selection

Shipping Selection

Dynamic Product Layouts based on Categories

Wondering how to adjust the Product Detail Page based on Category?

Answer:

As a User navigates to your Product Detail Page, Siteglide will load the Detail View you have specified in your eCommerce Settings. However, it is perfectly possible to customise this based on Categories, using Liquid logic! You can read more about using Categories on the Layout of the WebApp or Module Item they belong to here.

In this example, you'd need to know the ID of a category you want to display; this can be found in Admin when you select a category. E.g. let's say we want to display something special when something has the category "Featured" and you know it has an ID of "111111":

{% assign featured_id = "111111" %}
{% for category_id in this.category_array -%}
  {% if category_id == featured_id %}
    <!-- Add Featured Content Here -->
  {% endif %}
{% endfor %}

Product List Layout

Similar to WebApp List Layouts, a Product List Layout can allow users to browse Products. It can be filtered and sorted too!

Prerequisites

  • You have created Products in the Admin

Getting Started

This Tutorial will show you how to output a list of Products on your site.

It will cover how to:

  • Find where Product layouts are stored on Code Editor

  • Develop a wrapper.liquid file

  • Develop an item.liquid file

Add a List of Products to a Site

Parameters:

  • layout - choose the layout file for this list.

  • category_ids - filter the List by these category ids

  • sort_type - the field you wish the sort by

Folder Structure

If you need to refer to the folder structure for where layout files should go, refer to this:

Creating a new set of Product Layouts

To create a new set of Product layouts- create a new folder bearing the name of your layout, and create within it:

  • product

    • name_of_my_layout

      • list

        • wrapper.liquid

List Layout Development

A list view for products is made up of two parts.

wrapper.liquid

The wrapper contains the code for the main part of the section you are building. For example, the section title or some margin or padding that separates your list from other sections.

In the wrapper.liquid file, it is important to include the liquid file which loops over the Product items:

The item_layout parameter should be the name of a liquid file in the same folder as the current file. Usually this will be "item", but you could have an alternative Layout.

item.liquid

item.liquid -- list view example

This file contains the code for each iteration of the loop that displays the Products. You should expect this code to be rendered multiple times; once for each product displayed in the list. (Hint: Try not to run any GraphQL calls inside a loop or item.liquid file, as they would have an impact on performance. It is better to run these inside the wrapper.)

As it is inside the loop, the item.liquid file has access to the "this" object and dynamic information specific to an individual product. A full reference for the fields you can use can be found or you may find it convenient to output the "this" object on the page you are developing:

Output all data available in the "this" object: {{this | json}}

Adding to Cart on the List View

Marking Separate Products to support the Advanced Features of Adding to Cart on a Product List View

In order to help the JavaScript understand which Quantity and Attribute Control belongs to which Product, we've added a new requirement to Product List Layouts. Please add the following data-attribute on the highest-level HTML element in your item.liquid file.

In this example, the highest level element in the file is a <div> element which is wrapped around the rest of the content in the file, but yours could be any element. The important thing is that this element is wrapped around any controls in the File.

For old sites which do upgrade the eCommerce Module, but do not add this data-attribute, we'll add a console log in dev-tools to act as a reminder, but any functionality which worked previously will continue to work.

Adding to Cart on the List View

As with Detail Layouts, you'll need to include the following Liquid and HTML code within the item.liquid file. It's also now important that these elements lie within the element with the data-product-group Attribute, when you're building a List Layout. See the section above for details.

The "Add to Cart" Button

For more on developing the Add to Cart Button:

The Quantity Control

This is mandatory, but can be hidden and hard-coded to have a value of 1, if you want to simplify the UI:

Attribute Control

As this code can be complex, so please refer to the doc for further information, or take a look at the full example below.

Full Example: Example of an item.liquid file in a Product Layout which supports Adding to Cart:

sort_order - 'asc' or 'desc' - the order you wish to sort by.
  • use_search - See WebApp Search

  • use_adv_search - See WebApp Adv Search

  • type - Should be list, for a List View layout. This can also be used to display different types of layouts, like a Cart in a different context.

  • show_pagination - if pagination should be displayed after the products. Default is 'true'

  • item.liquid

  • detail

    • wrapper.liquid

    • item.liquid

  • Cart and Checkout Folder Structure
    here
    Add to Cart Button
    Attributes Layout
    {%- include 'ecommerce/products'
        layout: "products"
        category_ids: current_category_id
        type: 'list',
        show_pagination: 'true'
    -%}
    
    
    
    <div class="row">
      <div class="card-deck"> 
        {%- include 'modules/siteglide_ecommerce/ecommerce/get/get_products'
          item_layout: 'item' 
        -%}
      </div>
    </div>
    
    
    {%- include 'modules/siteglide_ecommerce/ecommerce/get/get_products'
        item_layout: 'item' 
    -%}
    <div class="card">
      <div class="card-img">
        <a href="/{{this.module_slug}}/{{this.slug}}">
          <img src="{{this.Image | asset_url}}" alt="{{this.name}}" class="card-img-top">
        </a>
      </div>
      <div class="card-body">
        <a style="height: 100%" href="/{{this.module_slug}}/{{this.slug}}">
          <h3 class="card-title">{{this['name']}}</h3>
          <p>{{this.price.currency_symbol}}{{this.price.price_charge_formatted}}</p>
        </a>
      </div>
    </div>
    
    
    <div class="card" data-product-group>
      <div class="card-img">
        <a href="/{{this.module_slug}}/{{this.slug}}">
          <img src="{{this.Image | asset_url}}" alt="{{this.name}}" class="card-img-top">
        </a>
      </div>
      <div class="card-body">
        <a style="height: 100%" href="/{{this.module_slug}}/{{this.slug}}">
          <h3 class="card-title">{{this['name']}}</h3>
          <p>{{this.price.currency_symbol}}{{this.price.price_charge_formatted}}   </p>
        </a>
      </div>
    </div>
    
    
    
    
    <input type="number" 
           min="1" 
           max="{{this.inventory.quantity}}" 
           data-quantity-control id="quantity" />  
    
    
    <input readonly hidden type="number" 
           min="1" 
           max="1" 
           value="1"  
           data-quantity-control id="quantity" />
    
    
    <div class="card" data-product-group>
      <div class="card-img">
        <a href="/{{this['module_slug']}}/{{this['slug']}}" title="">
        <img src="{{this['Image'] | asset_url}}" alt="{{this['name']}}"></a>
      </div>
      <div class="card-body">
        <h2 class="card-title">
          <a href="/{{this['module_slug']}}/{{this['slug']}}" title="">{{this['name']}}</a>
        </h2>
        <p>{{this.price.currency_symbol}}{{this.price.price_charge_formatted}}</p>
      </div>
      
    {% include 'ecommerce/cart_add' -%}
      <label for="quantity">Quantity</label>
      <input type="number" min="1" value="1" data-quantity-control id="quantity" />
      {% comment %}-----The following liquid code block loops over all attributes on this Product----{% endcomment %}
      {% for attribute in this.product_attributes %}
        {% if attribute.properties.enabled == true %}
          {% include 'ecommerce/product_attributes' name: attribute.properties.name layout: 'demo_site_attributes' -%} 
        {% endif %}
      {% endfor %}
      <div class="card-footer">
        <p class="tag">
          {% for category in this.category_array %}
            <a class="btn btn-primary" href="{{context.exports.categories.items[category].full_slug}}" title="">
              <i class="fas fa-tag"></i>{{context.exports.categories.items[category].name}}
            </a>
          {% endfor %}
        </p>
      </div>
    </div>  

    Shipping Options Layout

    Shipping Options let customers choose how fast they'd like eCommerce Products delivered and prices are added onto the price at Checkout.

    Introduction

    Shipping Options let customers choose how fast they'd like eCommerce Products delivered and prices are added onto the price at Checkout.

    Here's what it does:

    • Admin Users can add and remove Shipping Options e.g. "Free Delivery", "Premium"

    • You can output the Shipping Options in your Cart with their own sub-layout

    • Once chosen, the Shipping Option will be saved alongside the customer's Cart and the price of shipping will be added to the total price displayed.

    • When an Order is made, the customer will pay for the price of Shipping and the option chosen will be displayed against their Order in the Admin.

    Managing in the Admin

    You can add, edit and remove Shipping Options in the Admin. Go to ECOMMERCE/Shipping Options in the left-hand menu.

    Including the Options

    The Options are designed to be included in an HTML Select box in the Cart.

    Syntax

    You'll need to add the following Liquid where in your Cart you want to include your Shipping sub-layout:

    The only parameter you'll need to include is your Layout.

    You won't need to do anything else to implement this feature. Any options selected by the customer will have their prices added to the price total in Checkout.

    Custom Layouts

    File Structure

    Include your Custom Layout alongside my_layout:

    Here's an example:

    Some key points to note from the example:

    • You'll need to put the onchange attribute on the HTML Select element itself and use the Siteglide function.

    • You'll need to loop over the shipping_options array we've created for you to build your HTML Option elements.

    • You can use a Liquid if statement to mark an option as the Shipping Option currently selected by the User: `

    `

    Discount Selection

    📂 Discount Selection

    Introduction

    We're introducing Discount Codes to our eCommerce Module.

    Your Client will be able to define and manage codes in the Admin- and manage their offers by setting the release and expiry dates, as well as the maximum number of uses in advance.

    Minimum Payments

    Introduction

    Discount Codes can cause the payment total due to be smaller than your Client may wish- or even 0.

    When accepting payments, most Clients won't want to handle very small payments e.g. less then 50 cents.

    Why are small charges a problem?

    Stripe's payment gateway will, in fact, refuse to process payments smaller than its minimum payment amounts, which will lead to bad User Experience as Payments will fail.

    PayPal will accept these small payments, but will charge the Client potentially more than they make on the transaction.

    The solution for Basic Payment Forms and Checkout

    This Article will explain the two main solutions to these small charges:

    • Recommended - The Agency and Client can set Minimum Spend against each discount Code

    • Fallback - While applying discounts, Siteglide rounds payments up to an absolute minimum the Payment Gateway will accept.

    In the future, we plan to change the flow so that Siteglide will accept 100% discounts in the Checkout by skipping the Payment step. For now- we'll recommend alternatives if you need this functionality.

    Avoiding Small Charges

    In the following section, we'll refer to the "minimum desired spend". By this, we mean either:

    • The lowest value order your Client is willing to accept (bearing in mind they still need to pay the charges due to the Payment Gateway on this Order).

    • If using Stripe, this will be at least 50 of your currency's lowest denomination e.g. cents

    • If using PayPal, this will be at least 1 of your currency's lowest denomination e.g. cents.

    Setting the Minimum Spend as the Agency or Client

    The main method the Agency and Client have at their disposal to prevent this is the Minimum Spend field when creating or editing their Discount Codes.

    This field should be set up to make sure that if it's value has the discount applied, the total price due would still exceed the minimum desired spend.

    E.g.

    For percentage discounts - you should check that if the percentage discount is applied to the value in "minimum spend" it won't leave a total which is lower than the minimum desired spend:

    e.g. In this example, let's assume it's only economically viable for the Client to accept spends of 50 cents or more- this is their "Desired Minimum Spend" (your Client's may well be different!).

    In the screenshot below- even with a 90% discount, the minimum spend is high enough to avoid excessively small charges:

    $5.00 multiplied by 90 divided by 100 is a saving of $4.50.

    $5 dollars with a $4.50 dollar discount leaves a remaining payment due of $0.50.

    For value discounts the calculation is simpler - "Minimum spend" minus "value" should be greater than minimum desired spend.

    E.g. For a $9.50 discount, you need a "Minimum Spend" of $10 to prevent discounts from allowing a spend below $0.50.

    As explained below, Siteglide will take its own steps to avoid very small charges, but using the Minimum Spend field is the easiest way to make these limits clear to Users, improving their experience. It also allows the Client to decide if their minimum desired spend is greater than the Payment Gateway's value.

    How Siteglide Handles Small Charges on Basic Payment Forms and Checkout While applying discounts, Siteglide will automatically check if the total price due is below the absolute minimum needed for the Payment Gateway to accept the Payment.

    If this is the case, Siteglide will automatically adjust the total price due to:

    For Stripe, 50 of your currency's lowest denomination e.g. cents For PayPal, 1 of your currency's lowest denomination e.g. cents This will display on the Cart, and be the total amount actually charged to the User's Card.

    Informing Users

    Again, setting a reasonable Minimum Spend is the preferable solution to this issue, but in the case that Siteglide does need to fall-back and round charges up to the minimum payment, you can inform the Users of this with a message.

    This code can be used inside your Discount Code Layout:

    Subscriptions

    Stripe Subscriptions handle this problem differently. The variable discount_saving_maximum_reached will always return false for Subscriptions discounts, as we will never manually cap the amount of Discount for these kinds of payment.

    Firstly, Subscriptions allow you to give 100% discounts- this effectively creates one form of "free trial".

    Secondly, if Stripe judge a Subscription invoice to be for an un-economically small sum, they will carry that charge over to the next invoice. In the same way, if the discount gives a greater reduction in cost than the spend, the customer will receive credit in the Stripe account, which will be carried over into the next invoice. If you do not wish for this behaviour, see Setting Minimum Spend above!

    What if I actually want to apply 100% discounts on Basic Payment Forms and Checkout?

    Currently, it is not possible to offer 100% discounts on Checkout using Stripe or PayPal.

    In the future, we intend to better support 100% discounted Orders by completing the Order without carrying out a Payment, however, we expect values between 0 and the Payment Gateway's minimum to continue to be rounded up.

    The following alternative Form types do currently allow Users to complete them with Payments of 0:

    Our Quote Only feature for these customers- as this does allow Orders to be created without any charges being made- meaning the Client will not be charged. Our Basic Payment Form with Stripe will already skip payment if the amount due is exactly zero and the Minimum payment value field attached to the Form in Admin is also 0.

    {% include 'ecommerce/shipping_option', layout: "siteglide_example" %}
    
    └─`layouts`
      └─`modules`
        └─`module_14 (eCommerce)`
          └─`shipping_option`
            ├── `siteglide_example.liquid`
            └── `my_layout.liquid`
    <div class="form-group">
    	<select onchange="s_e_cart_shipping(this);">
    		<option value="">--Please select--</option>
    		
    {%- for this in shipping_options -%}
    			{% assign currency = this.price.properties["module_field_14/price_2"] %}
    			<option {% if this.id == current_cart_shipping_id %}selected{% endif %} 
    					value="{{this.id}}">{{this.name}} {{this.currency_symbol}}{{this.price}} 
    					</option>
    		{%- endfor -%}
    	</select>
    </div>
    {%- if discount_saving_maximum_reached == true -%}<!-- Message here --><p>Minimum total price reached. Unfortunately we cannot accept payments below this price. To make the most of your discount, try adding another item to your cart.{%- endif -%}

    You'll be able to implement options in the Cart and Checkout for entering discount codes and the Module will work out the discounted costs for you.

    Managing Codes in the Admin

    You can see a list of all Discount Codes under the eCommerce Menu.

    Discount Codes List

    Available Fields

    You can set the following fields when you create or edit a Discount Code:

    • Item Name - Gives the discount a name

    • Weighting - (optional) - Used in sorting

    • Release Date - When should the discount code start being valid?

    • Expiry Date - When should the discount code stop being valid?

    • Enabled - Should the discount code be enabled or disabled?

    • Code - A String of characters for the code a customer will need to enter for - the discount to be valid.

    • Type - Should the discount be a percentage of the total Cart value, or a fixed - amount?

    • Discount Value - How much of a discount should be given when this code is - entered? Choose a value appropriate to the type you selected e.g. 20 for 20% - or 20.00 for $20.00

    • Minimum Spend - Often your Client will want to use the offer to up-sell to the - customer. By setting a minimum spend, the customer will need to spend this - amount before the offer can be used. The offer will apply to the entire value - of the Cart still, not the difference between the minimum spend and the Cart - value.

    • Uses Remaining - This sets a total number of uses before the offer - automatically expires. This does not measure the number of times an individual customer uses the offer, rather it measures the number of times the offer has - been used globally. If your Client does not want to set a limit, you can set a - very large number- or your Client can increase the number when it runs low.

    • Valid on Payment Form Type - Choose 'Checkout' (default), 'Basic Payment' or 'Subscription'. The discount code will only be applicable to the specified - Form type. This is useful when you have both Checkout Forms and Basic Payment Forms on your Site with different purposes.

    Special Fields for Subscriptions Discount Codes

    When "Valid on Payment Form Type" is set to "Subscription", a "Coupon" will be created on the connected Stripe account. Therefore, extra fields are needed for this type:

    • Number of Months to Discount - Even if your Subscription's Interval is days or weeks, this field must be measured in whole months. The discount will apply to - every invoice until the months are finished, after which the price will revert - to the price defined in the Subscription's plan.

    • Stripe Coupon ID - This field will be filled automatically. You can use it to look up the associated Coupon in the Stripe Dashboard.

    Create a New Discount Code

    From the List View, you can create a new Discount Code.

    Discount Codes List

    Edit an Existing Discount Code

    Find your code in the List, and use the pencil icon to edit.

    Discount Codes List

    Delete a Discount Code

    From the Edit screen, you can delete a Discount Code.

    Discount Codes List

    Orders

    If customers have used a Discount Code to make a purchase, you'll be able to see this against their Order. You can see customers' Orders under the eCommerce Menu in Admin.

    Adding an Input Field for Codes in the Cart Layout

    In the next Article, we'll show you how to add and develop a Discount Codes Layout.

    This will allow Users to type in and apply a Code, or remove a Code if it no longer applies and is preventing them from checking out:

    Discount Codes List

    Attributes - Changing Product Price after Change

    This Article will look in detail at the JavaScript function which updates the Product price as the customer selects Attributes.

    Prerequisites

    • Your eCommerce Module should be updated to version 1.0.5 to get the latest version of this feature described by this Article. Earlier versions of the Module will have limited support for this feature on Product List views.

    • You have on some of your Products and nested inside your Product Layout.

    Introduction

    On the Product List and Detail Views you can provide customers with an option to select Product Attributes- changing features like "size" or "colour", depending on the Product.

    This Article will look in detail at the JavaScript function which achieves this and adjusts the displayed Price of the Product appropriately.

    A note on security: the prices we are working with in this topic are cosmetic only. There's no need to worry about malicious users "choosing their own prices" at this stage, as prices will be calculated afresh securely on the server if and when an Order is created.

    The s_e_update_price() Function

    What it does

    This function will update the currently displayed price of a Product to take into account any selected Attributes.

    Where it's commonly used

    To optionally set the initial prices to be displayed on:

    • Product Detail View

    • Product List View (support added in eCommerce version 1.0.5)

    To update the prices to be displayed on:

    • Product Detail View

    • Product List View (support added in eCommerce version 1.0.5)

    Arguments and Usage

    Optional - To Display the Initial Price

    To display the initial price of a Products on the Product List, or Detail View, on Page Load, you can run the function within the following Event Listener. No arguments are required.

    To Update the Price on Attribute Select

    To watch an Attribute for change, add the listener: onchange="s_e_update_price()"to the <select> element in your chosen Attributes Layout:

    Usage Notes

    The JavaScript looks for data in the HTML attributes in order to make its calculations. In the usage notes below we'll detail everything you need to provide for this function to do it's work.

    Usage note 1 - Define the element which will dynamically display the product price

    The purpose of this function is to dynamically update the displayed Price, but the choice of where this should be within the Layout is up to you.

    To mark an element within the item.liquid file as being the element which will receive the dynamic price as its text content when calculated, add the following HTML attributes:

    • data-price-control

    • data-currency-control

    The value of these Attributes should be set using Liquid to the Product's initial price and currency:

    In this example above- we also add the initial Price to the text content of the element using Liquid on Page Load. Instead, you can run the function on Page Load to display the initial price, should you choose.

    Usage note 2 - Define the prices of Attribute Options

    In order to add the prices of Attributes to the base price- you'll need to define the prices against the <option> element that contains a selectable Attribute Option: data-attribute-price-control="{{option.price.raw}}"

    For example:

    Usage note 3 - When using this Function on the Product List View, add the data-product-group attribute to your item.liquid file

    If you're using this function on the Product List View, you'll need to carry out additional steps to define the container for each Product. This helps the JavaScript to smoothly identify relationships between Products, their Prices and their Attributes.

    The HTML attribute data-product-group should be added to the highest level HTML element in your Product Layout item.liquid file. Which type of tag this element is doesn't matter- the important thing is that all Prices and Attributes related to this Product are nested inside this element.

    If you do not add this Attribute- the JavaScript will treat the Product List like a Detail view- and you may experience unexpected behaviour like all prices changing at once.

    Conclusion

    This function is useful for updating the displayed price of a Product when new Attribute Options are selected- or removed- by the User / Customer.

    Add to Cart Button

    Customise the "Add to Cart" button to keep customers on the Page or redirect them straight to the Checkout Flow with a "Buy Now" button.

    Prerequisites

    This Article assumes you've already:

    • Added a "cart_add" button to a Layout.

    If you've not already done this, you can read the following Articles to learn more:

    created Attributes
    included an Attributes sub-Layout
  • Product List Layouts

  • Product Detail Layouts

  • Introduction

    Although we've had an "Add to Cart" button for a while now, we've recently added the ability to add a custom Layout for this component.

    This will allow you to:

    • Change the style of the button

    • Change the style of the button when the Product is out of stock

    • Change the behaviour of JavaScript when adding to the Cart is successful

    Specifying a Layout

    You can add a Layout to the Cart Add Button by adding a component_layout parameter to the Liquid:

    This feature is backwards compatible, so if you have a Site which does not specify a Layout for these buttons, the default Layout will be chosen automatically- and this will be identical to the style and behaviour you are used to.

    Layout Files

    We store these Layout files at the following path: layouts/modules/module_14/components/add_to_cart_button/my_custom_layout.liquid

    You can either edit the default Layout or create your own by right-clicking on the "my_custom_layout" folder.

    Code

    Looking at the default layout, you can see that it has some key characteristics you may wish to keep in your new Layout:

    • Checking if the Product is in stock

    • Running the JavaScript function

    Checking if the Product is In Stock (or no inventory limit is set)

    You can use a Liquid If Statement to check if the Product is in stock.

    Running the JavaScript Function

    To achieve the functionality of adding a Product to the Cart, you'll need to run a JavaScript function when the button is clicked. The first argument is mandatory- you must pass in the ID of the Product using Liquid: onclick="s_e_cart_add({{this.id}})"

    Customising the Success Alert

    Adding your own Function

    The second argument in the JavaScript function is optional. If you like, you can add in the name of a function you've defined on your Page. This will run instead of the default "alert" message when a Product is successfully added:

    As in the example above, you can use this to add a different alert message with a different message. Or you could run any other JavaScript you like instead.

    Customising the Success Alert along with Live Cart Update

    Remember, you also have access to the function: s_e_live_cart_update()which will return the number of Items now in the Cart. You could incorporate this number into the message.

    Buy Now Button

    Some eCommerce Sites require a "Buy Now" button which adds the Product to the Cart and then sends them directly into the Checkout Flow. You can turn your "Add to Cart" button into a "Buy Now" button using customisation options:

    <script>
    
       window.addEventListener('load', function() {
    
          s_e_update_price();
    
       });
    
    </script>
    <label for="{{attribute_name | slugify}}">{{name}}</label>
    <select name="attr1" 
            class="form-control" 
            data-attribute-control="{{this_attribute.id}}" 
            onchange="s_e_update_price()">
    {% for option in product_attribute_options -%}
    <option {% if forloop.first %}selected{% endif %} value="{{option.id}}" 
                data-attribute-price-control="{{option.price_raw}}">
    {{option.name}} (+{{this.price.currency_symbol}}{{option.price}})
    </option>
    {% endfor -%}
    </select>
    
    
    <p class="product-price" 
       data-price-control="{{this.price.price_charge}}" 
       data-currency-control="{{this.price.currency_symbol}}">
       {{this.price.currency_symbol}}{{this.price.price_charge_formatted}}</p>
    <option value="{{option.id}}" data-attribute-price-control="{{option.price_raw}}">
    
          {{option.name}} {{this.price.currency_symbol}}{{option.price}})
    
    </option>
    {% include 'ecommerce/cart_add', component_layout: 'custom_layout' -%}
    
    {% if this.inventory.id == blank or this.inventory.quantity != '0' -%}
      <!-- Product is in stock - or no inventory limit is set.-->
    {% else -%}
      <!-- Product is out of stock. -->
    {% endif -%}
    <button class="btn btn-primary" 
            onclick="s_e_cart_add({{this.id}}, my_success_function)">Add to cart</button>
    
    <script>
      function my_success_function() {
        alert('Ajouter au Panier.');
      }
    </script>
    <button class="btn btn-primary" 
            onclick="s_e_cart_add({{this.id}}, my_success_function)">Add to cart</button>
    
    <script>
      function my_success_function() {
        var cartTotal = s_e_live_cart_update();
        alert('Success! You now have '+cartTotal+' items in your Cart');
      }
    </script>
    <button class="btn btn-primary" 
            onclick="s_e_cart_add({{this.id}}, my_success_function)">Buy it now!</button>
    
    <script>
      function my_success_function() {
        window.location.href = "/cart";
      }
    </script>

    Steps to Datasource and Display Related Products

    How to use Module Custom Fields to output similar, related products

    Pre-requisites

    • Your eCommerce Module is updated to at least version 1.2.0

    • You have already and outputted them in List or Detail Layouts on the Site

    Introduction

    Module Custom Fields allow a wide range of use cases for connecting up different areas of your Site. In this Article we'll look at how you can create a new Custom Field for your eCommerce products to store similar, related Products which could be displayed on the Product's Detail Page.

    You could of course use this same technique with the Blog Module or any other Module or WebApp.

    Step 1) Add a new Custom Field to Products

    To add a Custom Field to Products, first select Edit Module Structure from the Products List in Admin.

    At the bottom of the available fields, you can find the Custom Fields section, and press the "Add new field" button.

    The name of your field can be whatever you want, here we'll call it Related Products. The Datasource Multi type prompts us to choose a Module or WebApp that we will be able to select Items from.

    When you're ready, press save and your new Custom Field will be set up. You'll then be able to use this field when creating and editing Products.

    Step 2) Add related Products to a Product

    In this example, we'll edit the new Custom Field on an existing Product to create a relationship with another Product. From the Product Edit Page, select the Custom Fields tab:

    As we used the Datasource Multi field type and selected Products as the Module to be linked to, Siteglide knows what we're trying to do and will help us find the related Items.

    Select as many as you need. Each Product's unique ID will be stored in array format in your Custom Field.

    When you're ready, save the Product.

    Step 3) From the Product Detail Layout access the Related Product IDs

    For the next steps (3 - 6), we'll be navigating to Code Editor to develop custom Layouts to display the Related Products Front End. We'll start by working in the "item.liquid" file of the Layout you're using for the Product Detail View. We'll nest a new List of Related Products inside this Detail Layout.

    Inside the item.liquid file, we can access the Custom Field by name:

    It is sometimes more reliable to access a field by its ID, in case the name is changed in future. E.g. {{this.properties.module_field_custom_14/product_1}}

    This outputs an array of the IDs of each of the related Products stored against our current Product. It should look something like this: ["55","75","147"]

    Step 4) Convert the Related Product IDs to a comma-separated String format

    In Step 5, we'll need to nest a new List Layout of Products inside the Detail Layout and filter this by the IDs of our Related Products. However, the IDs are currently in an Array format and the include Liquid tag's item_ids parameter expects a comma separated String.

    We can change the type by assigning a new variable:

    Step 5) Add a Product List Layout which Datasources to the Related Products

    Next, we need to output a Product List, nested within our existing Product Detail Layout.

    Item Ids Parameter

    Without the item_ids parameter, our List outputs only the first few Products alphabetically, instead of fetching our dynamic Related Products.

    We can change that by adding the item_ids parameter and feeding in our comma-separated String of IDs (that we stored in a new Liquid variable):item_ids: related_products

    Datasource Parameter

    datasource: 'true' When you output an include inside a Detail Layout, by default Siteglide will try to fetch a Detail Layout. This is one reason why it's important to set the datasource: 'true' parameter, which will then cause Siteglide to look for a List type Layout.

    Another benefit of the datasource: 'true' parameter is that if no Related Product IDs are available, the List will return empty, instead of returning an unfiltered List. This prevents the List from showing unrelated Products in this situation.

    Per Page Parameter

    per_page: '3' In the example, the per_page has been set to 3. In some cases, you may wish to limit the number of "related" results in this way, so they don't distract from the main subject of the Page. It is completely optional.

    Layout Parameter Select the name of a Product List Layout you'll use to style how the dynamic Related Products List will look (see Step 7).

    Step 6) Hide content when no Related Products exist

    Optionally, you can add Liquid logic to only display the subtitle and Related Products content when the field is not empty. As the field contains an array, a safe way to check if it holds a value is to check its size (Liquid for the length of the array).

    Step 7) Optional - Develop a Custom Layout for the Related Products

    You can style and write Liquid for the Related Products List Layout in the same way you do for any . For example, you could provide a link to the Detail Pages of those Related Products using the Slug property.

    You've now completed the Step by Step guide for adding Related Products.

    Product Detail Layout

    Customise the way Products look on their automatically generated Detail Pages and add functionality for adding the Product to the Cart.

    Prerequisites

    • You have created Products in the Admin

    Getting Started

    This Tutorial will show you how to output information about a Product on its automatically-generated Detail Page.

    It will cover how to:

    • Find where Product layouts are stored on Code Editor

    • Develop a wrapper.liquid file

    • Include an item.liquid file

    • Add functionality for a User to add the Product to Cart

    File Structure

    In SITE MANAGER/Code Editor, the folder structure for eCommerce layouts is as below:

    • layouts

      • modules

        • module_14

    See more:

    Creating a new set of Product Layouts

    To create a new set of Product layouts- create your folder at the level of "name_of_my_layout". Inside that, the folders and files should be created as shown above.

    Detail Layout Development

    As with list views, the detail folder inside your new layout folder should contain a wrapper.liquid and an item.liquid file. Refer to the folder structure at top of the document for reference. You also have the option of creating an attribute layout which can be included inside your item.liquid file to show Product Variations.

    wrapper.liquid

    wrapper.liquid -- detail view example

    This is the file for the main section code e.g. a section title or padding. You will need to use the following liquid to include your item.liquid file inside the wrapper and give it access to information about the Product:

    item.liquid

    item.liquid -- detail view example

    Unlike the List View, the code in the item.liquid file in the Detail folder will only be displayed once instead of looped. Inside the item.liquid file, you'll have access to the "this" object, which contains the fields you'll need. See for available fields or output {{this | json}} in the item.liquid file to see the exact data available to you.

    Add to Cart

    To create a button to add the current Product to the Cart use the following Liquid code

    See more:

    Quantity to Add to Cart

    In order to use the "Add to Cart" Button, you'll also need to have an input element where Users can select the quantity they'd like to add. Make sure it has the correct data-attribute.

    Attribute Layout - Presenting the Choice to the Customer

    Product Attribute Layouts allow you to customise the way that you present users with a choice of which variation of a Product they want.

    Product Attribute Layouts allow you to customise the way that you present users with a choice of which variation of a Product they want.

    Prerequisites

    • You have created Products in the Admin

    • You have

    Introduction

    This Tutorial will show you how to use Attributes to let Users pick Variants on the Product's automatically-generated Detail Page.

    It will cover how to:

    • Find where Product layouts are stored on Code Editor

    • Develop a my_attribute_layout.liquid file

    • Allow the User to select Attribute Options before adding to Cart

    Folder Structure

    In SITE MANAGER/Code Editor, the folder structure for product attributes layouts is as below:

    See a more complete Cart & Checkout Folder Structure here:

    Creating a new set of Product Layouts

    To create a new set of Product layouts- create your folder at the level of "name_of_my_layout". Inside that, the folders and files should be created as shown above.

    Including a Single Known Attribute on a Detail Page

    If you are making a layout where you know exactly which Attribute a Product has, you can include an Attribute layout to display an Attribute with a given name: detail/item.liquid (including a single Attribute)

    Looping Over Multiple Attributes

    If your Products have multiple Attributes, or you want to write code which can dynamically display any Attribute given to the Product, you can use liquid to loop over all Attributes. We've recently updated this example to be much simpler and easier to use.

    Steps:

    1. Loop over all Attribute Options

    2. Check if the Attribute is enabled

    3. If so, include the relevant Attribute layout, dynamically filling in the "name" parameter.

    Full example:

    detail/item.liquid -- (looping over all Attributes linked to this Product)

    Attribute Layout Development

    There is no need to create a wrapper file for Attributes, as they are already included inside an item.liquid file. Your Attribute layout can be given a name of your choice. Different Attributes for the same Product may use different Attribute layouts, e.g. "Colour" may include colour swatches.

    You can output the name of the Attribute that the current Layout displays: {{this_attribute.properties.name}}

    The following liquid outputs an array of the options that have been created for this Attribute: {{product_attribute_options}}

    You can loop over this array with the following liquid code, (where the example has the variable "option", you could choose any variable name):

    To get the full benefits of Attribute functionality, including the user's choice of Attribute affecting what is added to the Cart, the data-attributes and function calls in the example should be included:

    As you can see in the example, inside the loop it is possible to access the specific Attribute Option in this iteration via the "option" variable you created when setting up the loop, but you can also still access the "this" object specific to the Detail Layout that wraps around and includes the Attribute Layout. See the to see the fields available in the "this" object and those specific to Attributes and Attribute Options.

    created eCommerce Products
    Product List

    product

    • name_of_my_layout

      • list

        • wrapper.liquid

        • item.liquid

      • detail

        • wrapper.liquid

        • item.liquid

  • product_attributes

    • my_attribute_layout.liquid

  • Cart and Checkout Folder Structure
    reference
    Add to Cart Button
    created a Product Detail View
    Cart and Checkout Folder Structure
    Product Layout Liquid Reference
    <h2>Related Products</h2><br><br>
    {{this['Related products']}}<br><br>
    
    
    {% assign related_products_str = this['Related products'] | join: ',' %}
    
    
    
    
    
    <h2>Related Products</h2>
    {%- include 'ecommerce/products'
        layout: 'default'
        per_page: '3'
        show_pagination: 'false'
        sort_type: 'properties.name'
        sort_order: 'asc'
        datasource: 'true'
        item_ids: related_products_str
    -%} 
    {% if this['Related Products'].size > 0  %}
      <h2>Related Products</h2>
      {% assign related_products = this['Related Products'] | join: "," %}
      {%- include 'ecommerce/products'
          layout: 'default'
          per_page: '3'
          show_pagination: 'false'
          sort_type: 'properties.name'
          sort_order: 'asc'
          datasource: 'true'
          item_ids: related_products 
      -%} 
    {% endif %}
    <section class="large detail-view ecommerce">
      <div class="container">
        <div class="row">
          {%- include 'modules/siteglide_ecommerce/ecommerce/get/get_products'
              item_layout: 'item' 
          -%}
        </div>
      </div>
    </section>
    
    
    {%- include 'modules/siteglide_ecommerce/ecommerce/get/get_products'
        item_layout: 'item' 
    -%}
    
    
    <div class="col-lg-6"> <img src="{{this['Image'] | asset_url}}" class="img-fluid"></div>
    <div class="col-lg-5 offset-lg-1">
      <div>
        <h2 class="product-title">{{this['name']}}</h2>
        <p class="product-price" data-price-control="{{this.price.price_charge}}" 
           data-currency-control="{{this.price.currency_symbol}}"></p>
        <div class="row">
          <div class="col-md-4">
            <div class="form-group">
              <label>Quantity</label>
              <input type="number" min="1" value="1" class="form-control" data-quantity-control="">
            </div>
          </div>
        </div>
      </div>
      <hr class="mt-4 mb-4">
      
    {% if this['Description'] %} <h4>Product Description</h4> {{this['Description']}} {% endif %}
      <hr class="mt-4 mb-4">
      <div class="row product-detail-buttons">
        <div class="col-12 col-md-6">
          {% include 'ecommerce/cart_add' -%}
    
    
        </div>
        <div class="col-12 col-md-6">
          <a class="btn btn-primary" href="/cart">View my Cart</a>
        </div>
      </div>
    </div>
    
    {%- include 'ecommerce/cart_add', component_layout: 'name_of_my_layout' -%}
    
    
    <label for="quantity">Quantity</label>
    <input type="number" min="1" value="1" data-quantity-control id="quantity" />
    marketplace_builder
    └───views
        └───partials
            └───layouts
                └───modules
                    └───module_14
                        ├───product
                        │   collection.liquid
                        │   └───custom_product_layout
                        │       ├───detail
                        │       │   item.liquid
                        │       │   wrapper.liquid
                        │       └───list
                        │           item.liquid
                        │           wrapper.liquid
                        └───product_attributes
                            └───custom_attributes_layout.liquid
    {% include 'ecommerce/product_attributes'
       name: attribute
       layout: 'demo_site_attributes'
       attribute_name: "Size" 
    -%}
    
    
    {% for attribute in this.product_attributes %}
      {% if attribute.properties.enabled == true %}
        {% include 'ecommerce/product_attributes'
           name: attribute.properties.name
           layout: 'demo_site_attributes' 
        -%} 
      {% endif %}
    {% endfor %}
    
    
    
    
    
    {% for option in product_attribute_options -%}
      {{option.name}} ({{this.price.currency_symbol}}{{option.price}})
    {% endfor %}
    
    
    
    
    
    <select name="attr1" class="form-control" data-attribute-control="{{product_attribute_id}}" onchange="s_e_update_price()">
      
    {% for option in product_attribute_options %}
        <option value="{{option.id}}" data-attribute-price-control="{{option.price_raw}}">
          {{option.name}} {{this.price.currency_symbol}}{{option.price}})
        </option>
      {% endfor %}
    </select>

    Discount Codes Layout

    This Article explains how to output a Discount Codes Layout in either Basic Payment Form, Cart, Checkout or Subscription Layouts

    Introduction

    Discount Codes allow your Client to provide special offers to their customers.

    You can learn how to set up Discount Codes in the Admin here.

    The role of a Discount Code Layout is to give the customer an opportunity to enter and apply a Discount Code on your Site. Additionally, once a code is applied, the Layout will give the customer information about how their code has been applied along with any terms and conditions, and the opportunity to remove the code.

    This Article will explain how you can include a Discount Codes Layout in either your:

    • Cart wrapper.liquid file

    • Checkout Form Layout (Discount Code Layouts for the Cart and Checkout will have the same syntax).

    • Basic Payment Form Layout - This will have slightly different syntax due to the unique properties of Basic Payment Forms, but we'll cover this below.

    • Subscription Form Layout - This will have slightly special considerations because the discount has the potential to be applied to all invoices for a specified number of months. It's also possible to use Subscription Discount Codes to take 100% off the price giving a free trial.

    Once a customer uses the button in the Layout to successfully add a Discount Code, this will be stored in their session alongside any Cart Data. We'll store one code at a time for each payment type, with Basic Payment Forms storing their codes in {{context.session.basic_payment_discount}}, Cart saving its codes in {{context.session.cart_discount}} and Subscriptions saving their codes in {{context.session.subscription_discount}}.

    When a customer completes a Payment Form, the Server-side checks will apply the code and reduce the amount they are charged. This means your Site will be secure and safe against malicious users choosing their own discounts.

    For setting up Discount Codes, including how to make only certain Products and Categories of Products eligible for a discount, see here:

    Step 1 - Including the Layout inside the Cart, Checkout, Basic Payment Form or Subscription Form Layout

    The Discount Code Layout can be nested inside a Cart. However, step 1 also applies in all kinds of Form Layout.

    1a - Add your Layout

    The following Liquid will add the Layout:

    The only parameter you'll need will be layout which refers to the file name of the Layout. We'll look at where to create the Layout files in Step 2.

    The code must be placed directly inside a form layout or a cart layout. This is important so that it can inherit variables it depends on to understand the customers' spend and the type of discount it needs to use. For subscription forms, the discount code layout must go inside a subscription form layout which is itself inside a subscription product layout.

    1b - Optional - Adding Support for Refreshing Layout instead of whole Page

    In order to better support adding Discount Code Layouts on Forms, we've added the option to reload just the Layout, instead of the whole Page. The main benefit of this is that Users will not have to refill their form data after adding a Discount Code. We'll discuss this more in Step 3) b)

    For now, you can add the data-attribute data-s-e-refresh-layout-discount-code to the element which serves as a wrapper for your Layout e.g.

    In a Cart Layout, you may also wish to set prices to automatically update when the discount code is added.

    You can add the following data-attributes:

    • data-s-e-live-cart-currency - the element will be filled dynamically with the Cart currency when the Layout refreshes

    • data-s-e-live-cart-total - the element will be filled dynamically with the updated Cart Total Price.

    e.g.

    Related Layout Development Docs

    Step 2 - Create Layout Files or Choose the Discount Code Layout

    A Discount Code Layout will typically contain:

    • An input field for the customer to enter a discount code

    • A button which allows them to submit the code

    • A button which allows them to remove a code (if perhaps the code is no longer valid and blocking payment).

    • Feedback to the user regarding successful and unsuccessful attempts to apply their discount code.

    File Structure

    Discount Code Layouts will be stored here, inside: layouts/modules/module_14/discount_code

    You'll just need a single Liquid file with the same name as your Layout. Optionally, you can use folders to organise Layouts of different types.

    If you haven't already, make sure your layout parameter in the Liquid tag matches the name of your Layout File. Any custom folders like 'cart/' should also be added to the layout parameter path.

    As there are subtle differences in implementation depending on the type of payment, we've created three different default layouts to help you get started:

    • "basic_payment/default"

    • "cart/default"

    • "subscription/default"

    For steps 3 and onwards, you may find it easier to copy and edit the code from the default Layout, but we'll break this down into steps here so you can see all the elements you'll need.

    Step 3 - Add HTML and Liquid to allow a Customer to enter a Discount Code

    3a - Add an &lt;input&gt; element and &lt;label&gt;

    HTML Attributes Explained:

    {{discount\_code\}}

    or

    {% if discount_code != blank %}value="\{{discount\_code\}}" readonly{% endif %}

    |

    If a code is already successfully added, it will be autofilled.

    or Any successful code is autofilled and the current field value is readonly until removed in step b) | One of these

    | |

    3b - Add an "Apply" button

    When adding the 'Apply' button, you can customise how the JavaScript will behave on successful and unsuccessful attempts to add a Discount.

    In the examples below, we'll show the basic options recommended for different types of Layout, then explain the full range of options you have for JavaScript behaviour.

    Applying to a Cart Layout:

    Applying to a Checkout Form Layout:

    Applying to a Basic Payment Form Layout:

    Applying to a Subscription Layout:

    Note

    We recommend hiding the apply button after the Subscription Order has been created and the Discount Code has been redeemed. See Subscription Specific Instructions.

    3c - JavaScript Options Explained

    At this stage, you have a choice about whether you'd like the whole Page to reload after a successful Discount Code is added, or whether you'd like to only reload the Discount Code Layout itself.

    We'd strongly recommend that for Layouts on Forms that you set reload: false as this will prevent the User having to re-enter their Form data, and will preserve any custom amount chosen on the Basic Payment Form.

    Note also that the value of spend will be different for Basic Payment Forms:

    • Basic Payment Forms store the spend value in document.querySelector('#s_e_amount').value - as this can be dynamically changed by JavaScript, there is no Liquid value for it.

    • Cart and Checkout Forms can use the Liquid value: '{{context.exports.cart_base_price.data | json}}'

    • Subscriptions store the spend in {{spend}}

    Step 4 - Add HTML and Liquid to allow a Customer to Remove a Discount Code

    You can optionally add a button to the Layout which will allow the customer to remove a Discount Code that has already been applied.

    The Liquid IF statement helps make sure the button is only displayed if there is a code present to be removed.

    The JavaScript function will make the button functional.

    Why is this helpful? Although we check Discount Codes are valid when they are added, there are cases where the code is no longer valid by the time the customer reaches the Checkout, for example:

    • The User may have adjusted the quantity of items in the Cart, causing the spending amount to drop lower than the minimum payment allowed by the Discount Code.

    • The Code may have been close to expiry.

    Adding a "remove" button gives the User a clear way to solve any problems stopping them from completing their purchase.

    Note

    You cannot remove a Subscription Discount Code after the Subscription Order has been created and the Discount redeemed. See Subscription Specific Instructions.

    Step 5 - Add HTML and Liquid to give the customer feedback

    5a - Displaying the Discount Amount

    On Page refresh (or if you've chosen reload: false on Layout refresh), after a successful Code is applied, the following Liquid will explain the minimum spend needed and the discount available.

    Depending on where your Layout is, different syntax may be needed to fetch the currency to display.

    On Cart and Checkout Layouts:

    On Basic Payment Layouts:

    On Subscription Layouts:

    On Subscription Layouts it is important to know whether or not the Subscription Order has been created, if it has, then the Discount will already be redeemed. The difference in display needs to account for the fact that a redeemed discount is time-limited.

    For both situations, we can use the fields inside the discount variable to access details on the Discount.

    Before the Subscription Order is Created At this stage, we can use general details of the discount which is applied, but not yet redeemed, from the this object.

    After the Subscription Order is Created and the Discount Redeemed At this stage, we can use details of the actual discount code stored against the Subscription Order. As this is time limited, we may also wish to give details of how much longer the Discount will be active for and the specific Subscription Order will provide these details.

    5b - Displaying the Minimum Spend

    The following code can be used to display the minimum spend needed to keep using the discount:

    On Cart and Checkout Layouts:

    On Basic Payment Layouts:

    The following code can be used to display the minimum spend needed to keep using the discount:

    On Subscription Layouts

    It's probably only really necessary to display the minimum spend before the Subscription Order is created and the Discount redeemed. Once the discount is redeemed, the amount spent will be fixed.

    5c - Displaying a Message when the Discount Maximum is Reached on Basic Payment Forms, Cart and Checkout

    This code will display a message if the minimum spend is not set strictly enough and the resulting payment total is below that allowed by the Payment Gateway.

    discount_saving_maximum_reached will always return false for Subscriptions and these allow any size of Discount (controlled only by the Partner and Client setting Minimum Spend values on each Discount Code in the Admin.) Therefore, it's not necessary to add this code to a Discount Code Layout for a Subscription.

    Read more about the

    Summary of Available fields when building your Discount Code Layout:

    • discount_code is a variable which contains the Discount Code successfully applied after page refresh

    • discount_minimum is a variable which contains the minimum spend needed for this Discount Code to be valid.

    • discount_amount is a variable which stores the calculated saving on the current Cart value.

    will output the currency symbol on Basic Payment Layouts

    • `{%- include 'modules/siteglide_ecommerce/ecommerce/price_formatter', price_data: discount_minimum -%}

    You can use this Liquid tag to format any Liquid price variable with the correct decimalisation. To use, set theprice_data` parameter to the variable you wish to format.

    • discount_saving_maximum_reached - if true, the Minimum Amount for the Discount Code has not been set strictly enough and the total Payment Due is below that allowed by the Payment Gateway. You can use this to display a warning message that it has not been possible to apply the full discount.

    • For Subscriptions, your Layout will inherit the variables of the Layouts it's nested within- meaning it will inherit variables from the Subscription Detail Page, then the Subscription Form. See details of these objects . e.g. {{this.price.currency_symbol}}

    Step 6 - Optional - Add JavaScript to handle errors

    There are lots of reasons why the customer may enter a code but be refused a discount. For example, the code may have expired, or the Cart's value may not be above the minimum spend.

    You can start with the JavaScript function below and make your own changes to decide how these errors are displayed to the customer:

    As the comments in the example mention, each error returned from a failed discount code will give both a code and a default message. You can choose which one you will use.

    Here are the full list:

    If you want to change the message, you can use logic to display different messages using the error code:

    Once you've created your function, use the error_cb option in step 3) b) and pass it your function name. e.g. error_cb: myErrorFunction

    Step 7 - Optional - Customise the JavaScript behaviour when a code is successfully added

    Setting reload to either true or false in the s_e_cart_discount_code function will both effectively refresh your Discount Code Layout and the Liquid will update with new values, so most use-cases will not need a custom success function. However, if you do need to make changes, you can use the function below as a starting point:

    Available arguments:

    Once you've created your function, use the success_cb option in step 3) b) and pass it your function name. e.g. success_cb: mySuccessFunction

    Step 8 - Optional - Customise the JavaScript behaviour when a code is successfully removed

    Setting reload to either true or false in the s_e_cart_discount_code function will both effectively refresh your Discount Code Layout and the Liquid will update with new values, so most use-cases will not need a custom success function. However, if you do need to make changes, you can use the function below as a starting point:

    Available arguments:

    Once you've created your function, use the success_cb option in step 3) b) and pass it your function name. e.g. success_cb: mySuccessFunction

    Specific Instructions for Subscriptions

    Note

    We recommend for Subscriptions to add some logic checking whether a Subscription Order has already been created and if so, to hide the apply button. This is because once the Subscription Order is created- any Discount Code already applied will be redeemed.

    At this point it's not possible to apply or change the Discount Code, only display details of the Order that's active. The purpose of the Form at this point is actually to allow Users to edit their payment details only.

    You could add this logic around the whole Layout (as in the default Layout), or just around individual components. For the sake of clarity, in the "subscription/default" Layout, we've opted to wrap the logic around the whole Layout, creating two distinctly separate blocks of Liquid for before and after redemption.

    You can also add the statement to check if the Discount will apply to the next invoice or if the Discounted period of months is over.

    Essential HTML, JavaScript and Liquid which controls functionality

    {{context.exports.cart_currency.data}} will output the currency symbol on Cart and Checkout Layouts

  • {% include 'ecommerce/basic_payment_currency', format: 'symbol' %}

  • Error: This Discount Code does not apply to this kind of payment. It may apply in another area of the Site.

    By default, Discount Codes are only redeemable on Cart / Checkout flow. You can change this for an individual code in the Admin using the "Valid on Payment Form Type" field.

    Code

    Purpose

    Required

    data-s-e-discount-code

    Attribute should be added to input field

    Yes

    value="

    Option

    Required / Default

    Notes

    spend: - document.querySelector('#s_e_amount').value - {{context.exports.cart_base_price.data

    json}} - {{spend}}

    Required - no default

    reload: - true - false

    default: true

    Setting true will refresh the entire Page. Setting false will refresh the Discount Code Layout only. We'd strongly recommend that for Layouts on Forms that you set reload: false as this will prevent the User having to re-enter their Form data, and will preserve any custom amount chosen on the Basic Payment Form. If you select false, you must add the data-attribute data-s-e-refresh-layout-discount-code to the element which wraps around the Layout see Step 1) b)

    error_cb: - custom JavaScript function name (don't call the function yet!) - success_cb: mySuccessFunction

    default: - Depending on the reload option, will reload the Page or Layout - If reload is false and the Payment Type is Checkout, will update the total Price by running the s_e_cart_update_prices();

    For arguments and how to customise your own function, head to step 7.

    Option

    Required / Default

    Notes

    reload: - true - false

    default: true

    Setting true will refresh the entire Page. Setting false will refresh the Discount Code Layout only. We'd strongly recommend that for Layouts on Forms that you set reload: false as this will prevent the User having to re-enter their Form data, and will preserve any custom amount chosen on the Basic Payment Form. If you select false, you must add the data-attribute data-s-e-refresh-layout-discount-code to the element which wraps around the Layout see Step 1) b)

    success_cb:

    Default: Depending on how you set the refresh setting, will refresh the Page or the Layout.

    For arguments and how to customise your own function, head to step 8.

    disable_alerts:

    Default: false

    To disable the default JS alert when the code is redeemed, pass in true here. This setting was kept for backwards compatibility. If you are also using a success callback function, the alert fires before the callback function, so this setting is still necessary.

    error.type

    error.message

    Notes

    no_code

    Error: This Discount Code does not exist.

    expired

    Error: This Discount Code has expired.

    below_min_spend={min-spend}

    Error: This Discount Code has a minimum spend of {min-spend}

    used_up

    This Discount Code has already been used the maximum number of times.

    Argument

    Example

    Purpose

    reload default: true

    The value of the reload setting passed into the function. Defaults to true for backwards compatibility.

    discount

    An object containing details of the newly applied discount code.

    payment_type

    'Checkout' or 'Basic Payment'

    Can be used in logic

    refreshed_discount_layout

    A DOMstring containing the HTML generated by the refreshed Discount Code Layout

    This can be used to refresh only the Discount Code Layout, if you choose.

    Argument

    Example

    Purpose

    reload default: true

    The value of the reload setting passed into the function. Defaults to true for backwards compatibility.

    payment_type

    'Checkout' or 'Basic Payment'

    Can be used in logic

    refreshed_discount_layout

    A DOMstring containing the HTML generated by the refreshed Discount Code Layout

    This can be used to refresh only the Discount Code Layout, if you choose.

    Discount Codes
    Developing Cart Layouts
    Checkout Tutorial
    Basic Payment Form Tutorial
    Discount Maximum requirement
    here

    incorrect_type

    {% include 'ecommerce/discount_code'
       layout: "cart/default" 
    %}
    
    <div data-s-e-refresh-layout-discount-code>
    {% include 'ecommerce/discount_code', layout: "cart/default" %}
    
    </div>
    
    <p class="text-uppercase">
        <strong>TOTAL PRICE:</strong> 
        <span data-s-e-live-cart-currency></span>
        <span data-s-e-live-cart-total>
            {% include 'ecommerce/price_total', format_type: 'formatted' -%}
        </span>
    </p>
    <label class="mb-3" for="s_e_discount_code">Discount Code</label>
    <input 
           class="form-control" 
           id="s_e_discount_code" 
           data-s-e-discount-code 
           {% if discount_code != blank %} 
                  value="{{discount_code}}" 
                  readonly="true"
           {%- endif -%}
    >
    <button class="btn btn-primary sg-btn sg-btn-primary" 
            id="s_e_discount_apply" 
            onclick="s_e_cart_discount_code(
    {
      spend: '{{context.exports.cart_base_price.data | json}}',
      reload: true
      
    }
    )">Apply Code</button>
    <button class="btn btn-primary sg-btn sg-btn-primary" 
            id="s_e_discount_apply" 
            onclick="s_e_cart_discount_code(
    {
      spend: '{{context.exports.cart_base_price.data | json}}',
      reload: false
    }
    )">Apply Code</button
    
    <button class="btn btn-primary sg-btn sg-btn-primary " 
            id="s_e_discount_apply" 
            onclick="s_e_cart_discount_code(
    { 
      spend: document.querySelector('#s_e_amount').value,
      reload: false
    }
    );">Apply Code</button>
    <button class="btn btn-primary sg-btn sg-btn-primary" 
            id="s_e_discount_apply" 
            onclick="s_e_cart_discount_code(
    {
      spend: {{spend}},
      reload: false
    }
    );">Apply Code</button>
    {%- if discount_code != blank -%}
      <button class="btn btn-danger" id="s_e_discount_remove" onclick="s_e_cart_discount_code_remove(
        {
          reload: false
        }
      )">
        Remove Code
      </button>
    {% endif %}
    
    
        <p>Discount: 
            <span style="color: red;">
                -{{context.exports.cart_currency.data}}
                {%- include 'modules/siteglide_ecommerce/ecommerce/price_formatter' price_data: discount_amount -%}
            </span>
        </p>
    {%- if discount_code != blank -%}
      <p>Discount: 
        <span style="color: red;">
            -{% include 'ecommerce/basic_payment_currency', format: 'symbol' %}
            {%- include 'modules/siteglide_ecommerce/ecommerce/price_formatter', price_data: discount_amount -%}
        </span>
      </p>
    {%- endif -%}
    
    
    
    
    
    {%- if discount_code != blank -%}
      <p>Discount: 
      <span style="color: red;">
        -{{this.price.currency_symbol}}
        {%- include 'modules/siteglide_ecommerce/ecommerce/price_formatter', price_data: discount_amount -%}
      </span>
      every 
        {% if this['Interval Count'] != "1" %}
          {{this['Interval Count']}} {{this['Interval']}}
        {% else %}
          {{this['Interval'] | pluralize: 1}}
        {% endif %}
        for {{discount.number_of_months_to_discount}} 
        {% if discount.number_of_months_to_discount == 1 %}
          month
        {% else %}
          months
        {% endif %}
      </p>
    {%- endif -%}
    
    
    
    
    
    {%- if discount_code != blank -%}
      <p>Discount redeemed: 
        <span style="color: red;">
          {{this.price.currency_symbol}}
          {%- include 'modules/siteglide_ecommerce/ecommerce/price_formatter'
                       price_data: discount_amount -%}
        </span> saved every 
        {% if subscription_order['Plan Interval Count'] != "1" %}
          {{subscription_order['Plan Interval Count']}}
          {{subscription_order['Plan Interval']}}
        {% else %}
          {{subscription_order['Plan Interval'] | pluralize: 1}}
        {% endif %}
        for {{discount.number_of_months_to_discount}} 
        {% if discount.number_of_months_to_discount == 1 %}
          month
        {% else %}
          months
        {% endif %}
        until {{subscription_order['Plan Discount Ends At'] | date: "%d/%m/%y"}} 
      </p>
      <p>Total Due: {{this.price.currency_symbol}}
        {%- include 'modules/siteglide_ecommerce/ecommerce/price_formatter'
                     price_data: discount.total_remaining -%}
                     </p>
    {%- endif -%}
    
    
    
    
    
    {%- if discount_code != blank and discount_minimum -%}
    <p class="mt-4">
        This code will only be valid on Cart orders worth over: 
        {{context.exports.cart_currency.data}}
        {%- include 'modules/siteglide_ecommerce/ecommerce/price_formatter'
                     price_data: discount_minimum -%}</p>
    {%- endif -%}
    
    
    
    
    
    {%- if discount_code != blank and discount_minimum -%}
    <p class="mt-4">
        This code will only be valid on orders over: 
        {% include 'ecommerce/basic_payment_currency'
                    format: 'symbol' %}
                    {%- include 'modules/siteglide_ecommerce/ecommerce/price_formatter'
                                 price_data: discount_minimum -%}
                                 </p>
    {%- endif -%}
    
    
    
    
    
    {%- if discount_code != blank and discount_minimum -%}
      <p class="mt-4">
        This code will only be valid on orders over: 
        {{this.price.currency_symbol}}
        {%- include 'modules/siteglide_ecommerce/ecommerce/price_formatter'
                     price_data: discount_minimum -%}
                     </p>
    {%- endif -%}
    
    
    
    
    
    {%- if discount_saving_maximum_reached == true -%}
    <!-- Message here -->
    <p class="mt-4">
        Minimum transaction value reached. 
        To make the most of your discount, try adding another item to your Cart.</p>
    {%- endif -%}
    
    
    
    function s_e_discount_error(error) {
    console.log(error.type); 
    /* an error code which you can use in your logic. */
    console.log(error.message); /* A ready-drafted error message */
    alert(error.message);
    }
    <script>
    function myErrorFunction(error) {
    if (error.type == 'no_code' ) {
    alert('Better luck next time. Discount Code not found!');
    } elsif (error.type.indexOf('below_min_spend=') != -1 ) {
    //As the below min_spend code can vary depending on the value, this code checks for the substring.
    alert('You'll need to spend more before using this code.');
    }
    
    </script>
    function mySuccessFunction(reload = true, discount, payment_type, refreshed_discount_layout) {
    if(reload == true) {
    window.location.reload();
    } else if (refreshed_discount_layout) {
    var slot = document.querySelector('[data-s-e-refresh-layout-discount-code]');
    slot.innerHTML = refreshed_discount_layout;
    if(payment_type == 'Checkout') {
    s_e_cart_update_prices();
    }
    }
    }
    function mySuccessFunction(reload = true, payment_type = 'Checkout', refreshed_discount_layout) { 
    if(reload == true) { 
    window.location.reload(); 
    } else if (refreshed_discount_layout) { 
    var slot = document.querySelector('[data-s-e-refresh-layout-discount-code]'); 
    slot.innerHTML = refreshed_discount_layout; 
    if(payment_type == 'Checkout') { 
    s_e_cart_update_prices(); 
    } 
    } 
    }
    {% if subscription_discount_already_redeemed == true %}
    
    <!-- Insert code here - the Discount has already been redeemed against the Subscription Order-->
    {% endif %}
    
    
    
    
    
    {% if rate_still_discounted == true %}
    {% endif %}