Shopify Cart Bug. Two Items added to cart with one click when there is a previous item in cart

Shopify Cart Bug. Two Items added to cart with one click when there is a previous item in cart.

Site: www.lit-escalates.com

Theme: Emerge

@jphillips725 I can replicate that issue. I think there is some custom code with your add to cart script. On the first add to cart only one product added but after the first action two items added to the cart. Can you share me the add to cart code snippet here?

@andriihudimov Thanks! There doesn’t seem to a specific “add to cart” liquid file in the snippets, but here is the full cart snippet:

{%- liquid

assign all_items_added_t = ‘cart.all_items_added’ | t

assign checkout_t = ‘cart.checkout’ | t

assign order_notes_t = ‘cart.order_notes’ | t

assign price_t = ‘cart.price’ | t

assign quantity_t = ‘cart.quantity’ | t

assign subtotal_t = ‘cart.subtotal’ | t

assign total_t = ‘cart.total’ | t

assign your_cart_t = ‘cart.your_cart’ | t

assign empty_html_t = ‘cart.empty_html’ | t: collections_url: routes.all_products_collection_url

if settings.cart–empty-enabled

assign empty_html_t = ‘cart.empty_with_list_html’ | t

endif

assign shipping_taxes_t = ‘cart.shipping_taxes_not_included’ | t

if cart.taxes_included

assign shipping_taxes_t = ‘cart.shipping_taxes_included’ | t

endif

assign empty_list = linklists[settings.cart–empty-list]

-%}

{%- capture cart_notes -%}

{%- if settings.cart–show-note -%}

<div

class=“cart–notes”

{% unless settings.transitions–other or view != ‘drawer’ %}

data-transition-item=“cart-{{ view }}”

{%- if async -%}

data-transition-active=“true”

{%- endif -%}

{% endunless %}

>

<label for="{{ view }}-cart_note" class="cart--notes--heading">

{{- order_notes_t -}}

</label>

<textarea
class="cart--notes--textarea"
id="{{ view }}-cart_note"
name="note"
maxlength="25"
\>{{ cart.note }}</textarea>

</div>

{%- endif -%}

{%- endcapture -%}

{%- capture cart_summary -%}

<div class="cart--summary">

<div class="cart--totals">

{%- unless cart.cart_level_discount_applications == blank -%}

<ul class="cart--discounts">

{%- for discount_application in cart.cart_level_discount_applications -%}

<li class="cart--discount">

<div data-item="nav-text">{{ discount_application.title }}</div>

<span data-item="nav-text" data-text-color="gray">

            –<span class="money">{{ discount_application.total_allocated_amount | money }}

</span>

</span>

</li>

{%- endfor -%}

</ul>

{%- endunless -%}

<div class="cart--total">

<div data-item="block-heading">

{{- subtotal_t -}}:

</div>

<div class="cart--total-price money" data-item="nav-text">

{{- cart.total_price | money_with_currency -}}

</div>

</div>

<div

class=“cart–tax-info”

data-item=“paragraph”

>

{{- shipping_taxes_t -}}

</div>

</div>

<button

type=“submit”

name=“checkout”

class=“cart–checkout-button”

data-item=“button”

data-text=“{{- checkout_t -}}”

{% unless settings.transitions–buttons %}

data-transition-button

{% endunless %}

>

<span class="cart-button--text">

{{- checkout_t -}}

</span>

<span class="cart-button--spinner">

{%- render ‘icons’, icon: ‘spinner’ -%}

</span>

</button>

</div>

{%- endcapture -%}

<cart-element

class=“cart–root”

{% unless section.id == blank %}

data-section-id=“{{ section.id }}”

{% endunless %}

data-view=“{{ view }}”

data-container-width=“3”

{% unless settings.transitions–other %}

data-transition-container=“cart-{{ view }}”

data-transition-type=“fade-in”

data-transition-cascade=“vertical”

data-transition-cascade-interval=“250”

{% endunless %}

>

<form

class=“cart–form”

action=“{{ routes.cart_url }}”

method=“post”

novalidate=“”

{%- if view == ‘drawer’ -%}

data-drawer-scroll-container

{%- endif -%}

>

<div class="cart--wrapper">

<div class="cart--header">

<h2

class=“cart–title”

data-item=“section-heading”

{% unless settings.transitions–other %}

data-transition-item=“cart-{{ view }}”

data-transition-type=“slide-in”

{% endunless %}

>

{{- your_cart_t -}}

</h2>

</div>

{%- unless settings.cart–shipping-limit == blank -%}

{%- liquid

assign free_shipping_limit = settings.cart–shipping-limit | times: 100.0

if cart.total_price >= free_shipping_limit

assign width = 100

assign message = settings.cart–shipping-after

else

assign width = cart.total_price | divided_by: free_shipping_limit | times: 100

assign remaining = free_shipping_limit | minus: cart.total_price | money

assign message = settings.cart–shipping-before | replace: ‘[$]’, remaining

endif

    -%}

<div class="cart--shipping">

<div class="cart--shipping-message" data-item="paragraph">

{{- message -}}

</div>

<div

