Sync a Product List Metafield Of Products That Share Another Common Metafield Value, with Mechanic.

Mechanic is a development and ecommerce automation platform for Shopify. :)

Sync a Product List Metafield Of Products That Share Another Common Metafield Value

This task runs across all active products on your store and syncs a list type product reference metafield to contain all products with a matching common single metafield value (the 'group by' meatfield).

Runs Occurs every day at midnight (in local time), Occurs when a user manually triggers the task, and Occurs when a bulk operation is completed. Configuration includes group by metafield namespace, group by metafield key, product list metafield namespace, product list metafield key, remove out of stock products, and include current product.

15-day free trial – unlimited tasks

Documentation

This task runs across all active products on your store and syncs a list type product reference metafield to contain all products with a matching common single metafield value (the 'group by' meatfield).

Optionally you can check the 'Remove out of stock products' to have the task remove out of stock products from the product list field on all shared products. * Note this option is not compatible with products that do not have tracked inventory.

Example use cases for this task include showing color variations of a product or showing a related products / shop the look section on a product page.

As a working example if you have the following products on your store:
- Cool Black T-Shirt

  • Cool Gray T-Shirt

  • Cool White T-Shirt

And then you set the 'group by' metafield value on all three to 'Cool T-Shirt', after this task runs on 'Cool Black T-Shirt' it will have the Gray and White products in the product list metafield and so on.

If you have the 'Include current product' option checked the Black T-Shirt itself will also be included (useful if you want the product list field to stay the same across products when simulating variant options).

Developer details

Mechanic is designed to benefit everybody: merchants, customers, developers, agencies, Shopifolks, everybody.

That’s why we make it easy to configure automation without code, why we make it easy to tweak the underlying code once tasks are installed, and why we publish it all here for everyone to learn from.

(By the way, have you seen our documentation? Have you joined the Slack community?)

Open source
View on GitHub to contribute to this task
Subscriptions
mechanic/scheduler/daily
mechanic/user/trigger
mechanic/shopify/bulk_operation
Tasks use subscriptions to sign up for specific kinds of events. Learn more
Options
group by metafield namespace (required) , group by metafield key (required) , product list metafield namespace (required) , product list metafield key (required) , remove out of stock products (boolean) , include current product (boolean)
Code
{% comment %}Set up the task options{% endcomment %}
{% assign group_by_namespace = options.group_by_metafield_namespace__required %}
{% assign group_by_key = options.group_by_metafield_key__required %}
{% assign product_list_namespace = options.product_list_metafield_namespace__required %}
{% assign product_list_key = options.product_list_metafield_key__required %}
{% assign remove_out_of_stock = options.remove_out_of_stock_products__boolean %}
{% assign include_current_product = options.include_current_product__boolean %}

{% comment %}Run the bulk GraphQL query{% endcomment %}
{% if event.topic == "mechanic/user/trigger" or event.topic == "mechanic/scheduler/daily" %}
  {% capture bulk_operation_query %}
    query {
      products(query: "status:ACTIVE{% if remove_out_of_stock %} inventory_total:>0{% endif %}") {
        edges {
          node {
            __typename
            id
            title
            group: metafield(
                namespace: {{ group_by_namespace | json }}
                key: {{ group_by_key | json }}
            ) {
                value
            }
            product_list: metafield(
                namespace: {{ product_list_namespace | json }}
                key: {{ product_list_key | json }}
            ) {
                value
            }
          }
        }
      }
    }
  {% endcapture %}
  {% action "shopify" %}
    mutation {
      bulkOperationRunQuery(
        query: {{ bulk_operation_query | json }}
      ) {
        bulkOperation {
          id
          status
        }
        userErrors {
          field
          message
        }
      }
    }
  {% endaction %}
{% elsif event.topic == "mechanic/shopify/bulk_operation" %}
  {% comment %}Preview data for debugging{% endcomment %}
  {% if event.preview %}
    {% capture jsonl_string %}
      {"__typename":"Product","id":"gid:\/\/shopify\/Product\/7819883282585","title":"Sample Product 1","group":{"id":"gid:\/\/shopify\/Metafield\/39837328081049","value":"Converse"},"product_list":null}
{"__typename":"Product","id":"gid:\/\/shopify\/Product\/7819883380889","title":"Sample Product 2","group":{"value":"Converse"},"product_list":{"value":"[\"gid:\/\/shopify\/Product\/7819883282585\",\"gid:\/\/shopify\/Product\/7819883380889\",\"gid:\/\/shopify\/Product\/7819883413657\"]"}}
{"__typename":"Product","id":"gid:\/\/shopify\/Product\/7819883413657","title":"Sample Product 3","group":{"value":"Converse"},"product_list":null}
    {% endcapture %}
    {% assign bulkOperation = hash %}
    {% assign bulkOperation["objects"] = jsonl_string | parse_jsonl %}
  {% endif %}

  {% comment %}Build a hash (object) keyed by unique values from the group by field, each element is an array of product ids with a matching group by value{% endcomment %}
  {% assign products_to_process = bulkOperation.objects %}
  {% assign products_groups = hash %}
  {% for product in products_to_process %}
    {% if product.group.value %}
      {% unless products_groups[product.group.value] %}
        {% assign products_groups[product.group.value] = array %}
      {% endunless %}
      {% assign products_groups[product.group.value] = products_groups[product.group.value] | push: product.id %}
    {% endif %}
  {% endfor %}

  {% comment %}
    Procees all products
  {% endcomment %}
  {% for current_product in products_to_process %}
    {% if current_product.group.value %}
      {% assign product_list = products_groups[current_product.group.value] %}
      
      {% unless include_current_product %}
        {% comment %}
          The array we built will contain the current product too so unless a user selects the 'Include Current Product' option we rebuild it without the current product in (there's no easy function for removing an item from an array in liquid/Mechanic)
        {% endcomment %}
        {% assign product_list_less_current = array %}
        {% for product_list_item in products_groups[current_product.group.value] %}
          {% unless product_list_item == current_product.id %}
            {% assign product_list_less_current = product_list_less_current | push: product_list_item %}
          {% endunless %}
        {% endfor %}
        {% assign product_list = product_list_less_current %}
      {% endunless %}

      {% comment %}
        Check if the product list metafield value is already correct and update it if not
      {% endcomment %}
      {% assign product_list_json = product_list | json  %}
      {% if current_product.product_list.value != product_list_json %}
        {% action "shopify" %}
          mutation {
            metafieldsSet(
              metafields: [{
                ownerId: {{ current_product.id | json }},
                namespace: {{ product_list_namespace | json }},
                key: {{ product_list_key | json }},
                value: {{ product_list | json | json }},
                type: "list.product_reference"
              }]
            ) {
              metafields {
                namespace
                key
                value
              }
              userErrors {
                code
                field
                message
              }
            }
          }
        {% endaction %}
        {% log message: "Updated product:", details: current_product.title %}
      {% else %}
        {% log message: "Metafield values match, skipped updating product:", details: current_product.title %}
      {% endif %}
    {% endif %}
  {% endfor %}
{% endif %}
Task code is written in Mechanic Liquid, an extension of open-source Liquid enhanced for automation. Learn more
Defaults
Group by metafield namespace
custom
Group by metafield key
product_group
Product list metafield namespace
custom
Product list metafield key
product_list
Include current product
true