Line item properties is null...

Solved
Tanya_Huang
Tourist
16 0 0

Hi!

Any help is appreciated! Been struggling with this seemingly simple thing all day yesterday! 


Issue: line item properties is null

1. I made a copy of my product.liquid file, named product.engraved.liquid

2. In product.engraved.liquid file, I added two input fields within the <form></form> tags (generated with Shopify UI Elements Generator) to take in the engrave text.

3. Everything looks good on the product page, but after clicking "add to cart" and going to the cart page, the engrave text was not added to line item properties (or anywhere in the cart).

4. I'll paste my product.engraved.liquid and cart.liquid files in the next post. 

 

Here is my page:

https://knotheory.com/products/engraved-silicone-rings-in-antique-gold-personalized-gift-for-him-and...

 

Thank you in advance 🙂🙂

Tanya

Accepted Solution (1)
tim
Shopify Expert
3111 190 1138

This is an accepted solution.

Looks like you're on the right track -- your theme uses Ajax to add item to cart. When doing this, you only pull variant id and quantity from the cart form and ignore the properties.

First step is to try with Ajax cart off (if your theme allows it). This way you will make sure your input fields and cart liquid are set up properly.

So you may try collecting properties from the form and passing them to AddItem, or you may simply use form.serialize() and use this data for ajax.