class=“cart–shipping-bar”

{% unless settings.transitions–other %}

data-transition-item=“cart-{{ view }}”

data-transition-type=“custom”

{% endunless %}

style=“–progress-percent:{{ width }}%;”

>

</div>

{%- endunless -%}

<div class="cart--body">

{%- if view == ‘desktop’ -%}

<div class="cart--headings" data-item="nav-text">

<div class="cart--heading--image"></div>

<div class="cart--heading--title"></div>

<div class="cart--heading--price">

{{- price_t -}}

</div>

<div class="cart--heading--quantity">

{{- quantity_t -}}

</div>

<div class="cart--heading--total">

{{- total_t -}}

</div>

</div>

{%- endif -%}

{%- for item in cart.items -%}

{%- liquid

assign preview_image = item.variant.featured_media.preview_image | default: item.product.featured_media.preview_image

if item.product.has_only_default_variant

assign preview_image = item.product.media[0].preview_image

endif

      -%}

{%- capture item_image -%}

<a class="cart--item--image" href="{{ item.url }}" aria-label="{{ item.product.title }}">

{%- if preview_image == blank -%}

{%- render ‘placeholder’, type: ‘product’, aspect_ratio: 1, placeholder_index: 1 -%}

{%- else -%}

{{-

preview_image |

image_url: width: preview_image.width |

image_tag: widths: “300, 500”, sizes: ‘250px’, loading: ‘lazy’

            -}}

{%- endif -%}

</a>

{%- endcapture -%}

{%- capture item_quantity -%}

{%- assign id = view | append: ‘-updates-’ | append: item.key -%}

<div class="cart--item--quantity">

{%-

render ‘quantity-selector’,

id: id,

type: ‘cart’,

value: item.quantity

          -%}

</div>

{%- endcapture -%}

<div

class=“cart–item”

data-variant-id=“{{ item.variant_id }}”

data-management=“{{ item.variant.inventory_management }}”

data-policy=“{{ item.variant.inventory_policy }}”

data-quantity=“{{ item.variant.inventory_quantity | default: 0 }}”

data-line-num=“{{ forloop.index }}”

{% unless settings.transitions–other %}

data-transition-item=“cart-{{ view }}”

{%- if async -%}

data-transition-active=“true”

{%- endif -%}

{% endunless %}

>

{%- if view == ‘desktop’ -%}

{{- item_image -}}

<div class="cart--item-details">

<div class="cart--item--title">

<div data-item="block-heading">

{{ item.product.title }}

</div>

{%- unless item.variant.title contains ‘Default’ -%}

<div class="cart--item--variant-name" data-item="nav-text">

{{ item.variant.title }}

</div>

{%- endunless -%}

{%- if item.selling_plan_allocation -%}

<div class="cart--item--selling-plan" data-item="small-text">

{{- item.selling_plan_allocation.selling_plan.name -}}

</div>

{%- endif -%}

{%- assign property_size = item.properties | size -%}

{%- if property_size > 0 -%}

{%- for property in item.properties -%}

{%- assign property_first_char = property.first | slice: 0 -%}

{% comment %}

                    Apps often use '\_' in front of a property to hide in background

                  {% endcomment %}

{%- unless property.last == blank or property_first_char == ‘_’ -%}

<br>

{{ property.first }}:

{% comment %}

                      Check if there was an uploaded file associated

                    {% endcomment %}

{%- if property.last contains ‘/uploads/’ -%}

<a href="{{ property.last }}">

{{ property.last | split: ‘/’ | last }}

</a>

{%- else -%}

{{ property.last }}

{%- endif -%}

{%- endunless -%}

{%- endfor -%}

{%- endif -%}

<div

class=“cart–error”

data-item=“small-text”

data-text-color=“alert”

aria-hidden=“true”

>

{{- all_items_added_t -}}

</div>

</div>

</div>

<div class="cart--item--price" data-item="nav-text">

{%- if item.original_price != item.final_price -%}

<div data-item="nav-text" data-text-color="gray">

{{ item.original_price | money }}

</div>

{%- endif -%}

<div class="money" data-item="nav-text">

{{- item.final_price | money -}}

</div>

{%- if item.unit_price_measurement -%}

<div class="cart--item--unit-price-container" data-item="small-text">

{%- liquid

echo item.unit_price | money | append: ‘/’

if item.unit_price_measurement.reference_value != 1

echo item.unit_price_measurement.reference_value

endif

echo item.unit_price_measurement.reference_unit

                -%}

</div>

{%- endif -%}

{% if item.line_level_discount_allocations.size > 0 %}

<div class="money" data-item="nav-text" data-text-color="gray">

{%- for discount_allocation in item.line_level_discount_allocations -%}

{{ discount_allocation.discount_application.title }} (-{{ discount_allocation.amount | money }})

{%- endfor -%}

</div>

{% endif %}

</div>

{{- item_quantity -}}

<div class="cart--item--total" data-item="nav-text">

{%- if item.original_line_price != item.final_line_price -%}

<div data-item="nav-text" data-text-color="gray">

{{ item.original_line_price | money }}

</div>

