By default, there is no discount input field on the cart page.
I attempted to add a custom input form with the action set to "/discount/YOUR_CODE". However, when I try to apply two different discount codes, the second code replaces the first one. Shopify allows for discount combinations, so this experience is not ideal.
After investigating, I found that we can achieve this by using the URL format "/checkout?discount=CODE1,CODE2,CODE3". Here are the steps with sample code:
<style>
.cart_discounts {
column-gap: 7px;
display: flex;
flex-wrap: wrap;
justify-content: flex-end;
margin-bottom: 15px;
row-gap: 7px;
}
.cart_discounts li {
background-color: #ededed;
border-radius: 5px;
padding: 7px 9px;
}
.cart_discounts span {
text-transform: uppercase;
}
.cart_discounts .remove-discount {
align-items: center;
cursor: pointer;
display: flex;
height: 10px;
justify-content: center;
margin-left: 9px;
opacity: 0.5;
width: 10px;
}
.cart_discounts .remove-discount:hover {
opacity: 1;
transition: 0.3;
}
.custom-discount-form {
margin-bottom: 7px;
}
.custom-discount-form input {
flex: 1;
}
.custom-discount-form input:focus-visible {
outline: none;
}
.custom-discount-form .form {
display: flex;
gap: 7px;
}
.custom-discount-form .error {
color: red;
display: none;
}
</style>
<div class="cart_discounts-block" style="margin: 0 auto; max-width: 80vw">
{% assign discount_codes = "" %}
{% assign discount_list = "" %}
{% for discount_application in cart.cart_level_discount_applications %}
{% if discount_application.type == "discount_code" %}
{% assign discount_codes = discount_codes | append: ',' | append: discount_application.title %}
{% endif %}
{% assign discount_list = discount_list | append: ',' | append: discount_application.title %}
{% endfor %}
{% for item in cart.items %}
{% if item.line_level_discount_allocations.size %}
{% for line_discount in item.line_level_discount_allocations %}
{% if line_discount.discount_application.type == "discount_code" %}
{% assign discount_codes = discount_codes | append: ',' | append: line_discount.discount_application.title %}
{% endif %}
{% assign discount_list = discount_list | append: ',' | append: line_discount.discount_application.title %}
{% endfor %}
{% endif %}
{% endfor %}
{% assign discount_codes = discount_codes | remove_first: ',' | split: ',' | uniq | join: ',' %}
{% assign discount_list = discount_list | remove_first: ',' | split: ',' | uniq | join: ',' %}
<div class="custom-discount-form">
<div class="form">
<input name="custom-discount-input" type="text" />
<button class="submit-discount button">Apply</button>
</div>
<p class="error">Enter a valid discount code or gift card</p>
</div>
<ul class="cart_discounts list-unstyled" role="list" aria-label="{{ 'customer.order.discount' | t }}">
{% assign codes = discount_list | split: ',' %}
{% for code in codes %}
{% if discount_codes contains code %}
<li class="discounts__discount discounts__discount--position">
{%- render 'icon-discount' -%}
<span>{{ code | escape }}</span>
<span class="remove-discount" data-code="{{ code }}">
{%- render 'icon-close' -%}
</span>
</li>
{% else %}
<li class="discounts__discount discounts__discount--position">
{%- render 'icon-discount' -%}
<span>{{ code | escape }}</span>
</li>
{% endif %}
{% endfor %}
</ul>
</div>
<script>
let enteredDiscountCode = '';
function reloadCart() {
const targetUrl = '/cart.js';
fetch(targetUrl, {method: 'GET'}).then(res => {
return res.json();
}).then(data => {
const appliedDiscounts = [];
console.log(data);
data.cart_level_discount_applications.forEach((discount) => {
if(discount.type === 'discount_code') {
appliedDiscounts.push(discount.title);
}
});
data.items.forEach((item) => {
item.line_level_discount_allocations.forEach((discount) => {
if(discount.discount_application.type === 'discount_code') {
appliedDiscounts.push(discount.discount_application.title);
}
});
});
console.log(appliedDiscounts);
if (appliedDiscounts.indexOf(enteredDiscountCode) === -1) {
const errorElement = document.querySelector('.custom-discount-form p.error');
errorElement.style.display = 'block';
errorElement.textContent = 'Enter a valid discount code or gift card';
} else {
window.location.reload();
}
});
}
document.querySelector('.submit-discount').addEventListener('click', (e) => {
const discountcodes = '{{ discount_codes }}'.split(',') ? '{{ discount_codes }}'.split(',') : [];
const discountCode = document.querySelector('.custom-discount-form input').value.trim();
document.querySelector('.custom-discount-form p.error').style.display = "none";
if (discountCode && discountCode.length) {
if (discountcodes.indexOf(discountCode) === -1) {
discountcodes.push(discountCode);
enteredDiscountCode = discountCode;
const targetUrl = '/checkout?discount=' + discountcodes.join(',');
fetch(targetUrl, {method: 'GET'}).finally(() => {
reloadCart();
});
} else {
const errorElement = document.querySelector('.custom-discount-form p.error');
errorElement.style.display = 'block';
errorElement.textContent = 'Entered Coupon was applied';
}
} else {
const errorElement = document.querySelector('.custom-discount-form p.error');
errorElement.style.display = 'block';
errorElement.textContent = 'Enter a valid discount code or gift card';
}
});
const codeTags = document.querySelectorAll('.remove-discount');
codeTags.forEach(function(codeTag) {
codeTag.addEventListener("click", function() {
const discountcodes = '{{ discount_codes }}'.split(',') ? '{{ discount_codes }}'.split(',') : [];
const discountCode = this.dataset.code;
const remainCodes = discountcodes.filter(function(code) { return code !== discountCode });
const targetUrl = '/checkout?discount=' + remainCodes.join(',');
fetch(targetUrl, {method: 'GET'}).finally(() => {
window.location.reload();
});
});
});
</script>
Note: My code currently only applies for discounts of products and collections; it does not apply for discounts of shipping yet. You can try to add more logic later.