Code to customize options for products

Solved
Highlighted
Tourist
9 0 1

Hey,

I'm trying to add customizable options for some products to avoid creating a whole heap of variants within the product - basically so customers can choose the color and contrast color that they want on a handbag.

I've found this article to be the only viable option so far, so I tried to make a drop-down list following all the instructions.

https://help.shopify.com/en/themes/customization/products/features/get-customization-information-for...

I'm using District theme and cannot get the code to work when I copy it from the UI Elements Generator into the sections liquid code. Can anyone please give me advice on what this should look like in the District theme?

This is one of the codes that I'm trying to enter, I will need three slightly different versions of the same code:

<p class="line-item-property__field">
  <label>Main Color</label><br>
  <select required class="required" id="main-color" name="properties[Main Color]">
    <option value="Black">Black</option>
    <option value="Navy">Navy</option>
    <option value="Forest Green">Forest Green</option>
    <option value="Tan">Tan</option>
    <option value="Red">Red</option>
  </select>
</p>

Any advice would be great, or better yet, is there a way that I can make the option values changeable within the product setup? It would be great to use this template for a bunch of different products, rather than change the code to change the color choices.

Thanks for the help!

0 Likes
Highlighted
Explorer
51 6 31

Hey is this functionality what you are looking for: https://teststoremjp.myshopify.com/products/extra-variants-product-1 that is a test product I created utilizing line item properties. It is also a product that has more than 100 variant combinations by combining multiple product options into this one option. The base Shopify variant options are size color and material, the rest are line item properties. These extra options are unique to this product and can be customized to whatever you want. This is achieved through product metafields, this is basically extra data that you can save for a product (or pretty much anything in Shopify) this data can then be utilized in your liquid files. Here is the example data from the metafield I used to power that example:

[
       {
		"type":"number",
		"title":"number input"
	},
	{
		"type":"select",
		"values":["Tall","Short","Long"],
		"title":"Length"
	},
	{
		"type":"text",
		"title":"Text input"
	},
	{
		"type":"radio",
		"values":["yes","no"],
		"title":"Yes or no"
	},
	{
		"type":"checkbox",
		"values":["dog","cat","bunny"],
		"title":"Pick the cute animals"
	}
]

If you want to go that route I would recommend this app Metafields Guru it is free and allows you to easily change metafields on Shopify. Now this data is a bit more complex and you could have the data be simple text if you want. The other way to add custom information to a product is through tags. You could add option data in the tags and then use that data to populate your dropdown. Keep in mind though if you display these tags anywhere, like in a collection filter you would need to filter those tags out. You definitely want to do it one of these ways otherwise all your products will just have that dropdown displayed (unless you are checking with an if statement or something like that).

 

With all that said when you say it is not working what do you mean? Is it not displaying the line item properties in your cart? Or is the dropdown just not appearing? Are you getting any error messages?

1 Like
Highlighted
Tourist
9 0 1

Thanks for your reply! The example you gave is similar to what I want, but I want all drop down menus, not txt options.

Basically I have a handbag that I want to be customizable, so from a drop-down menu the customer could choose the different colors for different components of the bag. With all these different color options is would probably exceed the variants allowed, and this product will then be made to order so there is no stock to be carried and tracked across all the variants.

There were no error messages in the code, it just simply was not showing up at all when I created a new product with this template.

0 Likes
Highlighted
Explorer
51 6 31

Ok sounds good I will try and whip something up either tonight or tomorrow for you. I will use a metafield method so if you haven't installed that metafield app I suggested go ahead and do that. The reason I want to use metafields is because then you won't have to worry about that data displaying anywhere on your website. Your customers will only see the dropdowns and the dropdowns will be unique to each item.

 

As to why it isn't displaying it is possible you pasted it in either the wrong file or the wrong place in the file, but it is hard to tell without seeing your site. One issue is since district is a payed theme I won't be able to see the code, so I will build a solution for one of the free themes, but it might take some tweaking to get it working correctly with your theme.

