2.0 Beta

Smootify 2.0 is in public beta. Your 1.x store keeps working. Move when you want.

What changed

Render a metafield yourself

Write a metafield value with your own code, with the smootify.devMetafield event that fires after Smootify's render, and render a list metafield from smootify.renderedMetafields.

v2.0 beta
Open .md1.x page ↗
On this page
  1. The smootify.devMetafield event
  2. Example: a JSON value
  3. Lists
  4. Where people get stuck
  5. Coming from 1.x

Smootify 2.0 renders every Shopify metafield type by itself, lists, JSON and references included. When a design needs a different output, a script can take over. This page shows the event that hands a single value to your code, and how to render a list yourself.

Note

Check first whether an attribute already gives the output you need: separator for lists, data-path for JSON, [reference] for references. See Metafields on the page and metafield types.

The smootify.devMetafield event

Smootify sends smootify.devMetafield on document right after it has written a metafield into an element. What your listener writes into the element stays: your code has the last word.

  • event.detail is { element, metafield }. element is the element with the metafield attribute; metafield is { namespace, key, type, value, reference, references }, with value as Shopify sends it (a string, JSON for structured types).
  • Weight and volume also carry jsonValue, the value already parsed ({ value, unit }).
  • It fires for every metafield attribute: metafield, variant-metafield, customer-metafield, company-metafield, and the fields of a metaobject.
  • It fires only when the metafield has a value on that product, variant or customer.

It fires for these types only:

  • json, weight, volume;
  • product_reference, variant_reference, collection_reference, page_reference, mixed_reference;
  • the lists list.number_integer, list.number_decimal, list.date, list.date_time, list.dimension, list.volume, list.weight, list.color, list.url, list.rating, list.product_reference, list.variant_reference, list.collection_reference, list.page_reference, list.mixed_reference.

The other types, such as text, numbers, rich text, files, rating and metaobject references, are rendered by Smootify with no event.

The event name has no smootify: prefix, so Smootify.on cannot listen to it: use document.addEventListener. Register the listener in the Head code, or in a push function, so it is there before the first product renders.

Example: a JSON value

A JSON metafield custom.dimensions holds {"width": 60, "depth": 40}. The designer puts metafield="dimensions" on a Text block. Without data-path, Smootify leaves an object as it is, and your code writes it:

document.addEventListener("smootify.devMetafield", (event) => {
  const { element, metafield } = event.detail;
  if (metafield.key !== "dimensions") return;
  const { width, depth } = JSON.parse(metafield.value);
  element.textContent = `${width} × ${depth} cm`;
});

Variant metafields render again at every variant change, and the event fires again each time. Write the listener so it can run many times on the same element.

Lists

What your listener writes into element shows only when the metafield fills one element:

One element on the page

Types
json, weight, volume, the references, and lists of numbers, dates and measures joined into one text.
Your text
Shows: your code has the last word.

One copy per value

Types
Lists of colors, URLs, ratings and references, and the other lists with separator="repeat".
Your text
Does not show.

Render the list from smootify.renderedMetafields instead.

To render a list yourself:

  1. Put an attribute of your own on the element that holds the list, such as data-features, not metafield.
  2. Ask Shopify for the metafield with the metafield_definitions filter, since no [metafield] element asks for it now.
  3. Write the list when smootify.renderedMetafields fires.

smootify.renderedMetafields goes out on document each time Smootify has rendered the metafields of an element. event.detail is { context, attribute, metafields }: context is that element (a smootify-product, a cart-item…), attribute the kind (metafield for a product’s metafields, variant-metafield for its variant’s), and metafields the values Shopify sent.

window.Smootify = window.Smootify || [];
window.Smootify.push((Smootify) => {
  Smootify.addFilter("metafield_definitions", (definitions, { scope }) =>
    scope === "product" ? [...definitions, { namespace: "custom", key: "features" }] : undefined,
  );
});

document.addEventListener("smootify.renderedMetafields", (event) => {
  const { context, attribute, metafields } = event.detail;
  if (attribute !== "metafield" || !(context instanceof Element) || !context.matches("smootify-product")) return;
  const list = context.querySelector("[data-features]");
  const features = metafields?.find((m) => m?.namespace === "custom" && m.key === "features");
  if (!list || !features?.value) return;
  list.replaceChildren(
    ...JSON.parse(features.value).map((text) => {
      const item = document.createElement("li");
      item.textContent = text;
      return item;
    }),
  );
});

The same pattern works for a single value that no attribute shows.

Where people get stuck

Check these first

  • The listener never runs. It was added with Smootify.on: use document.addEventListener. Or the type is one Smootify renders without the event, such as a text or a rating.
  • Nothing changes on a list. The list makes one copy per value, and the event’s element is the template, no longer on the page. Render the list from smootify.renderedMetafields.
  • It works on one product and not on another. The event fires only when that product has a value for the metafield.
  • The metafield never reaches the page. In Shopify, its definition needs Storefront access. Without any element or filter asking for it, Smootify does not request it either.
  • What the script wrote is gone after a variant change. Variant metafields render again at every change and the event fires again: do not stop the listener after its first run.

Coming from 1.x

In 1.x, lists, JSON and references were left to custom code through smootify.devMetafield. 2.0 renders them, and the event still fires for them, after the render: a script that writes a single value keeps working. A script that filled a list element must move to smootify.renderedMetafields, as above. Weight and volume now print the unit symbol (650 g) before the event, so a script that reads the element’s text sees the new format.

    ↑ ↓ to moveEnter to openEsc to close