shopifycombinationscartdiscount

How to add a Discount input in Cart page on Shopify (Allow for Discount combinations)


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.


Solution

  • 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:

    1. Add a new template named cart-discount.liquid in the snippets/ folder with the following 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>

    1. Open file sections/main-cart-footer.liquid and add {% render 'cart-discount' %} under div class="cart__blocks" enter image description here

    And this is the result: enter image description here

    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.