Re: Display product variants metafields

Solved

How can I display dynamic product variants metafields on a product page?

ValTodorov
Tourist
7 0 0

In the same way as the product variants SKUs can be displayed, I'd like to display our product variants metafield called "material". It's stored in variant.metafields.specs.material. How can I achieve this?

 

I was following https://help.shopify.com/en/themes/customization/products/features/show-sku-numbers

 

{% if variant.metafields.specs.material != blank %}
<p>Material: {{ variant.metafields.specs.material }}</p>
{% endif %}

This displays the metafield. But it's static, not dynamic like the SKU. When you select variant options (sizes and colors) the SKU changes. The "material" does not. Only if you reload the product page with the variant in the URL, only than the metafield data changes.

 

 

Here's the code for the SKU that works:

 

{% if variant.sku != blank and section.settings.display_sku %}
<p class="sku">SKU:  <span itemprop="sku">{{ variant.sku }}</span></p>
{% endif %}

 

I assume the issue is in the selectCallback function in sections.js.liquid. There I see:

 

$('.sku span', $product).text(variant.sku);

So by analogy I added:

 

 

$('.material span', $product).text(variant.metafields.specs.material);

 

This broke the functionality of the product page and the variants select elements disappeared.

 

Any advice or suggestions?

 

Thanks,

Val

 

 

 

Accepted Solution (1)
Mircea_Piturca
Shopify Partner
1548 44 347

This is an accepted solution.

Hi Val,

 

Jason pretty much explain the way to do it.

You need to:

1. Store the variant data in a JavaScript variable.

Can be something like this (not tested):

 

{% capture 'meta_data' %}
{% for variant in product.variants %}
  {{ variant.sku | json }}: {{ variant.metafields.specs.material | json }}
  {% unless forloop.last %},{% endunless %}
{% endfor %}
{% endcapture %}

<script>
  var metaData = { {{ meta_data }} }
</script>

 

2. On selectCallback pull data from that metaData object based on the variant SKU and display it in your page.

selectCallback = function(variant, selector) {
  // ... your default selectCallback code here
  var material = metaData[variant.sku];
}

Hope it makes sense.  

 

 

Finally—Add variant descriptions to your products

View solution in original post

Replies 22 (22)

Jason
Shopify Partner
11206 226 2314

@ValTodorov wrote:

...This displays the metafield. But it's static, not dynamic like the SKU. When you select variant options (sizes and colors) the SKU changes. The "material" does not. Only if you reload the product page with the variant in the URL, only than the metafield data changes...

 


You're on the right track.

 

When a variant is picked on the front end - using whatever UI is in place - there'll be JavaScript that fires a function. That function will handle the changing of price and sku data.

 

For your metafield to also be shown you'll need to:

  1. output all the metafields somewhere. I generally push them into the existing product object if that theme uses one, or just create a shiny new object for just those variant metafields
  2. tap into the existing function that changes the price, and add code to also do something with your metafield since it now lives in some global JS object. You could optionally choose to add a new event vs adjusting the existing function but this will come down to code preference.
★ I jump on these forums in my free time to help and share some insights. Not looking to be hired, and not looking for work. http://freakdesign.com.au ★
ValTodorov
Tourist
7 0 0

Jason, thanks for the tips. As you wrote "push them into the existing product object", I tried to add

$('.foo', $product).text(variant.metafields.specs.material);

in selectCallback after

