Separating the color option from the rest of the options

michaelmorgan
Shopify Partner
30 1 5

I need to separate the color option from the rest of the product options in the theme customizer. This way the client can have control of having the color option as a button and the other options as dropdowns. The code below is what I have so far. I tried doing a for loop with the option name == 'color' but for some reason, it is looping in the other variants and duplicating them like in the image below. I have also added an image of what the customizer layout is now, so you can see that the Color has a separate option.

options.jpgdownload.jpg

{%- unless product.has_only_default_variant -%}
{%- for product_option in product.options_with_values -%}
 {%- if product_option.name == "Color" -%}
     {%- if block.settings.color_picker_type == 'button' -%}
       <variant-radios class="no-js-hidden" data-section="{{ section.id }}" data-url="{{ product.url }}" {{ block.shopify_attributes }}>
         {%- for option in product.options_with_values -%}
             <fieldset class="js product-form__input">
               <legend class="form__label">{{ option.name }}</legend>
               {%- for value in option.values -%}
                 <input type="radio" id="{{ section.id }}-{{ option.position }}-{{ forloop.index0 }}"
                       name="{{ option.name }}"
                       value="{{ value | escape }}"
                       form="{{ product_form_id }}"
                       {% if option.selected_value == value %}checked{% endif %}
                 >
                 {% if product.variants[forloop.index0].metafields.color.values and option.name == 'Color' %}
                   <label id="color" for="{{ section.id }}-{{ option.position }}-{{ forloop.index0 }}" style="background-color: {{product.variants[forloop.index0].metafields.color.values}}">
                     &nbsp;
                   </label>
                 {% else %}
                   <label for="{{ section.id }}-{{ option.position }}-{{ forloop.index0 }}">
                     {{ value }}
                   </label>
                 {% endif %} 

                 <style>
                   {% if product.variants[forloop.index0].metafields.color.values and option.name == 'Color' %}
                   .product-form__input input[type=radio]:checked+#color {
                     padding: 0!important;
                     height: 35px;
                     border-radius: 100%;
                     width: 35px;
                     outline: 1px solid #000!important;
                     outline-offset: 5px;
                     margin: 8px 0 0 !important;
                     vertical-align: bottom;
                   }

                   .product-form__input input[type=radio]+#color {
                     padding: 0px!important;
                     height: 35px;
                     border-radius: 100%;
                     width: 35px;
                     outline: none!important;
                     outline-offset: 5px;
                     margin: 12px 6px 0!important;
                   }
                   {% endif %}
                 </style>

               {%- endfor -%}
             </fieldset>
         {%- endfor -%}
         <script type="application/json">
           {{ product.variants | json }}
         </script>
       </variant-radios>
     {%- else -%}
       <variant-selects class="no-js-hidden" data-section="{{ section.id }}" data-url="{{ product.url }}" {{ block.shopify_attributes }}>
         {%- for option in product.options_with_values -%}
           <div class="product-form__input product-form__input--dropdown">
             <label class="form__label" for="Option-{{ section.id }}-{{ forloop.index0 }}">
               {{ option.name }}
             </label>
             <div class="select">
               <select id="Option-{{ section.id }}-{{ forloop.index0 }}"
                 class="select__select"
                 name="options[{{ option.name | escape }}]"
                 form="{{ product_form_id }}"
               >
                 {%- for value in option.values -%}
                   <option value="{{ value | escape }}" {% if option.selected_value == value %}selected="selected"{% endif %}>
                     {{ value }}
                   </option>
                 {%- endfor -%}
               </select>
               {% render 'icon-caret' %}
             </div>
           </div>
         {%- endfor -%}

         <script type="application/json">
           {{ product.variants | json }}
         </script>
       </variant-selects>
 {%- endif -%}
 {%- else -%}
   {%- if block.settings.picker_type == 'button' -%}
       <variant-radios class="no-js-hidden" data-section="{{ section.id }}" data-url="{{ product.url }}" {{ block.shopify_attributes }}>
         {%- for option in product.options_with_values -%}
             <fieldset class="js product-form__input">
               <legend class="form__label">{{ option.name }}</legend>
               {%- for value in option.values -%}
                 <input type="radio" id="{{ section.id }}-{{ option.position }}-{{ forloop.index0 }}"
                       name="{{ option.name }}"
                       value="{{ value | escape }}"
                       form="{{ product_form_id }}"
                       {% if option.selected_value == value %}checked{% endif %}
                 >
               {%- endfor -%}
             </fieldset>
         {%- endfor -%}
         <script type="application/json">
           {{ product.variants | json }}
         </script>
       </variant-radios>
     {%- else -%}
       <variant-selects class="no-js-hidden" data-section="{{ section.id }}" data-url="{{ product.url }}" {{ block.shopify_attributes }}>
         {%- for option in product.options_with_values -%}
           <div class="product-form__input product-form__input--dropdown">
             <label class="form__label" for="Option-{{ section.id }}-{{ forloop.index0 }}">
               {{ option.name }}
             </label>
             <div class="select">
               <select id="Option-{{ section.id }}-{{ forloop.index0 }}"
                 class="select__select"
                 name="options[{{ option.name | escape }}]"
                 form="{{ product_form_id }}"
               >
                 {%- for value in option.values -%}
                   <option value="{{ value | escape }}" {% if option.selected_value == value %}selected="selected"{% endif %}>
                     {{ value }}
                   </option>
                 {%- endfor -%}
               </select>
               {% render 'icon-caret' %}
             </div>
           </div>
         {%- endfor -%}

         <script type="application/json">
           {{ product.variants | json }}
         </script>
       </variant-selects>
     {%- endif -%}
   {%- endif -%}	
{%- endfor -%}
{%- endunless -%}

 