0 Likes
Highlighted
Tourist
9 0 1

Thank you so much! I really appreciate your help. New to all of this and while I can get by following most of the tutorials, this one seemed to elude me. Thanks :)

0 Likes
Highlighted
Explorer
51 6 31

So then this is what you want? https://r1e8qrsfx4ezaz9x-3502309425.shopifypreview.com/products/test-product-with-dropdowns this is basically the same product just with extra dropdowns. Like I said before I don't have access to the specific theme you are using so it may take a bit more work to get it working for you so let me know if you have any issues. First thing you should do is go into your snippets folder and create a new file called add-options. Then place this code into that file: 

{%-for option in product.metafields.options.data-%}
	<div class="selector-wrapper js product-form__item extra-option">
      <label>{{ option.title }}</label>
	
	{%-if option.type == "text" -%}
		<input type="text" name="properties[{{ option.title }}]">

	{%-elsif option.type == "number" -%}
		<input type="number" name="properties[{{ option.title }}]">
	{%-elsif option.type == "select" -%}
		<select name="properties[{{ option.title }}">
          {%-for value in option.values -%}
          	<option value="{{ value | escape }}">{{ value }}</option>
          {%-endfor-%}
		</select>
    {%-elsif option.type == "radio" -%}
          {%-for value in option.values -%}
          	<input type="radio" value="{{value}}" name="properties[{{ option.title }}]">{{value}}
          {%-endfor-%}
    {%-elsif option.type == "checkbox" -%}
          {%-for value in option.values -%}
          	<input type="checkbox" value="{{value}}" name="properties[{{ option.title |append: " " |append:forloop.index}}]">{{value}}
          {%-endfor-%}
	{%-endif-%}
   </div>
{%-endfor-%}

Again this may or may not work for you since your theme will have different classes etc. if that is the case message me and we can figure out how to get it working for you. Anyways after you do that there will be a place possibly in your product-template file that actually creates the variant selectors. Paste this code within your product form and make sure it is not within any for loops otherwise it will create multiple copies of the dropdowns.

{%-include 'add-options', product:product-%}

Lastly here is a template to follow for your product metafield, you are going to want to create a metafield for the namespace call it options, for the key call it data, and select the value type as JSON string:

[
	{
		"type":"select",
		"values":["Tall","Short","Long"],
		"title":"Length"
	},
        {
		"type":"select",
		"values":["Red","Green","Yellow"],
		"title":"Color 1"
	},
        {
		"type":"select",
		"values":["Rectangle","Circle","Triangle","Square"],
		"title":"Shape"
	}
]

If you are unfamiliar with JSON data this may get some getting used to, basically make sure the text is always surrounded by double quotes, and each section between {} is a new dropdown. So if you wanted to add a new dropdown you could do something like this:

        {
		"type":"select",
		"values":["option1","option2","etc"],
		"title":"Drop down 2"
	}

This is a bit more complex setup so feel free to ask me questions, and if you need to feel free to message me here and we can work through the implementation. 

1 Like
Highlighted
Tourist
9 0 1

Thanks for all your help! Added the snippets folder. This is what the product-template.liquid file looks like for District theme, and I added the code you suggested on a variety of lines but nothing showed. Followed all other instructions to create the Metafields for this product but it still wouldn't show up on the product page. Any ideas?

 

