Metafields - So much promise, such a hard fall from grace

The new metafield offering from Shopify was so exciting when I read up about it. It showed so much promise. Allowing merchants to add unlimited data to improve the experience for my customers. GREAT! You can group them by namespace? FANTASTIC! I can not only give my customers the data they need, but I can decide where this data is shown on my website? Can Shopify do any wrong..?!

AND THEN…

Shopify docs tell me that I can’t loop over the metafields..? https://shopify.dev/api/liquid/objects#metafield-access-metafields

How ridiculous is this? This practically makes the metafield feature useless. For a shop like mine where I have unlimited product specifications (to give a few examples: weights, resolution, size, compatibility, compliance, heat output … the list goes on into the 100s), I have to hard code direct access with if statements to understand which metafields apply to which products? What if I add a new spec? Oh, just hard code some more direct access if statements.

No. Why did you build this stupid brick wall? Can’t explain how disappointed I am with this stupid restriction.

You can iterate over a metafields value when it’s a JSON type metafield.

Outputting a hash using first and last properties&filters , similar to line-item-properties.

https://shopify.dev/api/liquid/objects#metafield-accessing-metafields-of-type-json

Note: this does not apply to the json filter.

Metafields are not a hammer for every nail, it’s just another feature to facilitate extensibility not a magical panacea for every woe out of the box.

Ultimately it’s a bit historical since there weren’t always private metafields which makes looping and outputting such a thing in themes very bad idea for accidental data leaking. And it’s a key/hash based system, getting into the specifics of why such things are not always iterable would require diving into computer science concepts.

Instead of fixating on a reasonable limitation due to unfounded expectations, focus on the goal and deconstructing the real need as an information architecture problem not an unmaintainable {%if%} problem:

Ideally you set it up so only need to just output the metafield if it has no value the content is empty and html simply doesn’t display because it has no height , or javascript checks for lack of content in the situation with stuff like padding/borders,etc.

No. Why did you build this stupid brick wall? Can’t explain how disappointed I am with this stupid restriction.

Even if metafields were iterable that still wouldn’t free you of having to code the design/content logic as metafield types just contain data , not theme html or output logic. Even with the metafield_tag filter based on the context such as displaying a table versus an infographic ,image, or a video, linking to a pdf etc etc you can still have tons of conditional checks when dealing with large datasets.

The metafield data has to be coming from somewhere before import or data entry.

For a large dataset per product an alternative is to structure the entire spec data per product to be imported as a JSON metafield to have a custom object structure that has iterable properties.

Hypothetically should the display of specifications end up needing to be done in liquid with only {% if %} , or other conditional tags such as {% case %} , then what ever system is being used to track those product specs that is used to create&import metafields data should also then be utilized to generate the liquid code instead of hand coding.

Such as an excel spreadsheet using formula|macro|script to generate the content code for a liquid templates snippet. Or a small middleware app reading product data, or even an automation app such as usemechanic scripting.

But go a bit higher and look at what other features are available for controlling data display in bulk: tags and alternate templates. Also for advanced development the section rendering api.

  • Tags - If a product has specific sets of characteristics that are not in the variant-options this is typically indicated with tags.
  • Alternate templates - If sets of products have similar specific sets of characteristics that are not in the variant-options the display of that data can be controlled with alternate templates.

For tags it’s not the data itself, just the indication of that category of data. i.e. tag == __specification-resolution.

Metafield have hash array access so you can just pass a value from a variable to access different parts.

{% for tag in product.tags %}
 {% if tag contains '__specification' %}
 {% assign spec_category_key  = 'specs' %}
 {% assign specification = tag | split:'-' | last %}
  {% product.metafield[spec_category_key][specification]
 {% endif %}
{% endfor %}

Below is some code to can try in the dev docs 'Direct Access" sections interactive code box with the information directions metafield it uses:

{%  assign category = "information" %}
{%  assign tag = "directions" %}
{%  comment %}SBN = square bracket [ ] notation ~ array hash accessor{%  endcomment %}
Value using SBN: {{ product.metafields[category][tag].value }}
Value using map filter: {{ product.metafields[category] | map:tag }}

For the JSON codebox:

The JSON : {{ product.metafields.information.burn_temperature | strip_newlines }}

{%-  assign spec_category = 'information' -%}
{%-  assign spec = 'burn_temperature' -%}
{%-  assign spec_detail = 'temperature' -%}

{%  comment %}SBN = square bracket [ ] notation ~ array hash accessor{%  endcomment %}
JSON using SBN for namespace-key value: {{ product.metafields[spec_category][spec]  | strip_newlines }}

JSON using SBN with a property keyname : {{ product.metafields[spec_category][spec].value.first.first }}
JSON using SBN for a property value : {{ product.metafields[spec_category][spec].value[spec_detail] }}

JSON first filters to get the property keyname : {{ product.metafields.information.burn_temperature.value | first | first }}
JSON first last filters to get the property value : {{ product.metafields.information.burn_temperature.value | first | last }}

JSON using SBN with string to access the property value {{ product.metafields.information.burn_temperature.value['temperature'] }}

The JSON with map filter : {{ product.metafields.information.burn_temperature.value | map:"unit" }}

Good Hunting!