Checkout page order Summary

On this checkout page:

there are total 6 products 3 is with price and 3 is zero price

1x Coussin- 29.90€
1x Coussin- 39.90€
2x Coussin- 59.80€
1x Housse de rechange- 0€
2x Housses de rechange- 0€
1 Livre électronique-0€

Now I need something like: when customer select/choose this product: 1x Coussin- 29.90€
in the order summary should not add any free product
but when customer select/choose this product: 1x Coussin- 39.90€
in the order summary should add this free product :1x Housse de rechange- 0€

but when customer select/choose this product: 2x Coussin- 59.80€
in the order summary should add these free products :
2x Housses de rechange- 0€
1 Livre électronique-0€

Then After clicking the Submit button on the Confirmation page the product should visible only selected products:
I did this code already, For now for any secection on the confirmation page all the free products are added:


<!DOCTYPE html>
<html>
<head>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
  <style>
    .hide-force {
      display: none !important;
    }
    .order-summary .os-inner-container .os-items .os-price p:nth-child(2) strong, .product-list .pl-items .pl-price p:nth-child(2) strong {
        color: #13193b !important;
    }
    .order-summary .os-inner-container .os-items .os-price p:nth-child(3) span, .product-list .pl-items .pl-price p:nth-child(3) span {
        color: #000 !important;
    }
    .order-summary .os-items {
        padding: 8px 0px !important;
    }
    .right-sidebar .os-price p strong {
        font-size: 26px !important;
        color: #13193b !important;
    }
    @media (max-width: 768px) {
      .order-summary .os-items {
        padding: 8px 0px;
      }
    }
    @media (max-width: 768px) {
      .offers-check {
        padding-left: 15px !important;
         padding-right: 15px !important;
      }
      .p-hypen-tag p em {  
        font-size: 8px !important;
      }
    }
    @media (max-width: 768px) {
      .offers-1 {
        margin-left: 0px !important;
         margin-right: 0px !important;
      }
    }
    @media (max-width: 400px) {
      .p-hypen-tag p em {  
        font-size: 6px !important;
      }
    }
    .checkhero {
      position: relative;
      padding-top: 50px !important;
      padding-bottom: 50px !important;
    }
    @media (max-width: 768px) {
      .checkhero {
        padding-top: 0px !important;
        padding-bottom: 0px !important;
      }
    }
    .checkhero::before {
      content: '';
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      background-color: white;
      opacity: 0.4;
      z-index: 1;
    }
    .checkhero > * {
      position: relative;
      z-index: 2;
    }
    .orderCheckoutProduct .container-box .pl-items .pl-price span.pl-pvalue p:nth-child(2) strong {
        color: #13193b !important;
        font-size: 26px !important;
    }
    .orderCheckoutProduct .container-box .pl-items .pl-price span.pl-pvalue p:nth-child(3) span {
        color: #000 !important;
    }
    .product-main-class .pl-items {
        display: grid;
        gap: 16px;
        padding-top: 33px;
    }
    .product-main-class .pl-item {
        background-color: #f9f9f9;
        box-shadow: 0 4px 3px #00000012, 0 2px 2px #0000000f;
    }
    .product-main-class .pl-item .pl-name {
        width: 50%;
    }
    .product-main-class .pl-item .pl-price {
        min-width: auto;
        text-align: center;
        width: 50%;
        flex: 1;
    }
    .product-main-class span.pl-pvalue h1 {
        line-height: 1;
        margin-bottom: 0px;
    }
    .product-main-class span.pl-pvalue h1 strong {
        font-size: 12px !important;
    }
    span.pl-pvalue span {
        font-size: 20px !important;
        font-weight: 700;
        color: #13193b;
    }
    .product-main-class span.pl-pvalue p s:nth-child(1) {
        color: #6d6d6d !important;
        font-size: 16px !important;
        display: block;
        color: #fff;
        padding: 2px 8px;
        border-radius: 50px;
        display: table;
        margin-left: auto;
    }
    .product-main-class span.pl-pvalue p s:last-child {
         color: #13193b;
    }
    .product-main-class .pl-item .pl-name .pl-nvalue {
        position: relative;
        font-weight: 600;
    }
    .product-list .pl-item .pl-name .pl-nvalue span.name {
        font-size: 16px;
        font-weight: 900;
        text-align: left;
        color: #13193b;
    }
    .product-main-class .pl-item .pl-image {
        width: 150px;
        height: 100%;
        margin: 0;
        border: none;
        background: transparent;
    }
    .product-main-class .pl-item.small.selected {
        background-color: #fafefa;
    }
    .product-main-class .pl-item .pl-inner:hover {
        background: transparent;
    }
    .product-main-class .pl-item {
        position: relative;
        overflow: inherit;
    }
    .right-sidebar .os-price h1 {
        line-height: 1;
        margin-bottom: 10px;
    }
    .right-sidebar .os-price h1 strong {
        font-size: 12px !important;
    }
    .right-sidebar .os-price p s:nth-child(1) {
        color: #6d6d6d !important; 
        font-size: 16px !important;
        display: block;
    }
    .right-sidebar .os-price p strong:nth-child(1) {
        color: #13193b !important; 
        font-size: 20px !important;
    }
    .right-sidebar .os-price span {
        font-weight: 700;
        color: #13193b;
        border-radius: 50px;
        padding: 4px 7px;
        font-size: 12px;
        display: inline-block;
        margin-bottom: 3px;
    }
    .right-sidebar .os-price p s:last-child {
        color: #13193b;
    }
    .right-sidebar .os-row .os-price {
        min-width: 250px;
    }
    .product-list .pl-item input.pl-radio {
        position: absolute;
        left: 5px;
        top: 55px;
    }
    .product-main-class .pl-item .pl-name {
        flex-direction: column-reverse;
        justify-content: flex-end;
        gap: 18px;
        align-items: baseline;
        flex: 0 !important;
    }
    .p-hypen-tag p {
        display: flex;
        align-items: center;
        font-weight: 600;
        font-size: 14px;
        margin-bottom: 4px;
    }
    .p-hypen-tag p img {
        width: 32px;
        height: auto;
        margin-right: 5px;
        border-radius: 5px;
    }
    .p-hypen-tag p em {
        background-color: #13193b;
        color: #fff;
        display: flex;
        padding: 4px 7px;
        border-radius: 2px;
        margin-left: 5px;
        font-size: 10px;
    }
    .product-list .pl-item .pl-inner {
        flex-wrap: wrap;
    }
    span.pl-pvalue {
        text-align: right;
        color: #13193b;
        font-size: 20px;
        font-weight: 600;
    }
    .pl-item.small.selected label.pl-inner {
        background: #dff3e8;
        border: 2px #13193B solid;
    }
    .product-list .pl-item .pl-name input {
        accent-color: #13193B;
    }
    .pl-items .pl-item.small:nth-child(1) .pl-price p:nth-child(1) {
        color: #fff;
        padding: 2px 0px;
        border-radius: 50px;
        font-size: 12px;
        font-weight: 600;
        text-align: right;
    }
    span.pl-pvalue p span:nth-child(1) {
        color: #0E8390 !important;
        padding: 2px 8px;
        border-radius: 50px;
        font-size: 12px !important;
        font-weight: 600;
        display: table;
        margin-left: auto;
    }
    span.pl-pvalue p s {
        color: #13193b;
    }
    span.pl-pvalue p:nth-child(1) span {
        color: #fff !important;
    }
    .right-sidebar .os-price p:nth-child(3) span {
        color: #0E8390 !important;
    }
    .order-summary .os-row .os-price {
        max-width: 100% !important;
    }
    @media(max-width: 768px) {
        .product-main-class .pl-items {
            grid-template-columns: repeat(1, minmax(0, 1fr));
        }
        .checkout_main_custom .container.el-504683 {
            display: flex;
            flex-direction: column;
            align-items: center;
        }
        .checkout_main_custom .container-box {
            width: 85% !important;
        }
        .checkout_main_custom .container.el-411237, .checkout_main_custom .container.el-454282 {
            margin: 0 !important;
        }
    }
    @media(max-width: 480px) {
        span.pl-pvalue p span:nth-child(1) {
            font-size: 10px !important;
        }
        .product-main-class .pl-item .pl-price p strong {
            font-size: 11px !important;
        }
        span.pl-pvalue p span:nth-child(1) {
            font-size: 10px !important;
        }
        .product-main-class .pl-item .pl-image {
            width: 90px;
        }
        .order-summary .os-row .os-price {
            min-width: 160px;
        }
        .order-summary .os-row .os-price p strong {
            font-size: 20px !important;
        }
        .p-hypen-tag p em {
            padding: 4px 4px;
        }
        .pl-item.small.selected .p-hypen-tag p em {
            padding: 4px 1px !important;
        }
    }
    @media(max-width: 600px) {
        .checkout_main_custom .container-box {
            width: 100% !important;
        }
        .product-main-class .pl-item .pl-name {
            padding-left: 10px;
        }
    }
  </style>