<div class="product-template" id="ProductSection-{{ section.id }}" data-section-id="{{ section.id }}" data-section-type="product-template" data-enable-history-state="true">
  <section class="single-product" itemscope itemtype="http://schema.org/Product">
    <meta itemprop="name" content="{{ product.title }}{% unless product.has_only_default_variant %} - {{ current_variant.title }}{% endunless %}">
    <meta itemprop="url" content="{{ shop.url }}{{ product.url }}">
    <meta itemprop="image" content="{{ product.featured_image.src | img_url: '1024x1024' }}">
    {% comment %}
      Get first variant, or deep linked one
    {% endcomment %}
    {% assign current_variant = product.selected_or_first_available_variant %}
    <div class="wrapper">

      <header class="content-util">
      {% include 'breadcrumb' %}
      {% include 'social-icons' %}
      </header>

      <header class="product-header">
        <div class="product-jump-container">
          {% comment %}
            If the user is on a collection product page (ie with /collections/collection-handle/products/product-handle)
            in the URL, we can show next/previous links to other products in the collection.
          {% endcomment %}
          {% if collection %}
            {% if collection.previous_product or collection.next_product %}
              <ul class="product-jump">

              {% if collection.previous_product %}
                {% capture prev_url %}{{ collection.previous_product}}#content{% endcapture %}
                <li class="previous">
                  {{ 'products.general.previous_product_html' | t | link_to: prev_url }}
                </li>
              {% endif %}

              {% if collection.next_product %}
                {% capture next_url %}{{ collection.next_product}}#content{% endcapture %}
                <li class="next">
                  {{ 'products.general.next_product_html' | t | link_to: next_url }}
                </li>
              {% endif %}

              </ul>
            {% endif %}
          {% endif %}
        </div>

      </header>

      <div class="grid">
        <div class="product-images thumbnails-placement-{{ section.settings.thumbnails_placement }}">
          <div class="images-container">
            <div class="featured {% if product.images.size == 1 %}full-width{% endif %}" id="ProductPhoto">
              {%- assign image = current_variant.featured_image | default: product.featured_image -%}
              {%- assign image_width = image.width | append: 'x' -%}
              {%- assign image_highresolution = image | img_url: image_width -%}
              <div class="featured-container featured-container-{{ section.id }} {% if section.settings.product_featured_zoom_enable %}featured-zoom{% endif %}" data-zoom="{{ section.settings.product_featured_zoom_enable }}" data-lightbox="{{ section.settings.product_featured_lightbox_enable }}">
                <a href="{{ image_highresolution }}" class="card__image-container">
                  {% assign image_widths = '85,100,200,295,394,590,720,800' %}
                  {% include 'theme-rias' %}
                  <div class="productimage-limit" style="max-width:{{ image.width }}px">
                    <img id="ProductImage" class="lazyload"
                      src="{{ image | img_url: '394x' }}"
                      data-id="{{ section.id }}"
                      data-src="{{ image_url_pattern }}"
                      data-widths="[{{ image_widths }}]"
                      data-aspectratio="{{ image.aspect_ratio }}"
                      data-sizes="auto"
                      data-position="{{ image.position | minus: 1 }}"
                      data-max-width="{{ image.width }}"
                      alt="{{ image.alt | escape }}">
                    <noscript>
                      <img src="{{ image | img_url: '590x' }}" alt="{{ image.alt | escape }}">
                    </noscript>
                  </div>
                </a>
              </div>
            </div>
            {% comment %}
              Create thumbnails if we have more than one product image
            {% endcomment %}
            {% unless product.images.size == 1 %}
              <div class="thumbnails" {% if section.settings.thumbnails_placement == 'hide' %}style="display:none;"{% endif %}>
                <ul id="ProductThumbs-{{ section.id }}">

                  {% for image in product.images %}
                    {%- assign image_width = image.width | append: 'x' -%}
                    {%- assign image_highresolution = image | img_url: image_width -%}
                    {%- assign active_image = current_variant.featured_image | default: product.featured_image -%}
                    <li>
                      <a href="{{ image_highresolution }}" class="product-single__thumbnail--{{ section.id }} {% if image == active_image %}active{% endif %}">
                        {% assign image_widths = '85,100,200,295,394,590,720,800' %}
                        {% include 'theme-rias' %}
                        <img class="lazyload"
                          src="{{ image | img_url: '100x' }}"
                          data-default="{{ image | img_url: '394x' }}"
                          data-src="{{ image_url_pattern }}"
                          data-src-pattern="{{ image_url_pattern }}"
                          data-widths="[{{ image_widths }}]"
                          data-aspectratio="{{ image.aspect_ratio }}"
                          data-sizes="auto"
                          data-position="{{ forloop.index0 }}"
                          data-max-width="{{ image.width }}"
                          alt="{{ image.alt | escape }}">
                        <noscript>
                          <img src="{{ image | img_url: '100x' }}" alt="{{ image.alt | escape }}">
                        </noscript>
                      </a>
                    </li>
                  {% endfor %}

                </ul>
              </div>
            {% endunless %}
          </div>
        </div>
        
        <aside class="product-aside">
          <div class="purchase-box {% if section.settings.product_box_padding %}padding-box{% endif %}" itemprop="offers" itemscope itemtype="http://schema.org/Offer">
            <meta itemprop="priceCurrency" content="{{ shop.currency }}">
            <link itemprop="availability" href="http://schema.org/{% if product.available %}InStock{% else %}OutOfStock{% endif %}">
            
            {% comment %}
              ID addToCartForm is a selector for the ajax cart plugin
            {% endcomment %}
            <form action="/cart/add" method="post" enctype="multipart/form-data" id="AddToCartForm" class="form-vertical product-form product-form-{{ section.id }}" data-section="{{ section.id }}">

              <div class="product-title">
                <h1 itemprop="name">{{ product.title }}</h1>
                {% if section.settings.show_vendors %}
                  <span class="vendor">{{ product.vendor | link_to_vendor }}</span>
                {% endif %}
              </div>

              <div class="selection-wrapper price product-single__price-{{ section.id }}">
                <span class="money" id="ProductPrice-{{ section.id }}" itemprop="price" content="{{ current_variant.price | money_without_currency | remove: ',' }}">{{ current_variant.price | money }}</span>
                {% if current_variant.compare_at_price > current_variant.price %}
                  <p id="ComparePrice-{{ section.id }}" style="display:block;">
                    {{ 'products.product.compare_at' | t }} <span class="money">{{ current_variant.compare_at_price | money }}</span>
                  </p>
                {% else %}
                  <p id="ComparePrice-{{ section.id }}" style="display:none;">
                    {{ 'products.product.compare_at' | t }} <span class="money">{{ current_variant.compare_at_price | money }}</span>
                  </p>
                {% endif %}
              </div>

              {% comment %}
                Collection of variant options
              {% endcomment %}
              {% unless product.has_only_default_variant %}
                <div class="selection-wrapper variant js">
                  <div class="variant-grid">
                    {% for option in product.options_with_values %}
                      <div class="selector-wrapper">
                        <label for="SingleOptionSelector-{{ forloop.index0 }}">
                          {{ option.name }}
                        </label>

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

              {% comment %}
                Primary variant select controlled JS
              {% endcomment %}
              <div class="selection-wrapper variant no-js">
                <div class="selector-wrapper full-width">
                  <select name="id" id="ProductSelect-{{ section.id }}" data-section="{{ section.id }}" class="product-form__variants no-js">
                    {% for variant in product.variants %}
                      {% if variant.available %}
                        <option {% if variant == product.selected_or_first_available_variant %} selected="selected" {% endif %} value="{{ variant.id }}" data-sku="{{ variant.sku }}">
                          {{ variant.title }} - {{ variant.price | money_with_currency }}
                        </option>
                      {% else %}
                        <option disabled="disabled">{{ variant.title }} - {{ 'products.product.sold_out' | t }}</option>
                      {% endif %}
                    {% endfor %}
                  </select>
                </div>
              </div>


              <div class="error cart-error cart-error-{{ section.id }}"></div>
              <div class="selection-wrapper cart">
                {% if section.settings.product_quantity_enable %}
                  <div class="selector-wrapper quantity quantity-{{ section.id }}" {% unless current_variant.available %}style="display:none;"{% endunless %}>
                    <label for="Quantity">{{ 'products.product.quantity' | t }}</label>
                    <div class="quantity-select quantity-select-{{ section.id }}">
                      <div class="button-wrapper">
                        <button class="adjust adjust-minus">-</button>
                      </div>
                      <div class="input-wrapper">
                        <input type="text" class="quantity" value="1" min="1" pattern="[0-9]*" name="quantity" id="Quantity">
                      </div>
                      <div class="button-wrapper">
                        <button class="adjust adjust-plus">+</button>
                      </div>
                    </div>
                  </div>
                {% endif %}
                <div class="button-wrapper">
                  <button type="submit" name="add" id="AddToCart-{{ section.id }}" class="button solid {% unless current_variant.available %}disabled{% endunless %}" {% unless current_variant.available %}disabled{% endunless %}>
                    <span id="AddToCartText-{{ section.id }}">
                      {% unless current_variant.available %}
                        {{ 'products.product.sold_out' | t }}
                      {% else %}
                        {{ 'products.product.add_to_cart' | t }}
                      {% endunless %}
                    </span>
                  </button>
                </div>
              </div>

            </form>
          </div>
          <div class="description rte" itemprop="description">
            {{ product.description }}
          </div>
          {% if section.settings.show_share_buttons %}
            {% include 'social-share' %}
          {% endif %}
        </aside>
      </div>

    </div>
  </section>

  {% comment %}
    Related products
  {% endcomment %}
  {% for block in section.blocks %}
    <div class="product-block-container" {{ block.shopify_attributes }}>
      {% case block.type %}
        {% when 'related_products' %}
          <div class="block-container">
            {% include 'related-products' %}
          </div>

        {% when 'product_collection'}
          {%- assign product_collection_count = '4' -%}
          {%- assign collection_count = '4' -%}
          <div class="simple-collection layout-{{ collection_count }}">
            <div class="wrapper">
              <header>
                {% if block.settings.title != blank %}
                  <h4>{{ block.settings.title | escape }}</h4>
                {% endif %}
                {% if block.settings.button_link != blank and block.settings.button_label != blank %}
                  <a href="{{ block.settings.button_link }}" class="button outline">{{ block.settings.button_label | escape }}</a>
                {% endif %}
              </header>
              <div class="product-container">
                {%- assign collection = collections[block.settings.collection] -%}
                {%- assign product_limit = collection_count -%}
                {% for product in collection.products limit: product_limit  %}
                  {% include 'product-grid-item' %}
                {% else %}
                  {% for i in (1..product_limit) %}
                    {% include 'placeholder-product-grid-item' %}
                  {% endfor %}
                {% endfor %}
              </div>
            </div>
          </div>
      {% endcase %}
    </div>
  {% endfor %}