Replies 5 (5)

LitExtension
Shopify Partner
4860 1001 1125

Hi @michaelmorgan,

Please change all code:

{%- unless product.has_only_default_variant -%}
  {%- for option in product.options_with_values -%}
    {%- if option.name == "Color" -%}
      <variant-radios class="no-js-hidden" data-section="{{ section.id }}" data-url="{{ product.url }}" {{ block.shopify_attributes }}>
        <fieldset class="js product-form__input">
          <legend class="form__label">{{ option.name }}</legend>
          {%- for value in option.values -%}
          <input type="radio" id="{{ section.id }}-{{ option.position }}-{{ forloop.index0 }}"
                 name="{{ option.name }}"
                 value="{{ value | escape }}"
                 form="{{ product_form_id }}"
                 {% if option.selected_value == value %}checked{% endif %}
                 >
          {% if product.variants[forloop.index0].metafields.color.values and option.name == 'Color' %}
          <label id="color" for="{{ section.id }}-{{ option.position }}-{{ forloop.index0 }}" style="background-color: {{product.variants[forloop.index0].metafields.color.values}}">
            &nbsp;
          </label>
          {% else %}
          <label for="{{ section.id }}-{{ option.position }}-{{ forloop.index0 }}">
            {{ value }}
          </label>
          {% endif %} 

          <style>
            {% if product.variants[forloop.index0].metafields.color.values and option.name == 'Color' %}
            .product-form__input input[type=radio]:checked+#color {
              padding: 0!important;
              height: 35px;
              border-radius: 100%;
              width: 35px;
              outline: 1px solid #000!important;
              outline-offset: 5px;
              margin: 8px 0 0 !important;
              vertical-align: bottom;
            }

            .product-form__input input[type=radio]+#color {
              padding: 0px!important;
              height: 35px;
              border-radius: 100%;
              width: 35px;
              outline: none!important;
              outline-offset: 5px;
              margin: 12px 6px 0!important;
            }
            {% endif %}
          </style>

          {%- endfor -%}
        </fieldset>
        <script type="application/json">
                   {{ product.variants | json }}
        </script>
      </variant-radios>
    {%- else -%}
      <variant-selects class="no-js-hidden" data-section="{{ section.id }}" data-url="{{ product.url }}" {{ block.shopify_attributes }}>
        <div class="product-form__input product-form__input--dropdown">
          <label class="form__label" for="Option-{{ section.id }}-{{ forloop.index0 }}">
            {{ option.name }}
          </label>
          <div class="select">
            <select id="Option-{{ section.id }}-{{ forloop.index0 }}"
                    class="select__select"
                    name="options[{{ option.name | escape }}]"
                    form="{{ product_form_id }}"
                    >
              {%- for value in option.values -%}
              <option value="{{ value | escape }}" {% if option.selected_value == value %}selected="selected"{% endif %}>
                {{ value }}
              </option>
              {%- endfor -%}
            </select>
            {% render 'icon-caret' %}
          </div>
        </div>
        <script type="application/json">
                 {{ product.variants | json }}
        </script>
      </variant-selects>
    {%- endif -%}	
  {%- endfor -%}
{%- endunless -%}

Hope it helps!

LitExtension - Shopping Cart Migration Expert
Check out our Shopify migration app to migrate your online store to Shopify
michaelmorgan
Shopify Partner
30 1 5

That works! thank you!

michaelmorgan
Shopify Partner
30 1 5

Hey, I have implemented the code but now I notice that now the variant selector (dropdown) isn't connected with the variant options. I think it has something to do with the for loop. It doesn't change the product image and the price disappears. Here is the JS that I believe applies to the variant dropdown.

class VariantSelects extends HTMLElement {
  constructor() {
    super();
    this.addEventListener('change', this.onVariantChange);
  }

  onVariantChange() {
    this.updateOptions();
    this.updateMasterId();
    this.toggleAddButton(true, '', false);
    this.updatePickupAvailability();
    this.removeErrorMessage();

    if (!this.currentVariant) {
      this.toggleAddButton(true, '', true);
      this.setUnavailable();
    } else {
      this.updateMedia();
      this.updateURL();
      this.updateVariantInput();
      this.renderProductInfo();
      this.updateShareUrl();
    }
  }