Basically, here is your code from the addToCartHandle:

      $addToCartBtn.addClass('btn--adding');
      self
        .addItem(variantId, qty)
        .done(function() {

 

Replace it with 

      $addToCartBtn.addClass('btn--adding');
      $.post(
        '/cart/add.js', 
        $('form[action="/cart/add"]').serialize(),
        null,
        'json'
      ) 
      .done(function() {

 

This should do it.

Now at acidgreen

View solution in original post

Replies 18 (18)
Tanya_Huang
Tourist
16 0 0

Here is my product.engraved.liquid file. The only change I made was adding the input tags 

 

{% comment %}
  Assign some variable from configuration in theme customize
{% endcomment %}

{%- assign layout = settings.product_page_layout -%}
{%- if layout == 'top_gallery' -%}
  {%- assign is_full_layout = true -%}
  {%- assign product_image_size = '2048x' -%}
{%- else -%}
  {%- assign is_full_layout = false -%}
  {%- assign product_image_size = '1024x' -%}
{%- endif -%}

{%- assign gallery_type = settings.product_page_gallery_type -%}

{%- unless gallery_type == 'single_slider' or gallery_type == 'center_mode_slider' -%}
  {%- assign is_single_slider = false -%}
{%- else -%}
  {%- assign is_single_slider = true -%}
{%- endunless -%}

{%- assign zoom_type = settings.product_page_zoom_type -%}

{%- if settings.product_page_detail_info_position == 'inside_info_col' -%}
  {%- assign detail_is_inside_col = true -%}
{%- else -%}
  {%- assign detail_is_inside_col = false -%}
{%- endif -%}

{%- if settings.product_page_detail_displaying_type == 'tab' -%}
  {%- assign display_detail_as_tabs = true -%}
{%- else -%}
  {%- assign display_detail_as_tabs = false -%}
{%- endif -%}

{%- assign current_variant = product.selected_or_first_available_variant -%}

{% comment %}
  Declare available badges for product.
  Priority: % > soldout > sale(tag) > hot > new

  - %: percentage of discount
  - soldout: out of stock and not allow pre-order
  - sale/hot/new: tags
{% endcomment %}
{%- if current_variant.compare_at_price > current_variant.price -%}
  {%- assign sale_percent = available_variant.compare_at_price | minus: available_variant.price | times: 100.0 | divided_by: available_variant.compare_at_price | round: 1 -%}
{%- else -%}
  {%- assign sale_percent = 0 -%}
{%- endif -%}

{%- if product.available -%}
  {%- assign sold_out = false -%}
{%- else -%}
  {%- assign sold_out = true -%}
{%- endif -%}

{%- assign is_hot = false -%}
{%- for tag in product.tags -%}
  {%- assign tag_handle = tag | handleize -%}
  {%- if tag_handle == 'hot' -%}
    {%- assign is_hot = true -%}
    {%- break -%}
  {%- endif -%}
{%- endfor -%}

{%- assign is_new = false -%}
{%- for tag in product.tags -%}
  {%- assign tag_handle = tag | handleize -%}
  {%- if tag_handle == 'new' -%}
    {%- assign is_new = true -%}
    {%- break -%}
  {%- endif -%}
{%- endfor -%}

{%- assign is_saleoff = false -%}
{%- for tag in product.tags -%}
  {%- assign tag_handle = tag | handleize -%}
  {%- if tag_handle == 'sale' -%}
    {%- assign is_saleoff = true -%}
  {%- endif -%}
{%- endfor -%}

{%- assign featured_image = current_variant.featured_image | default: product.featured_image -%}

{%- assign disable_availability = settings.product_availability_disable -%}
{%- assign disable_type = settings.product_type_disable -%}
{%- assign disable_vendor = settings.product_vendor_disable -%}
{%- assign disable_sku = settings.product_sku_disable -%}

{%- capture form_selectors -%}

  {% unless product.variants.size == 1 and product.options.size == 1 and product.options.first == 'Title' and product.variants.first.title == 'Default Title' %}
    {%- if settings.variant_selector_type == 'swatch' -%}
      {%- for option in product.options -%}
        {%- assign option_handle = option | downcase -%}
        {%- unless option_handle contains 'title' -%}
          {%- include 'virgo-swatch' with option, prefix: 'prodpage' -%}
        {%- endunless -%}
      {%- endfor -%}
    {%- else -%}
      <div class="product-selectors grid">
        {%- for option in product.options_with_values -%}
          <div class="selector-wrapper grid__item medium-up--one-half">
            <label
              class="swatch__title"
              for="SingleOptionSelector-{{ forloop.index0 }}"
              >
              {{ option.name }}
            </label>

            <select
              class="js-single-selector"
              id="SingleOptionSelector-{{ forloop.index0 }}"
              data-single-option-selector
              data-index="option{{- option.position -}}">
              {%- for value in option.values -%}
                <option
                  value="{{ value | escape }}"
                  {%- if option.selected_value == value -%}
                    selected
                  {%- endif -%}
                  >
                  {{ value }}
                </option>
              {%- endfor -%}
            </select>
          </div>
        {%- endfor -%}
      </div>
    {%- endif -%}
  {%- endunless -%}

  <select name="id" class="no-js" data-product-select>
    {%- for variant in product.variants -%}
      <option
        {% if forloop.first %}
          selected
        {% endif %}
        {% unless variant.available %}
          disabled
        {% endunless %}
        value="{{ variant.id }}"
        data-policy="{{ variant.inventory_policy | default: 'deny' }}"
        data-quantity="{{ variant.inventory_quantity | default: 0 }}"
        >
        {{- variant.title -}}
      </option>
    {%- endfor -%}
  </select>
{%- endcapture -%}

{% comment %}
  Meta tags to define microdata for SEO
{% endcomment %}
<meta itemprop="name" content="{{ product.title }}{% unless current_variant.title == 'Default Title' %} - {{ current_variant.title }}{% endunless %}">
<meta itemprop="url" content="{{ shop.url }}{{ current_variant.url }}">
<meta itemprop="brand" content="{{ product.vendor }}">
<meta itemprop="image" content="{{ featured_image | img_url: '600x600' }}">
<meta itemprop="description" content="{{ product.description | strip_html | escape }}">

{% comment %}
  ---------------------------
  - Main markup start here. -
  ---------------------------
{% endcomment %}
{% comment %}Breadcrumb{% endcomment %}
<div class="product-page__header" {% if settings.product_page_header_image %}style="background-image: url({{ settings.product_page_header_image | img_url: 'master' }});"{% endif %}>
  <div class="page-width">
    {% include 'breadcrumbs' %}
  </div>
</div>

<div class="product-page__content js-product-container" data-enable-history-state="true" itemscope itemtype="http://schema.org/Product">
  {%- unless is_full_layout -%}
    <div class="page-width">
      <div class="grid">
        <div class="grid__item medium-up--one-half one-whole {% if layout == 'right_side_gallery' %}medium-up--push-one-half{% endif %}">
          <section class="product-gallery-wrapper">
            {% include 'product-gallery' %}
          </section>
        </div>

        <div class="grid__item medium-up--one-half one-whole {% if layout == 'right_side_gallery' %}medium-up--pull-one-half{% endif %}">
  {%- endunless -%}

          {%- if is_full_layout -%}
            <section class="product-gallery-wrapper product-gallery-wrapper--full">
              {%- if gallery_type != 'center_mode_slider' -%}
                <div class="page-width">
                  <div class="grid">
                    {%- if gallery_type == 'single_slider' or gallery_type == 'syncing_slider_bottom' -%}
                      <div class="grid__item one-whole medium--two-thirds medium--push-one-sixth large-up--one-half large-up--push-one-quarter">
                    {%- else -%}
                      <div class="grid__item one-whole medium--four-fifths medium--push-one-tenth large-up--two-thirds large-up--push-one-sixth">
                    {%- endif -%}
              {%- endif -%}
                {% include 'product-gallery' %}
              {%- if gallery_type != 'center_mode_slider' -%}
                    </div>
                  </div>
                </div>
              {%- endif -%}
            </section>
          {%- endif -%}

          <section class="product-info-wrapper {% if is_full_layout %}product-info-wrapper--full{% endif %}">
            {%- if is_full_layout -%}
              <div class="page-width">
                <div class="grid">
                  <div class="grid__item one-whole medium--four-fifths medium--push-one-tenth large-up--two-thirds large-up--push-one-sixth">
            {%- endif -%}
            <h1 class="product-info__title">{{ product.title }}</h1>
                    {% include 'judgeme_widgets', widget_type: 'judgeme_preview_badge', jm_style: '', concierge_install: true %}
            {% comment %}
              <p>{{ product.vendor }}</p>
            {% endcomment %}

            <div itemprop="offers" itemscope itemtype="http://schema.org/Offer">
              <meta itemprop="priceCurrency" content="{{ shop.currency }}">
              <meta itemprop="price" content="{{ current_variant.price | divided_by: 100.00 }}">
              <link itemprop="availability" href="http://schema.org/{% if current_variant.available %}InStock{% else %}OutOfStock{% endif %}">

              {%- include 'reviews-badge' -%}

              <div class="product-info__price js-price-wrapper">
                <span class="product-info__price--current js-current-price">
                  {{ current_variant.price | money }}
                </span>

                {% if product.compare_at_price_max > product.price %}
                  <span class="visually-hidden">{{ 'products.product.regular_price' | t }}</span>
                  <s class="js-compare-price">
                    {% if is_saleoff %}
                      {{ current_variant.compare_at_price | money }}
                    {% endif %}
                  </s>
                {% endif %}
              </div>

              {% unless disable_availability and disable_type and disable_vendor and disable_sku %}
                <div class="product-basic-info">
                  {%- unless disable_availability -%}
                    <p class="product-basic-info__item">
                      <span class="label">
                        {{- 'products.product.availability' | t -}}:
                      </span>
                      <span class="content js-availability"></span>
                    </p>
                  {%- endunless -%}
                  {%- unless disable_type or product.type == blank -%}
                    <p class="product-basic-info__item">
                      <span class="label">
                        {{- 'products.product.type' | t -}}:
                      </span>
                      <a href="{{ product.type | url_for_type }}" class="content">
                        {{- product.type -}}
                      </a>
                    </p>
                  {%- endunless -%}
                  {%- unless disable_vendor or product.vendor == blank -%}
                    <p class="product-basic-info__item">
                      <span class="label">
                        {{- 'products.product.vendor' | t -}}:
                      </span>
                      <a href="{{ product.vendor | url_for_vendor }}" class="content">
                        {{- product.vendor -}}
                      </a>
                    </p>
                  {%- endunless -%}
                  {%- unless disable_sku -%}
                    <p class="product-basic-info__item">
                      <span class="label">
                        {{- 'products.product.sku' | t -}}:
                      </span>
                      <span class="content js-sku">
                        {%- if current_variant -%}
                          {{- current_variant.sku -}}
                        {%- endif -%}
                      </span>
                    </p>
                  {%- endunless -%}
                </div>
              {% endunless %}

              <div class="product-form-wrapper">
                {% comment %}
                  [dev] Change to AJAX.
                {% endcomment %}
                {% if settings.show_dynamic_checkout_button %}
                  {% form 'product', product %}
                    {{ form_selectors }}
                
                    <div class="product-action-wrapper js-action-wrapper">
                      <div class="stock out-of-stock js-out-of-stock">
                        <span class="stock__label">
                          {{- 'products.product.out_of_stock' | t -}}
                        </span>
                      </div>
                      <div class="stock unavailable js-unavailable">
                        <span class="stock__label">
                          {{- 'products.product.unavailable' | t -}}
                        </span>
                      </div>
                      <div class="stock available js-available">
                        <div class="input-group input-quantity clearfix">
                          <label class="visually-hidden" for="Quantity">{{ 'products.product.quantity' | t }}</label>
                          <button type="button" class="btn btn--lg quantity-button quantity-button--minus minus">
                            <i class="fa fa-minus"></i>
                          </button>
                          <input type="number" class="input-quantity__value no-spinner js-input-quantity" id="Quantity" name="quantity" value="1" min="1" pattern="[0-9]*">
                          <button type="button" class="btn btn--lg quantity-button quantity-button--plus plus">
                            <i class="fa fa-plus"></i>
                          </button>
                        </div>

                        <button
                          type="submit"
                          name="add"
                          class="btn btn--lg btn--add-to-cart js-virgo-add-to-cart"
                          data-add-to-cart
                          >
                          <span class="add" data-add-to-cart-text>
                            {{ 'products.product.add_to_cart' | t }}
                          </span>
                          <span class="adding">
                            <i class="fa fa-spinner adding"></i>
                          </span>
                        </button>
                        

                        <div class="payment-divider"><span>Or</span></div>
                        {{ form | payment_button }}
                      </div>
                    </div>
                  {% endform %}
                {% else %}
                  <form action="/cart/add" method="post" enctype="multipart/form-data">
                    {{ form_selectors }}
                    

  <!-- Engrave text input begin -->     
<p class="line-item-property__field">
  <label for="inside-engraving">Inside Engraving:&nbsp;</label>
  <input id="inside-engraving" type="text" maxlength="20" size="25" name="properties[Inside Engraving]">
</p>
                    
<p class="line-item-property__field">
  <label for="outside-engraving">Outside Engraving:&nbsp;</label>
  <input id="outside-engraving" type="text" maxlength="20" size="25" name="properties[Outside Engraving]">
</p>
      <!-- Engrave text input end -->  
                                        
                        
                    
                    <div class="product-action-wrapper js-action-wrapper">
                      <div class="stock out-of-stock js-out-of-stock">
                        <span class="stock__label">
                          {{- 'products.product.out_of_stock' | t -}}
                        </span>
                      </div>
                      <div class="stock unavailable js-unavailable">
                        <span class="stock__label">
                          {{- 'products.product.unavailable' | t -}}
                        </span>
                      </div>
                      <div class="stock available js-available">
                        <div class="input-group input-quantity clearfix">
                          <label class="visually-hidden" for="Quantity">{{ 'products.product.quantity' | t }}</label>
                          <button type="button" class="btn btn--lg quantity-button quantity-button--minus minus">
                            <i class="fa fa-minus"></i>
                          </button>
                          <input type="number" class="input-quantity__value no-spinner js-input-quantity" id="Quantity" name="quantity" value="1" min="1" pattern="[0-9]*">
                          <button type="button" class="btn btn--lg quantity-button quantity-button--plus plus">
                            <i class="fa fa-plus"></i>
                          </button>
                        </div>

                        <button
                          type="submit"
                          name="add"
                          class="btn btn--lg btn--add-to-cart js-virgo-add-to-cart"
                          data-add-to-cart
                          >
                          <span class="add" data-add-to-cart-text>
                            {{ 'products.product.add_to_cart' | t }}
                          </span>
                          <span class="adding">
                            <i class="fa fa-spinner adding"></i>
                          </span>
                        </button>
                      </div>
                    </div>
                  </form>
                {% endif %}
                
                
                
                
                
              </div>

            </div>
            {%- if is_full_layout -%}
                  </div>
                </div>
              </div>
            {%- endif -%}
          </section>

          {%- unless is_full_layout -%}
            {%- if detail_is_inside_col -%}
              <section class="product-detail-wrapper product-detail-wrapper--inside">
                {%- if display_detail_as_tabs -%}
                  {% section 'product-togglable-tabs' %}
                {%- else -%}
                  {% section 'product-accordion' %}
                {%- endif -%}
              </section>
            {%- endif -%}

            {%- if settings.product_page_show_share_buttons -%}
              {% include 'social-sharing', share_title: product.title, share_permalink: product.url, share_image: product %}
            {%- endif -%}
          {%- endunless -%}
        {%- unless is_full_layout -%}
        </div>
        {%- endunless -%}

        {%- if is_full_layout -%}
          <section class="product-detail-wrapper product-detail-wrapper--outside">
            <div class="page-width">
              <div class="grid">
                <div class="grid__item one-whole medium--four-fifths medium--push-one-tenth large-up--two-thirds large-up--push-one-sixth">
                  {%- if display_detail_as_tabs -%}
                    {% section 'product-togglable-tabs' %}
                  {%- else -%}
                    {% section 'product-accordion' %}
                  {%- endif -%}
                </div>
              </div>
            </div>
          </section>

          {% if settings.product_page_show_share_buttons %}
            <div class="page-width social-sharing-wrapper--full">
              {% include 'social-sharing', share_title: product.title, share_permalink: product.url, share_image: product %}
            </div>
          {% endif %}
        {%- else -%}
          {%- unless detail_is_inside_col -%}
            <div class="grid__item one-whole">
              <section class="product-detail-wrapper product-detail-wrapper--outside">
                {%- if display_detail_as_tabs -%}
                  {% section 'product-togglable-tabs' %}
                {%- else -%}
                  {% section 'product-accordion' %}
                {%- endif -%}
              </section>
            </div>
          {%- endunless -%}
        {%- endif -%}

        {%- unless is_full_layout -%}
          <div class="grid__item one-whole">
        {%- endunless -%}
          {% section 'related-product' %}
        {%- unless is_full_layout -%}
          </div>
        {%- endunless -%}

  {%- unless is_full_layout -%}
      </div>
    </div>
  {%- endunless -%}

  {% unless product.empty? %}
    <script type="application/json" data-product-json>
      {{ product | json }}
    </script>
  {% endunless %}
</div>
<script>
$(document).ready(function() {
  new theme.Product('.js-product-container', {{ current_variant.id }});
})
</script>
<div id="wc_review_section" class="wc_review_main_content" data-url="{{ shop.url }}" data-handle="{{ product.handle }}" data-limit="0"></div><div class="yotpo yotpo-main-widget" data-product-id="{{ product.id }}" data-name="{{ product.title | escape }}" data-url="{{ shop.url }}{{ product.url }}" data-image-url="{{ product.featured_image | product_img_url: 'large' |replace: '?', '%3F' | replace: '&amp;','%26'}}" data-description="{{ product.description | escape }}" data-price="{{ variant.price | money_without_currency }}" data-currency="{{ shop.currency }}"></div>
{% include 'judgeme_widgets', widget_type: 'judgeme_review_widget', concierge_install: true, auto_install: true %}

 

 

Tanya_Huang
Tourist
16 0 0

Here's my cart.liquid file. The only change I added here were the line item properties and cart json dumps, hoping to see what's going on. It just shows properties to be null :'(

<div class="page__header page__header--small" {% if settings.page_header_image %}style="background-image: url({{ settings.page_cart_header_image | img_url: 'master' }});"{% endif %}>
<div class="page-width">
<header class="text-center">
<h2 class="page__title">{{ 'cart.general.title' | t }}</h2>
{% include 'breadcrumbs' %}
</header>
</div>
</div>

<div class="page-width">
{% if cart.item_count > 0 %}
<div class="cart">
<form action="/cart" method="post" novalidate>
<table class="table responsive-table">
<thead class="small--hide">
<tr>
<th colspan="2">{{ 'cart.label.product' | t }}</th>
<th>{{ 'cart.label.price' | t }}</th>
<th>{{ 'cart.label.quantity' | t }}</th>
<th>{{ 'cart.label.total' | t }}</th>
<th></th>
</tr>
</thead>
<tbody>

{% for item in cart.items %}

{% comment %}

Cart Item Template
=====================
The data-label attributes on <td> elements are mobile-friendly
helpers used for responsive-table labels
{% endcomment %}

<tr class="responsive-table-row">
<td class="small-text-center" data-label="{{ 'customer.order.product' | t }}">
<a href="{{ item.url | within: collections.all }}">
<img width="80" src="{{ item | img_url: '80x' }}"
srcset="{{ item | img_url: '80x' | split:'?' | first }} 80w,
{{ item | img_url: '118x150' | split:'?' | first }} 118w,
{{ item | img_url: '235x300' | split:'?' | first }} 235w,
{{ item | img_url: '768x980' | split:'?' | first }} 768w,
{{ item | img_url: '803x1024' | split:'?' | first }} 803w,
{{ item | img_url: '370x472' | split:'?' | first }} 370w,
{{ item | img_url: 'master' | split:'?' | first }} 870w"
alt="{{ item.title | escape }}" sizes="(max-width: 240px) 100vw, 240px">
</a>
</td>
<td>


<a class="cart__item__name" href="{{ item.url }}">{{ item.product.title }}</a>


{% unless item.variant.title contains 'Default' %}
<dl class="cart__item__variant">
{% for option in item.product.options %}
<dt class="variant-label">{{ option }}:</dt>
<dd class="variant-value">{{ item.variant.options[forloop.index0] }}</dd>
{% endfor %}
</dl>
{% endunless %}

<p class="cart__item__vendor">{{ item.vendor }}</p>

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

<!-- line item properties dump--> 
<strong>line_item.properties json dump:</strong> 
{{ line_item.properties | json }}

<br><br>

<!-- cart dump--> 
<strong>cart json dump:</strong> 
{{ cart | json }}

<br><br>


{% if property_size > 0 %}
{% for p in item.properties %}
{% unless p.last == blank %}
{{ p.first }}:

{% if p.last contains '/uploads/' %}
<a href="{{ p.last }}">{{ p.last | split: '/' | last }}</a>
{% else %}
{{ p.last }}
{% endif %}

{% endunless %}
{% endfor %}
{% endif %}
</td>
<td class="text-center small--text-right" data-label="{{ 'cart.label.price' | t }}">
{% if item.original_line_price != item.line_price %}
<span class="visually-hidden">{{ 'cart.label.discounted_price' | t }}</span>
{{ item.price | money }}
<span class="visually-hidden">{{ 'cart.label.original_price' | t }}</span>
<s>{{ item.original_price | money }}</s>
{% else %}
{{ item.price | money }}
{% endif %}
</td>
<td class="text-center small--text-right" data-label="{{ 'cart.label.quantity' | t }}">
<div class="input-quantity js-quantity">
<button type="button" class="input-quantity__button minus">
{% include 'icon-minus' %}
</button>
<input type="number"
name="updates[]"
id="updates_{{ item.key }}"
value="{{ item.quantity }}"
min="0"
class="input-quantity__value"
aria-label="{{ 'cart.general.item_quantity' | t }}">
<button type="button" class="input-quantity__button plus">
{% include 'icon-plus' %}
</button>
</div>
</td>
<td class="text-center small--text-right" data-label="{{ 'cart.label.total' | t }}">
{{ item.line_price | money }}
</td>
<td class="text-center small--text-right" data-label="{{ 'cart.label.remove' | t }}">
<a href="/cart/change?line={{ forloop.index }}&amp;quantity=0">
{% include 'icon-close' %}
</a>
</td>
</tr>

{% endfor %}
</tbody>
</table>

<div class="grid">
<div class="grid__item large-up--one-half one-whole">
{% if settings.cart_notes_enable %}
<div class="cart__note">
<label for="CartSpecialInstructions">{{ 'cart.general.note' | t }}</label>
<textarea name="note" id="CartSpecialInstructions">{{ cart.note }}</textarea>
</div>
{% else %}
&nbsp;
{% endif %}
</div>
<div class="grid__item large-up--one-half one-whole">
<div class="cart__total">
<label class="cart__total__label">{{ 'cart.general.subtotal' | t }}</label>
<p class="cart__total__value">{{ cart.total_price | money }}</p>
{% if cart.total_discounts > 0 %}
<p>{{ 'cart.general.savings' | t }} {{ cart.total_discounts | money }}</p>
{% endif %}
<p>{{ 'cart.general.shipping_at_checkout' | t }}</p>
</div>
<div class="cart__action">
<input type="submit" name="update" class="btn btn--outline" value="{{ 'cart.general.update' | t }}">
<input type="submit" name="checkout" class="btn" value="{{ 'cart.general.checkout' | t }}">
</div>
</div>
</div>
</form>
</div>
{% else %}
<div class="cart--empty text-center">
{% comment %}
Cart empty state
{% endcomment %}
<div class="supports-cookies">
<div class="cart__icon">
{% include 'icon-cart-outline' %}
</div>
<div class="cart__text">
<p>{{ 'cart.general.empty' | t }}</p>
</div>
<a href="/collections/all" class="btn btn--outline btn--circled">{{ 'cart.general.continue_browsing' | t }}</a>
</div>

{% comment %}
Cart no cookies state
---------------------
Browser cookies are required to use the cart. If cookies aren't enabled in the
browser a message is displayed prompting the user to enable them.
{% endcomment %}
<div class="supports-no-cookies">
<p>{{ 'cart.general.cookies_required' | t }}</p>
</div>
</div>
{% endif %}
</div>
Ninthony
Shopify Partner
2321 349 1019

Did you make any changes to cart.liquid to output the properties? It probably won't do so by default. Find your loop for your line items in cart.liquid, it'll probably look something like:

{% for item in cart.items %}
// Code for your line items, then echo out the properties underneath.
 {% unless item.properties == empty %}
<ul>
  {% for property in item.properties %}
  <li>{{ property.first }}: {{ property.last }}</li>
  {% endfor %}
</ul>
{% endunless %}
{% endfor %}

 

More info: https://shopify.dev/docs/themes/liquid/reference/objects/line_item/#line_item-properties

If my solution helped you, please like it and accept it as the solution!
If you'd like to make any edits to your store, please send me a personal message and we can discuss what you'd like to accomplish 😄
Tanya_Huang
Tourist
16 0 0

Hi Ninthony!

Yes, the theme already had this loop in product.liquid (so it's also in my product.engraved.liquid file because it's a copy of product.liquid).

I added {{ item | json }} to check cart item's content and its properties is null 😞

                {% if property_size > 0 %}
                  {% for p in item.properties %}
                    {% unless p.last == blank %}
                     {{ p.first }}:

                    {% if p.last contains '/uploads/' %}
                      <a href="{{ p.last }}">{{ p.last | split: '/' | last }}</a>
                    {% else %}
                      {{ p.last }}
                    {% endif %}

                    {% endunless %}
                  {% endfor %}
                {% endif %}

 

Tanya_Huang
Tourist
16 0 0

I couldn't figure out why the input field content is not getting stored into the line item properties array....

Ninthony
Shopify Partner
2321 349 1019

Hm, I'm not sure. It looks like you're doing it correctly but I could be missing something. Would you mind if I requested access to your themes and took a look?

If my solution helped you, please like it and accept it as the solution!
If you'd like to make any edits to your store, please send me a personal message and we can discuss what you'd like to accomplish 😄
Tanya_Huang
Tourist
16 0 0

Hi Ninthony!

That would be cool, yes, please!

How does receiving / granting access work? Let me know 🙂

Tanya

Ninthony
Shopify Partner
2321 349 1019

I requested access, you should get an email in the one associated with your account where you can approve

If my solution helped you, please like it and accept it as the solution!
If you'd like to make any edits to your store, please send me a personal message and we can discuss what you'd like to accomplish 😄
Tanya_Huang
Tourist
16 0 0

Ahh, I didn't know this! Just shared access. Thanks Ninthony!

Ninthony
Shopify Partner
2321 349 1019

Hey Tanya, I took a look at your code. Honestly, I have no idea what the problem is. It appears you have everything done correctly. You were using line_item.properties though instead of item.properties (you have to use whatever key was specified at the beginning of the loop, E.g. "for item in cart.items" you would need to use "item" not "line_item"). But even after switching that it still returns null. I haven't the faintest idea why it's not working. I reverted all changes that I made to the code.

If my solution helped you, please like it and accept it as the solution!
If you'd like to make any edits to your store, please send me a personal message and we can discuss what you'd like to accomplish 😄
Tanya_Huang
Tourist
16 0 0

Hey Ninthony,

Thanks for taking the time to look at my code! 

Though I wish there WAS something wrong with it...maybe I'll look for a working example within my theme...

I assumed line_item is a special object in Liquid, so it didn't need to be created / defined in the code:

https://shopify.dev/docs/themes/liquid/reference/objects/line_item

Tanya

Ninthony
Shopify Partner
2321 349 1019

It is, but you access the line item object through cart.items -- So when you define your key in the for loop it could be anything. You could say

{% for line_item in cart.items %}
  {{ line_item.title }}
{% endfor %}

 

Or you could say:

{% for spaghetti in cart.items %}
 {{ spaghetti.title }}
{% endfor %}

 

You'd get the same result either way. So it depends on how it's defined in the beginning of the forloop.

If my solution helped you, please like it and accept it as the solution!
If you'd like to make any edits to your store, please send me a personal message and we can discuss what you'd like to accomplish 😄
Tanya_Huang
Tourist
16 0 0

Hi Ninthony!

I figured out the culprit!

In my theme.js, line 3113, there is an addItem() function to add product to the cart. Here, the "properties" variable was not assigned any value.

This is javascript though....are you familiar with javascript?

 

tim
Shopify Expert
3111 190 1138

This is an accepted solution.

Looks like you're on the right track -- your theme uses Ajax to add item to cart. When doing this, you only pull variant id and quantity from the cart form and ignore the properties.

First step is to try with Ajax cart off (if your theme allows it). This way you will make sure your input fields and cart liquid are set up properly.

So you may try collecting properties from the form and passing them to AddItem, or you may simply use form.serialize() and use this data for ajax.

Basically, here is your code from the addToCartHandle:

      $addToCartBtn.addClass('btn--adding');
      self
        .addItem(variantId, qty)
        .done(function() {

 

Replace it with 

      $addToCartBtn.addClass('btn--adding');
      $.post(
        '/cart/add.js', 
        $('form[action="/cart/add"]').serialize(),
        null,
        'json'
      ) 
      .done(function() {

 

This should do it.

Now at acidgreen
Tanya_Huang
Tourist
16 0 0

Omg it worked!! Thank you thank you Tim!!

I was looking into passing the properties object into the cart, and it involved so many changes in so many places!

Your solution of serializing the form is so elegant. Thank you again. Thank you thank you!!

Tanya

Ninthony
Shopify Partner
2321 349 1019

@tim with the save, I didn't even think about the fact it could be adding through javascript. Glad its working

If my solution helped you, please like it and accept it as the solution!
If you'd like to make any edits to your store, please send me a personal message and we can discuss what you'd like to accomplish 😄
Tanya_Huang
Tourist
16 0 0

Thank you so much too @Ninthony for confirming that the liquid side of things were fine!

EasifyApps-Zoe
Shopify Partner
581 13 34

Hi @Tanya_Huang,

Setting up your Engraving option is a breeze with the Easify Product Options app, and it doesn't require any coding 🤗.

 

EasifyAppsZoe_1-1696537035987.png

 

If you'd like, you can take a look at this demo, which includes an engraving option similar to what you're looking for, for reference.

EasifyAppsZoe_2-1696537108151.png

EASIFY - MAKING SHOPIFY SIMPLE & SWEET!
Easify Product Options: Create custom product options 10X faster & easier!
Easify Product Attachments: Effortlessly add downloadable PDF files (or any other format) to Shopify pages!
Try for Free | 24/7 Live Chat Support