Discount Codes Layout
This Article explains how to output a Discount Codes Layout in either Basic Payment Form, Cart, Checkout or Subscription Layouts
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.
Step 1 - Including the Layout inside the Cart, Checkout, Basic Payment Form or Subscription Form Layout
The screenshot below shows how the Discount Code Layout can be nested inside the Cart. However, step 1 also applies in all kinds of 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.
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.
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.
- Essential HTML, JavaScript and Liquid which controls functionality
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.
HTML Attributes Explained:
Code | Purpose | Required |
---|---|---|
data-s-e-discount-code | Attribute should be added to input field | Yes |
value="{%- if discount_code != blank -%}{{discount_code}}{%- endif -%}" 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 |
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.
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.
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}}
Option | Required / Default | Notes |
---|---|---|
spend:
| Required - no default | Basic Payment Forms use spend: 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: spend: '{{context.exports.cart_base_price.data | json}}' |
reload:
| 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:
| default:
| For arguments and how to customise your own function, head to step 6. |
success_cb:
| default:
| For arguments and how to customise your own function, head to step 7. |
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.
Option | Required / Default | Notes |
---|---|---|
reload:
| 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. |
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.
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 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.
The following code can be used to display the minimum spend needed to keep using the discount:
The following code can be used to display the minimum spend needed to keep using the discount:
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 Discount Maximum requirement
- 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.
- {{context.exports.cart_currency.data}} will output the currency symbol on Cart and Checkout Layouts
- {% include 'ecommerce/basic_payment_currency', format: 'symbol' %} 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 the price_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 here. e.g. {{this.price.currency_symbol}}
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:
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. |
|
incorrect_type | 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. |
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
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:
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. |
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
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:
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. |
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
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.