</head>
<body>
  <script>
    document.addEventListener('DOMContentLoaded', function () {
      var windowWidth = $(window).width();
      if (windowWidth <= 600) {
        const plItems = document.querySelectorAll('.product-list.el-410566.product-main-class .pl-items .pl-item');
        function selectItem(item) {
          plItems.forEach(i => {
            i.classList.remove('selected');
            const radio = i.querySelector('input[type="radio"]');
            if (radio) radio.checked = false;
          });
          item.classList.add('selected');
          const radio = item.querySelector('input[type="radio"]');
          if (radio) {
            radio.checked = true;
            radio.dispatchEvent(new Event('change', { bubbles: true }));
          }
        }
        const defaultItem = document.querySelector('.product-list.el-410566.product-main-class .pl-items .pl-item:nth-child(1)');
        if (defaultItem) {
          selectItem(defaultItem);
        }
        plItems.forEach(item => {
          item.addEventListener('click', () => selectItem(item));
        });
      } else if (windowWidth > 600) {
        const plItems = document.querySelectorAll('.product-main-class .pl-items .pl-item');
        function selectItem(item) {
          plItems.forEach(i => {
            i.classList.remove('selected');
            const radio = i.querySelector('input[type="radio"]');
            if (radio) radio.checked = false;
          });
          item.classList.add('selected');
          const radio = item.querySelector('input[type="radio"]');
          if (radio) {
            radio.checked = true;
            radio.dispatchEvent(new Event('change', { bubbles: true }));
          }
        }
        const defaultItem = document.querySelector('.product-main-class .pl-items .pl-item:nth-child(1)');
        if (defaultItem) {
          selectItem(defaultItem);
        }
        plItems.forEach(item => {
          item.addEventListener('click', () => selectItem(item));
        });
      }
    });
  </script>

  <script>
    $(document).ready(function() {
      // Variant IDs for free products (replace with actual IDs)
      const FREE_PRODUCT_IDS = [
        'VARIANT_ID_HOUSSE_1', // 1x Housse de rechange
        'VARIANT_ID_HOUSSE_2', // 2x Housses de rechange
        'VARIANT_ID_EBOOK'    // 1 Livre électronique
      ];

      // Hide free product rows initially
      $('.order-summary .os-items .os-row:nth-child(2), .order-summary .os-items .os-row:nth-child(3), .order-summary .os-items .os-row:nth-child(4)').addClass('hide-force').hide();

      // Append promotional content
      $('.pl-items .pl-item.small:nth-child(2) label.pl-inner').append('<div class="p-hypen-tag"><p><img src="//cellsius-shop.com/cdn/shop/files/CoussinGenou-NouvelleVersion.jpg?v=1700460485&width=300" width="300" height="300" loading="lazy" alt="Housse de rechange lavable - Coussin genoux Cellsius">+ 1 Housse de rechange <em>-30%</em></p></div>');
      $('.pl-items .pl-item.small:nth-child(3) label.pl-inner').append('<div class="p-hypen-tag"><p><img src="//cellsius-shop.com/cdn/shop/files/CoussinGenou-NouvelleVersion.jpg?v=1700460485&width=300" width="300" height="300" loading="lazy" alt="Housse de rechange lavable - Coussin genoux Cellsius">+ 2 Housses de rechange <em>🎁 OFFERTES</em> </p><p><img src="//cellsius-shop.com/cdn/shop/files/IMAGES_PRODUIT_2.jpg?v=1722288720&width=300" width="300" height="300" loading="lazy" alt="Livre Electronique : 7jours pour un sommeil sans douleur">+ 1 e-Book <em>🎁 OFFERT</em></p></div>');

      // Function to update order summary visibility
      function updateOrderSummary(price) {
        $('.order-summary .os-items .os-row:nth-child(2), .order-summary .os-items .os-row:nth-child(3), .order-summary .os-items .os-row:nth-child(4)').addClass('hide-force').hide();
        if (price === '29.90') {
          // No free products
        } else if (price === '39.90') {
          $('.order-summary .os-items .os-row:nth-child(2)').removeClass('hide-force').show(); // 1x Housse
        } else if (price === '59.80') {
          $('.order-summary .os-items .os-row:nth-child(3)').removeClass('hide-force').show(); // 2x Housses
          $('.order-summary .os-items .os-row:nth-child(4)').removeClass('hide-force').show(); // e-Book
        }
      }

      // Function to clear all free product-related inputs
      function clearFreeProducts($form) {
        // Remove all items[] inputs except those marked as main product
        $form.find('input[name^="items["]').each(function() {
          const $input = $(this);
          const isMainProduct = $input.attr('data-main-product') === 'true';
          if (!isMainProduct && FREE_PRODUCT_IDS.includes($input.val())) {
            $input.remove();
          }
        });
        // Remove any orphaned quantity inputs
        $form.find('input[name="items[][quantity]"]').each(function() {
          const $quantityInput = $(this);
          const index = $quantityInput.attr('name').match(/items\[(\d+)\]/)?.[1];
          if (index && !$form.find(`input[name="items[${index}][id]"]`).length) {
            $quantityInput.remove();
          }
        });
        console.log('Form state after clearing free products:', $form.serialize());
      }

      // Attempt to update Funnelish cart (if API is available)
      function updateFunnelishCart(items) {
        if (typeof Funnelish !== 'undefined' && Funnelish.updateCart) {
          Funnelish.updateCart(items).then(() => {
            console.log('Funnelish cart updated successfully:', items);
          }).catch(err => {
            console.error('Failed to update Funnelish cart:', err);
          });
        } else {
          console.warn('Funnelish.updateCart not available.');
        }
      }

      // Handle product selection
      $('.orderCheckoutProduct .pl-item').on('click', function() {
        const $form = $('form');
        const priceElement = $(this).find('.pl-price p strong').text().trim();
        const price = priceElement.match(/[\d,.]+/) ? priceElement.match(/[\d,.]+/)[0].replace(',', '.') : '';
        if (price) {
          clearFreeProducts($form);
          updateOrderSummary(price);
          // Rebuild cart with only selected main product
          const mainProductId = $(this).find('input[type="radio"]').val(); // Assuming radio value is the main product ID
          $form.find('input[name^="items["]').remove();
          $form.append(`<input type="hidden" name="items[][id]" value="${mainProductId}" data-main-product="true">`);
          $form.append('<input type="hidden" name="items[][quantity]" value="1" data-main-product="true">');
          updateFunnelishCart([{ id: mainProductId, quantity: 1 }]);
        } else {
          console.error('Price not found for selected product');
        }
      });

      // Handle form submission
      $('form').on('submit', function(e) {
        e.preventDefault();
        const $form = $(this);
        const selectedItem = $('.orderCheckoutProduct .pl-item.selected');
        const priceElement = selectedItem.find('.pl-price p strong').text().trim();
        const price = priceElement.match(/[\d,.]+/) ? priceElement.match(/[\d,.]+/)[0].replace(',', '.') : '';
        
        // Clear all existing items and rebuild
        $form.find('input[name^="items["]').remove();
        const mainProductId = selectedItem.find('input[type="radio"]').val(); // Main product ID
        $form.append(`<input type="hidden" name="items[][id]" value="${mainProductId}" data-main-product="true">`);
        $form.append('<input type="hidden" name="items[][quantity]" value="1" data-main-product="true">');

        // Add free products based on price
        if (price === '39.90') {
          $form.append('<input type="hidden" name="items[][id]" value="VARIANT_ID_HOUSSE_1" data-free-product="true">');
          $form.append('<input type="hidden" name="items[][quantity]" value="1" data-free-product="true">');
        } else if (price === '59.80') {
          $form.append('<input type="hidden" name="items[][id]" value="VARIANT_ID_HOUSSE_2" data-free-product="true">');
          $form.append('<input type="hidden" name="items[][quantity]" value="1" data-free-product="true">');
          $form.append('<input type="hidden" name="items[][id]" value="VARIANT_ID_EBOOK" data-free-product="true">');
          $form.append('<input type="hidden" name="items[][quantity]" value="1" data-free-product="true">');
        }

        // Update Funnelish cart with the full item list
        const cartItems = [];
        $form.find('input[name="items[][id]"]').each(function() {
          const $idInput = $(this);
          const index = $idInput.attr('name').match(/items\[(\d+)\]/)?.[1];
          const quantity = $form.find(`input[name="items[${index}][quantity]"]`).val();
          cartItems.push({ id: $idInput.val(), quantity: parseInt(quantity) });
        });
        updateFunnelishCart(cartItems);

        // Debug the final state
        console.log('Final form data before submission:', $form.serialize());
        if (typeof Funnelish !== 'undefined' && Funnelish.getCart) {
          Funnelish.getCart().then(cart => {
            console.log('Funnelish cart before submission:', cart);
          }).catch(err => {
            console.error('Failed to fetch Funnelish cart:', err);
          });
        }

        $form.off('submit').submit();
      });

      // Monitor order summary for Funnelish updates
      const observer = new MutationObserver(() => {
        const selectedItem = $('.orderCheckoutProduct .pl-item.selected');
        const priceElement = selectedItem.find('.pl-price p strong').text().trim();
        const price = priceElement.match(/[\d,.]+/) ? priceElement.match(/[\d,.]+/)[0].replace(',', '.') : '';
        if (price) {
          updateOrderSummary(price);
        }
      });
      const orderSummary = document.querySelector('.order-summary .os-items');
      if (orderSummary) {
        observer.observe(orderSummary, { childList: true, subtree: true });
      }

      // Initial setup
      const $form = $('form');
      const defaultItem = $('.orderCheckoutProduct .pl-item.selected');
      if (defaultItem.length) {
        const priceElement = defaultItem.find('.pl-price p strong').text().trim();
        const price = priceElement.match(/[\d,.]+/) ? priceElement.match(/[\d,.]+/)[0].replace(',', '.') : '';
        clearFreeProducts($form);
        updateOrderSummary(price);
        const mainProductId = defaultItem.find('input[type="radio"]').val();
        $form.find('input[name^="items["]').remove();
        $form.append(`<input type="hidden" name="items[][id]" value="${mainProductId}" data-main-product="true">`);
        $form.append('<input type="hidden" name="items[][quantity]" value="1" data-main-product="true">');
        updateFunnelishCart([{ id: mainProductId, quantity: 1 }]);
      }
    });
  </script>