</div>
{% unless product.empty? %}
  <script type="application/json" id="ProductJson-{{ section.id }}">
    {{ product | json }}
  </script>
{% endunless %}

{% schema %}
{
  "name": "Product pages",
  "settings": [
    {
      "type": "select",
      "id": "thumbnails_placement",
      "label": "Thumbnails placement",
      "options": [
        {
          "value": "side",
          "label": "Side"
        },
        {
          "value": "below",
          "label": "Below"
        },
        {
          "value": "hide",
          "label": "Hide"
        }
      ],
      "default": "side"
    },
    {
      "type": "checkbox",
      "id": "product_quantity_enable",
      "label": "Show quantity selector",
      "default": true
    },
    {
      "type": "checkbox",
      "id": "show_vendors",
      "label": "Show vendor",
      "default": false
    },
    {
      "type": "checkbox",
      "id": "product_featured_zoom_enable",
      "label": "Enable image zoom",
      "default": false
    },
    {
      "type": "checkbox",
      "id": "product_featured_lightbox_enable",
      "label": "Enable image lightbox",
      "default": true
    },
    {
      "type": "checkbox",
      "id": "product_box_padding",
      "label": "Show product details background",
      "default": true
    },
    {
      "type": "checkbox",
      "id": "show_share_buttons",
      "label": "Show social sharing buttons",
      "default": true
    }
  ],
  "blocks": [
    {
      "type": "related_products",
      "name": "Related products",
      "limit": 1,
      "settings": [
        {
          "type": "text",
          "id": "title",
          "label": "Heading",
          "default": "Related Products"
        },
        {
          "type": "text",
          "id": "button_label",
          "label": "Button label",
          "default": "View more"
        }
      ]
    },
    {
      "type": "product_collection",
      "name": "Product Collection",
      "limit": 1,
      "settings": [
        {
          "type": "text",
          "id": "title",
          "label": "Heading",
          "default": "Simple collection"
        },
        {
          "type": "text",
          "id": "button_label",
          "label": "Button label",
          "default": "View more"
        },
        {
          "type": "url",
          "id": "button_link",
          "label": "Button link"
        },
        {
          "id": "collection",
          "type": "collection",
          "label": "Collection"
        }
      ]
    }
  ]
}
{% endschema %}

 