selectCallback = function(variant, selector) {
  var $product = $('.product-' + selector.product.id);
  var $notify_form = $('.notify-form-' + selector.product.id);
  var $productForm = $('.product_form, .shopify-product-form', $product);
  var variantInventory = $productForm.data('variant-inventory');
    if (variant) {
    if (variantInventory) {
      variantInventory.forEach(function(v){
        if (v.id === variant.id) {
          variant.inventory_quantity = v.inventory_quantity;
          variant.inventory_management = v.inventory_management;
          variant.inventory_policy = v.inventory_policy;
        }
      });
    }

    $('.sku span', $product).text(variant.sku);

It complains

TypeError: variant.metafields is undefined

But it doesn't seem to complain about variant.sku

 

Your thoughts?

Mircea_Piturca
Shopify Partner
1548 44 347

This is an accepted solution.

Hi Val,

 

Jason pretty much explain the way to do it.

You need to:

1. Store the variant data in a JavaScript variable.

Can be something like this (not tested):

 

{% capture 'meta_data' %}
{% for variant in product.variants %}
  {{ variant.sku | json }}: {{ variant.metafields.specs.material | json }}
  {% unless forloop.last %},{% endunless %}
{% endfor %}
{% endcapture %}

<script>
  var metaData = { {{ meta_data }} }
</script>

 

2. On selectCallback pull data from that metaData object based on the variant SKU and display it in your page.

selectCallback = function(variant, selector) {
  // ... your default selectCallback code here
  var material = metaData[variant.sku];
}

Hope it makes sense.  

 

 

Finally—Add variant descriptions to your products
ValTodorov
Tourist
7 0 0

Thanks to Mircea, I was able to make it work.

 

Capturing the meta data in product-template.liquid worked exactly as described by him.

 

Then in the selectCallback function in sections.js.liquid I had to add:

$('.material span', $product).text(metaData[variant.sku]);

Then back in product-template.liquid I could display the meta data in the same way as the SKU:

{% if variant.sku != blank and section.settings.display_sku %}
<p class="sku">SKU: <span itemprop="sku">{{ variant.sku }}</span></p>
<p class="material">Material: <span itemprop="material">{{ variant.sku }}</span></p>
{% endif %}

By the way, the theme I'm working with is Turbo Portland.

 

Thanks both to Jason and Mircea for the tips.

platformuser
Visitor
2 0 1

Thanks for sharing your code here, this solution worked great for me. (also using a Turbo theme). One issue i'm trying to sort out is some variants of a product do not have data for a metafield (e.g. I'm using this to display backorder Shipping dates). Do you have any pointers on how i could modify this to not display anything for products that have data in the metafield?  Since variant.sku is the filter all variants load the code to display the metafield data. 

 

In my case it is something like this in the product template: 

 

{% capture 'meta_data' %}
  {% for variant in product.variants %}
    {{ variant.sku | json }}: {{ variant.metafields.my_fields.delivery_month | json }}
    {% unless forloop.last %},{% endunless %}
  {% endfor %}
{% endcapture %}

<script>
  var metaData = { {{ meta_data }} }
</script>  
                    
{% if variant.sku != blank %}
  <p class="backorder">Ships by: <span itemprop="backorder">{{ variant.sku }}</span></p>
{% endif %}

 

 

and then using this in my sections.js.liquid

 

    $('.backorder span', $product).text(metaData[variant.sku]);
aaronr
Visitor
2 0 0

I'm at that exact spot too - I'm using variant fields to show a 'back in stock' message when the person clicks on the variant swatch.

i have it working well when all variations have data in the field but when one doesn't, it keeps showing the data from the last click.

My one thought is in the JS i'm using to have a 'if is null' kind of statement, but i can't get it working.

Here's my code:

     {%- if product.metafields.product.stock_info != blank -%} //This tells it to use the main Product field if it exists and ignore variant fields
        <div class="stock-info">{{ product.metafields.product.stock_info }}</div>
      {%- else -%}
      <div class="vstock-info" style="display:none;"></div> //This is the main block to show the info, its hidden first, then turned to 'block' when activated.
          {% capture meta_data %}
          	{% for variant in product.variants %}
                {%- if variant.metafields.variant.stock_date != blank -%}
                  	{{ variant.id}}:{{variant.metafields.variant.stock_date | json}}
              	{%- endif -%}
    		{% unless forloop.last %},{% endunless %}
          	{% endfor %}
          {% endcapture %}
    
      <script>
        const currentVariantId = {{ product.selected_variant.id }};  // get the currently selected before variant is changed. 
        const metaData = { {{ meta_data }} };
        const shippingInfo = (id) => {
         var selector = document.querySelector('.vstock-info');
          if (metaData[id]) { 
            // <----I think here is where we need code - like a 'if there is no data for the 
           //"variant.metafields.variant.stock_date" then the style selector should go to display:none
           //like: if(metaData[variant.metafields.variant.stock_date] != blank)
           selector.style.display = 'block'
           selector.innerHTML = metaData[id];
          } 
        };
        shippingInfo(currentVariantId);
      </script> 

          {%- endif -%}
aaronr
Visitor
2 0 0

Found the solution to hiding it when the variant has no data. I Just added to the JS code :

      <script>
        const currentVariantId = {{ product.selected_or_first_available_variant.id }};  // get the currently selected before variant is changed. 
        const metaData = { {{ meta_data }} };
        const shippingInfo = (id) => {
         var selector = document.querySelector('.vstock-info');   
          if (metaData[id]) {           
           selector.style.display = 'block'                      
           selector.innerHTML = metaData[id];
          } else {       //Added this and the 3 lines below
           selector.style.display = 'none'                      
           selector.innerHTML = metaData[id];
          }
        };
        shippingInfo(currentVariantId);
      </script>
charlied_mc
Visitor
2 0 0

I had two different fields I wanted to display - I copied code from an old developer so not sure if this was the best way to do it, but here is my code:

The place where I wanted the metadata fields displayed:

<div id="casecount" class="product-detail">  </div>
<div id="unitprice" class="product-detail">  </div>

Underneath the variant selector (<option> tag) I put this in. I guessed on the formatting to create an array, but it worked as expected:

{% capture 'meta_data_set' %}
{% for variant in product.variants %}
   {{ variant.sku | json }}: { 	"unit_price": {{ variant.metafields.my_fields.unit_price | json }}, 
            					"case_count": {{ variant.metafields.my_fields.case_count | json }}
            				}
   {% unless forloop.last %},{% endunless %}
{% endfor %}
{% endcapture %}

 Then in the selectCallback function I used this code:

var metaDataSet = { {{ meta_data_set }} }

$("#unitprice").html('<span>Unit Price: '+ metaDataSet[variant.sku]["unit_price"] +'</span>');   
$("#casecount").html('<span>Case Count: '+ metaDataSet[variant.sku]["case_count"] +'</span>');  

 

MyLUCA
Excursionist
18 0 5

Do you think something like that can be put into a custom liquid code inside the theme editor?
I just want to display the content of a variant metafield. 

my_fields.variant_description

gurmeetshergill
Visitor
3 0 0

Hi Mircea

I have checked this code module, it helps me to display variant values where i wanted to display. Because there is a for loop, it displaying all the key_values of all variants. 

Can you please help me to display single key_value at a time. So, when i switch to another variant then metafields or key_value also change immediately.


Here you can see my requirement, i have posted:
https://community.shopify.com/c/Technical-Q-A/Update-metafields-value-by-change-variant/m-p/658958/h...

Mike4502
Tourist
6 0 2

Hey Temitope! I've tried to apply this kind of code into my snippet which i am calling, unfortunately i have to reload my page to see the variant i have changed.

 

The only modification i've made is the key and namespace of the metafield variant:

 

<p class="variant_shipping_info" style="display: none;"></p>

{% capture 'meta_data' %}
{% for variant in product.variants %}
{{variant.id}}:{{ variant.metafields.global.additionalinfo | json }}{% unless forloop.last %},{% endunless %}
  {% endfor %}
  {% endcapture %}

<script>
  const currentVariantId = {{ product.selected_or_first_available_variant.id }};  // get the currently selected before variant is changed. 
  const metaData = { {{ meta_data }} };
  
  const shippingInfo = (id) => {
   var selector = document.querySelector('.variant_shipping_info');
    if (metaData[id]) {
     selector.style.display = 'block' 
     selector.innerHTML = metaData[id];
    } 
  }
  shippingInfo(currentVariantId);
  
// When the variant is changed, get the id and call the function. :)
  document.addEventListener('variant:changed', function(event) { 
    var variant = event.detail.variant; // Gives you access to the whole variant details
    var id = variant.id 
     shippingInfo(id);
  });
  
</script> 

What am i missing? what other things i have to change to relate to my theme? because the value doesn't change instantly...

 

Thank you!

mmeyer
Shopify Partner
14 0 9

I'm having the same trouble with the variant selection callback script. No problem getting the metafields I want showing on first load, but then I have to hit refresh to see the metadata update after changing variants.

Did you figure this out?

“The smaller your reality, the more convinced you are that you know everything.” ― Thomas Campbell
Mike4502
Tourist
6 0 2

I gave up and had to pay for a dev to fix it 😞

mmeyer
Shopify Partner
14 0 9

Thanks for the reply, Mike. Bummer! Glad you eventually got it sorted one way or another though.

I eventually got Temitope's script to work for me. Mine was a little more involved because I had a large array of metafields I wanted to display in a specs chart, per variant. In the end, I combined all specs fields from my source application (netsuite) into a single metafield in Shopify. Then it was plug and play with his script.

“The smaller your reality, the more convinced you are that you know everything.” ― Thomas Campbell
DeanGWard
Tourist
5 0 3

Can anyone recommend a dev that could do this for me?
I can get the meta fields displaying on the initial product page, but would also like it to change with each variant.

https://www.willowbay.co.uk/products/birlea-balmoral-fabric-bed-grey-velvet

 

 

Alan15
Shopify Partner
148 27 72

I got this to work for the debut theme, if it's any help to you. The details are on this post:

https://community.shopify.com/c/Technical-Q-A/Help-with-Metafield-descriptions-for-variants/m-p/1003...

Need more help? Contact me here
NMaskey
Shopify Partner
15 0 4

Thank you! This worked greatly.

ErSanjay
Shopify Partner
321 20 47

@NMaskey  which solution work for you ?

Business Owner & Shopify Plus, Shopify app , Shopify Consultant - Full Stack Sofware Engineer
Warm regards,
Er Sanjay

If you find yourself in need of assistance with your store, don't hesitate to reach out! Feel free to send me a direct message, and I'll do my best to help you out.
robin_sandhu
Tourist
8 0 0

can u share code for future visitors thanks

OmarBakir
Visitor
1 0 0

Hi Jason,

 

I'm currently having the same issue. I would like to display variant metafields dynamically on the product page under the dimensions tab. I'm currently Kitting bed SKU's with different size variants and would like the product and package dimensions to change dynamically when variant is selected.

I'm using an app Excelify to import metafield data

Link to store: https://www.boisetcuir.com/

Link to product page: https://www.boisetcuir.com/collections/beds/products/avalon-series-king-bed-frame

 

bed 2.JPGbed 1.JPG

Much appreciated!

 

markatia
Visitor
3 0 0

I am actually having an issue creating an if logic for the product variant metafields

{% if variant.metafields.variant.shade != blank %}
<p>Hex: {{ variant.metafields.variant.shade }}</p>
{% endif %}

ErSanjay
Shopify Partner
321 20 47

@ValTodorov  @NMaskey @markatia   try this solutions.

 

 

  {% assign description = current_variant.metafields.custom.ingredients1_title%}
{% assign key =  current_variant.sku  %}
{% assign description = description[key] %}
<h3> {{description }}</h3>
Business Owner & Shopify Plus, Shopify app , Shopify Consultant - Full Stack Sofware Engineer
Warm regards,
Er Sanjay

If you find yourself in need of assistance with your store, don't hesitate to reach out! Feel free to send me a direct message, and I'll do my best to help you out.