</body>
</html>

Hey @MD_SHAHIN_KABIR :waving_hand:

Yes, this is possible :+1:
Right now your issue is: all free products are always showing.
We need to show them based on selected product only.


:light_bulb: Simple Idea

Think like this:

  • Product A → no free item

  • Product B → show 1 free item

  • Product C → show multiple free items

So we control it using JS + selected product


:white_check_mark: Easy Example (How to do it)

Each product has a radio button.
We listen when user selects a product.
Then we show/hide free items.

<script>
document.addEventListener("DOMContentLoaded", function () {

  const radios = document.querySelectorAll('.product-list input[type="radio"]');

  radios.forEach((radio, index) => {
    radio.addEventListener("change", function () {

      // hide all free products first
      document.querySelectorAll('.free-item').forEach(el => {
        el.style.display = "none";
      });

      // Example logic
      if (index === 0) {
        // Product 1 → no free product
      }

      if (index === 1) {
        // Product 2 → show 1 free item
        document.querySelector('.free-item-1').style.display = "block";
      }

      if (index === 2) {
        // Product 3 → show multiple free items
        document.querySelector('.free-item-2').style.display = "block";
        document.querySelector('.free-item-3').style.display = "block";
      }

    });
  });

});
</script>


:puzzle_piece: What you need to do

  1. Add class to free products:
free-item free-item-1
free-item free-item-2
free-item free-item-3

  1. By default hide them:
.free-item {
  display: none;
}


:bullseye: Result

  • User selects 29.90€ → no free item

  • User selects 39.90€ → 1 free item appears

  • User selects 59.80€ → multiple free items appear


:warning: Important

This controls UI (order summary display)

For final order (confirmation / Shopify sync)
you should also handle it using:
:backhand_index_pointing_right: Funnelish automations (recommended)


In Funnelish, products are controlled by selection (radio input) and shown in order summary dynamically.

You will find a similar solution on this example:
:backhand_index_pointing_right: https://anwer.funnelish.io/women-snail-mucin-cream-1/qf5-checkout-1769274445459175

You can also check video tutorial here https://youtu.be/ZY0R0JCpHZE?t=41

1 Like