  updateOptions() {
    this.options = Array.from(this.querySelectorAll('select'), (select) => select.value);
  }

  updateMasterId() {
    this.currentVariant = this.getVariantData().find((variant) => {
      return !variant.options.map((option, index) => {
        return this.options[index] === option;
      }).includes(false);
    });
  }

  updateMedia() {
    if (!this.currentVariant) return;
    if (!this.currentVariant.featured_media) return;

    const mediaGallery = document.getElementById(`MediaGallery-${this.dataset.section}`);
    mediaGallery.setActiveMedia(`${this.dataset.section}-${this.currentVariant.featured_media.id}`, true);

    const modalContent = document.querySelector(`#ProductModal-${this.dataset.section} .product-media-modal__content`);
    const newMediaModal = modalContent.querySelector( `[data-media-id="${this.currentVariant.featured_media.id}"]`);
    modalContent.prepend(newMediaModal);
  }

  updateURL() {
    if (!this.currentVariant || this.dataset.updateUrl === 'false') return;
    window.history.replaceState({ }, '', `${this.dataset.url}?variant=${this.currentVariant.id}`);
  }

  updateShareUrl() {
    const shareButton = document.getElementById(`Share-${this.dataset.section}`);
    if (!shareButton) return;
    shareButton.updateUrl(`${window.shopUrl}${this.dataset.url}?variant=${this.currentVariant.id}`);
  }

  updateVariantInput() {
    const productForms = document.querySelectorAll(`#product-form-${this.dataset.section}, #product-form-installment`);
    productForms.forEach((productForm) => {
      const input = productForm.querySelector('input[name="id"]');
      input.value = this.currentVariant.id;
      input.dispatchEvent(new Event('change', { bubbles: true }));
    });
  }

  updatePickupAvailability() {
    const pickUpAvailability = document.querySelector('pickup-availability');
    if (!pickUpAvailability) return;

    if (this.currentVariant && this.currentVariant.available) {
      pickUpAvailability.fetchAvailability(this.currentVariant.id);
    } else {
      pickUpAvailability.removeAttribute('available');
      pickUpAvailability.innerHTML = '';
    }
  }

  removeErrorMessage() {
    const section = this.closest('section');
    if (!section) return;

    const productForm = section.querySelector('product-form');
    if (productForm) productForm.handleErrorMessage();
  }

  renderProductInfo() {
    fetch(`${this.dataset.url}?variant=${this.currentVariant.id}&section_id=${this.dataset.section}`)
      .then((response) => response.text())
      .then((responseText) => {
        const id = `price-${this.dataset.section}`;
        const html = new DOMParser().parseFromString(responseText, 'text/html')
        const destination = document.getElementById(id);
        const source = html.getElementById(id);

        if (source && destination) destination.innerHTML = source.innerHTML;

        const price = document.getElementById(`price-${this.dataset.section}`);

        if (price) price.classList.remove('visibility-hidden');
        this.toggleAddButton(!this.currentVariant.available, window.variantStrings.soldOut);
      });
  }

  toggleAddButton(disable = true, text, modifyClass = true) {
    const productForm = document.getElementById(`product-form-${this.dataset.section}`);
    if (!productForm) return;
    const addButton = productForm.querySelector('[name="add"]');
    const addButtonText = productForm.querySelector('[name="add"] > span');

    if (!addButton) return;

    if (disable) {
      addButton.setAttribute('disabled', 'disabled');
      if (text) addButtonText.textContent = text;
    } else {
      addButton.removeAttribute('disabled');
      addButtonText.textContent = window.variantStrings.addToCart;
    }

    if (!modifyClass) return;
  }

  setUnavailable() {
    const button = document.getElementById(`product-form-${this.dataset.section}`);
    const addButton = button.querySelector('[name="add"]');
    const addButtonText = button.querySelector('[name="add"] > span');
    const price = document.getElementById(`price-${this.dataset.section}`);
    if (!addButton) return;
    addButtonText.textContent = window.variantStrings.unavailable;
    if (price) price.classList.add('visibility-hidden');
  }

  getVariantData() {
    this.variantData = this.variantData || JSON.parse(this.querySelector('[type="application/json"]').textContent);
    return this.variantData;
  }
}

customElements.define('variant-selects', VariantSelects);

 

LitExtension
Shopify Partner
4860 1001 1125

Hi @michaelmorgan,

I checked and it needs to change for JS so this would be a complicated requirement.

I recommend hiring an expert or installing an app for it.

Because it takes a lot of time to change, debug and test, it will be difficult for me to guide you in detail.

Please sympathize with me in this case.

LitExtension - Shopping Cart Migration Expert
Check out our Shopify migration app to migrate your online store to Shopify
script_theory
Shopify Partner
1 0 0

@LitExtension When products have multiple options then this code {{ product.variants[forloop.index0].metafields.color.values }} is not working and print duplicate values