{%- endif -%}

<div class="money">

{{- item.final_line_price | money -}}

</div>

</div>

{%- else -%}

<div class="cart--item--title">

<div data-item="block-heading">

{{ item.product.title }}

</div>

<div

class=“cart–error”

data-item=“small-text”

data-text-color=“alert”

aria-hidden=“true”

>

{{- all_items_added_t -}}

</div>

</div>

{{- item_image -}}

<div class="cart--item--info">

{%- unless item.variant.title contains ‘Default’ -%}

<div class="cart--item--variant-name" data-item="nav-text">

{{ item.variant.title }}

</div>

{%- endunless -%}

{%- if item.selling_plan_allocation -%}

<div class="cart--item--selling-plan" data-item="small-text">

{{- item.selling_plan_allocation.selling_plan.name -}}

</div>

{%- endif -%}

{%- assign property_size = item.properties | size -%}

{%- if property_size > 0 -%}

<div class="cart--item-properties">

{%- for property in item.properties -%}

{%- assign property_first_char = property.first | slice: 0 -%}

{%- unless property.last == blank or property_first_char == ‘_’ -%}

<br>

{{ property.first }}:

{% comment %} Check if there was an uploaded file associated {% endcomment %}

{%- if property.last contains ‘/uploads/’ -%}

{{ property.last | split: ‘/’ | last }}

{%- else -%}

{{ property.last }}

{%- endif -%}

{%- endunless -%}

{%- endfor -%}

</div>

{%- endif -%}

<div class="cart--item--price">

{%- if item.original_price > item.final_price -%}

<div class="cart--item--orig-price" data-item="nav-text" data-text-color="gray">

{{ item.original_price | money }}

</div>

{%- endif -%}

<div class="cart--item--total money" data-item="nav-text">

{{- item.final_price | money -}}

</div>

{%- if item.unit_price_measurement -%}

<div class="cart--item--unit-price-container" data-item="small-text">

{%- liquid

echo item.unit_price | money | append: ‘/’

if item.unit_price_measurement.reference_value != 1

echo item.unit_price_measurement.reference_value

endif

echo item.unit_price_measurement.reference_unit

                  -%}

</div>

{%- endif -%}

{%- if item.line_level_discount_allocations.size > 0 -%}

<div class="cart--item--discounts" data-item="nav-text" data-text-color="gray">

{%- for discount_allocation in item.line_level_discount_allocations -%}

{{ discount_allocation.discount_application.title }} 

                    (–<span class="money">{{ discount_allocation.amount | money }}</span>)

{%- endfor -%}

</div>

{%- endif -%}

</div>

{{- item_quantity -}}

</div>

{%- endif -%}

</div>

{%- endfor -%}

</div>

{%- if view == ‘desktop’ -%}

<div

class=“cart–footer”

{% unless settings.transitions–other %}

data-transition-item=“cart-{{ view }}”

{%- if async -%}

data-transition-active=“true”

{%- endif -%}

{% endunless %}

>

{{- cart_notes -}}

{{- cart_summary -}}

</div>

{%- else -%}

{{- cart_notes -}}

{%- endif -%}

<div class="cart--empty" data-text-alignment="center">

<div class="cart--empty-text" data-item="paragraph">

{{- empty_html_t -}}

</div>

{%- if settings.cart–empty-enabled and empty_list.links.size > 0 -%}

<div class="cart--empty-list">

{%- for link in empty_list.links -%}

{%- comment %}locksmith:86c1{% endcomment -%}

{%- capture var %}{% render ‘locksmith-variables’, scope: ‘subject’, subject: link, subject_parent: empty_list, variable: ‘transparent’ %}{% endcapture %}{% if var == “true” %}{% else %}{% continue %}{% endif -%}

{%- comment %}</locksmith:86c1>{% endcomment -%}

<a class="cart--empty-link" href="{{ link.url }}" data-item="block-link">

{{- link.title -}} 

</a>

{%- endfor -%}

</div>

{%- endif -%}

</div>

</div>

{%- liquid

unless view == ‘desktop’

echo cart_summary

endunless

-%}

</form>

</cart-element>


@jphillips725 I noticed that the cart.js request sent as setInterval on the first render. I attached the image and you can see on the Network of inspect. This means that there is multiple submit request when the add to cart event happened. I will check the code shortly and let you know.

Thank you! Please let me know what you find out

@jphillips725 I have checked it and this liquid seems good. The issue is comes from the JavaScript initialization logic. To aviod double request you can add this to the Javascript line.
if (this.initialized) return; this.initialized = true;
I think there is the custom JS that handle the add to cart fetch. Can you please share that custom JS code snippet? It should be specified with cartelement or addtocart.

This does look like a theme bug.
The theme seem to add product to cart with ajax, but does not prevent form submission if cart type is set to page.

The problem is in this line:


Can’t recommend any edits since not sure how you see the assets/theme.js in theme code editor.

Check whether the problem persists with cart type set to drawer.

Reach out to theme support.

I guess most testing was done with drawer cart.

Also – your version is 8, the current theme version is 10 and this code is different – changed to handle this properly.