0 Likes
Highlighted
Explorer
51 6 31

That is really weird I will take a look at it and see if I notice anything. In the meantime could you send me a link to the product you tried this on? I want to see if I can find any errors on the live page.

0 Likes
Highlighted
Explorer
51 6 31

One thing I am noticing is that you are missing this line of code:

{%-include 'add-options', product:product-%}

This is the line of code that actually pulls in the add-options file that handles the extra options. I would place that at around line 190 so the code snippet would look something like this:

{% comment %}
                Primary variant select controlled JS
              {% endcomment %}
              <div class="selection-wrapper variant no-js">
                <div class="selector-wrapper full-width">
                  <select name="id" id="ProductSelect-{{ section.id }}" data-section="{{ section.id }}" class="product-form__variants no-js">
                    {% for variant in product.variants %}
                      {% if variant.available %}
                        <option {% if variant == product.selected_or_first_available_variant %} selected="selected" {% endif %} value="{{ variant.id }}" data-sku="{{ variant.sku }}">
                          {{ variant.title }} - {{ variant.price | money_with_currency }}
                        </option>
                      {% else %}
                        <option disabled="disabled">{{ variant.title }} - {{ 'products.product.sold_out' | t }}</option>
                      {% endif %}
                    {% endfor %}
                  </select>
                </div>
              </div>
              {%-comment-%}
include this line here
{%-endcomment-%} {%-include 'add-options', product:product-%} <div class="error cart-error cart-error-{{ section.id }}"></div> <div class="selection-wrapper cart"> {% if section.settings.product_quantity_enable %} <div class="selector-wrapper quantity quantity-{{ section.id }}" {% unless current_variant.available %}style="display:none;"{% endunless %}> <label for="Quantity">{{ 'products.product.quantity' | t }}</label> <div class="quantity-select quantity-select-{{ section.id }}"> <div class="button-wrapper"> <button class="adjust adjust-minus">-</button> </div> <div class="input-wrapper"> <input type="text" class="quantity" value="1" min="1" pattern="[0-9]*" name="quantity" id="Quantity"> </div> <div class="button-wrapper"> <button class="adjust adjust-plus">+</button> </div> </div> </div> {% endif %}

Let me know if that fixes it or if there are anymore issues! Also still send me the link so I can check out the live page and make sure there are no console errors.

 

1 Like
Highlighted
Tourist
9 0 1

Yeah I left that bit of code out to show you the original code for District theme, it wasn't working when I inserted it. It's not working now either. I've made the product live temporarily so you can see it.

https://jahdemade.com/collections/handbags/products/custom-belt-bag

Thank you!

0 Likes