Mechanic is a development and ecommerce automation platform for Shopify. :)
This task populates variant metafields with your desired variant options for use by Online Store 2.0 filtering, taking into account whether or not a variant has inventory available for sale online. It runs when inventory levels are updated, and may also be run manually to scan all variants in your shop.
Runs Occurs whenever an inventory level is updated, Occurs when a user manually triggers the task, and Occurs when a bulk operation is completed. Configuration includes metafield namespace and option names and metafield keys.
This task populates variant metafields with your desired variant options for use by Online Store 2.0 filtering, taking into account whether or not a variant has inventory available for sale online. It runs when inventory levels are updated, and may also be run manually to scan all variants in your shop.
Configure it with a single metafield namespace (e.g. "my_fields") and one or more variant options (e.g. "Size") paired with their respective metafield key (e.g. "size_in_stock").
Important: To use OS 2.0 collection and search filtering, you must configure variant metafield definitions for each metafield key configured in this task. Read Shopify's documenation on adding metafield definitions for more info.
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?)
shopify/inventory_levels/update mechanic/user/trigger mechanic/shopify/bulk_operation
{% assign metafield_namespace = options.metafield_namespace__required | strip %}
{% assign option_names_and_metafield_keys = options.option_names_and_metafield_keys__keyval_required %}
{% assign metafield_keys = option_names_and_metafield_keys | values %}
{% capture metafields_query %}
{% for metafield_key in metafield_keys %}
metafield_{{ metafield_key | md5 }}: metafield(
namespace: {{ metafield_namespace | json }}
key: {{ metafield_key | json }}
) {
id
value
}
{% endfor %}
{% endcapture %}
{% assign variants = array %}
{% if event.topic == "shopify/inventory_levels/update" %}
{% capture query %}
query {
inventoryLevel(id: {{ inventory_level.admin_graphql_api_id | json }}) {
item {
variant {
id
displayName
inventoryPolicy
availableForSale
sellableOnlineQuantity
selectedOptions {
name
value
}
{{ metafields_query }}
}
}
}
}
{% endcapture %}
{% assign result = query | shopify %}
{% assign variants[0] = result.data.inventoryLevel.item.variant %}
{% elsif event.topic == "mechanic/user/trigger" %}
{% capture bulk_operation_query %}
query {
productVariants {
edges {
node {
id
displayName
inventoryPolicy
availableForSale
sellableOnlineQuantity
selectedOptions {
name
value
}
{{ metafields_query }}
}
}
}
}
{% endcapture %}
{% action "shopify" %}
mutation {
bulkOperationRunQuery(
query: {{ bulk_operation_query | json }}
) {
bulkOperation {
id
status
}
userErrors {
field
message
}
}
}
{% endaction %}
{% elsif event.topic == "mechanic/shopify/bulk_operation" %}
{% assign variants = bulkOperation.objects %}
{% endif %}
{% if event.preview %}
{% capture variants_json %}
[
{
"id": "gid://shopify/ProductVariant/1234567890",
"displayName": "Duffel Bag - Pleather / Large",
"inventoryPolicy": "DENY",
"availableForSale": true,
"sellableOnlineQuantity": 1,
"selectedOptions": [
{
"name": "Material",
"value": "Pleather"
},
{
"name": "Size",
"value": "Large"
}
]
}
]
{% endcapture %}
{% assign variants = variants_json | parse_json %}
{% endif %}
{% comment %}
-- save mutation inputs for setting and deleting metafields
{% endcomment %}
{% assign metafields_to_set = array %}
{% assign metafields_to_delete = array %}
{% for variant in variants %}
{% assign is_in_stock = nil %}
{% if variant.availableForSale %}
{% if variant.sellableOnlineQuantity > 0 or variant.inventoryPolicy == "CONTINUE" %}
{% assign is_in_stock = true %}
{% endif %}
{% endif %}
{% for selected_option in variant.selectedOptions %}
{% assign selected_option_name = selected_option.name | downcase %}
{% for keyval in option_names_and_metafield_keys %}
{% assign configured_option_name = keyval[0] | downcase %}
{% if configured_option_name == selected_option_name %}
{% assign set_metafield = nil %}
{% assign metafield_key = keyval[1] %}
{% assign metafield_alias = metafield_key | md5 | prepend: "metafield_" %}
{% assign metafield = variant[metafield_alias] %}
{% if metafield == blank %}
{% if is_in_stock %}
{% assign set_metafield = true %}
{% endif %}
{% elsif is_in_stock %}
{% if metafield.value != selected_option.value %}
{% assign set_metafield = true %}
{% endif %}
{% else %}
{% assign metafield_to_delete = hash %}
{% assign metafield_to_delete["ownerId"] = variant.id %}
{% assign metafield_to_delete["namespace"] = metafield_namespace %}
{% assign metafield_to_delete["key"] = metafield_key %}
{% assign metafields_to_delete = metafields_to_delete | push: metafield_to_delete %}
{% endif %}
{% if set_metafield %}
{% assign metafield_to_set = hash %}
{% assign metafield_to_set["ownerId"] = variant.id %}
{% assign metafield_to_set["namespace"] = metafield_namespace %}
{% assign metafield_to_set["key"] = metafield_key %}
{% assign metafield_to_set["type"] = "single_line_text_field" %}
{% assign metafield_to_set["value"] = selected_option.value | append: "" %}
{% assign metafields_to_set = metafields_to_set | push: metafield_to_set %}
{% endif %}
{% endif %}
{% endfor %}
{% endfor %}
{% endfor %}
{% unless event.topic == "mechanic/shopify/bulk_operation" %}
{% log
total_metafields_being_set: metafields_to_set.size,
total_metafields_being_deleted: metafields_to_delete.size
%}
{% endunless %}
{% comment %}
-- metafields may be set 25 at a time
{% endcomment %}
{% if metafields_to_set != blank %}
{% assign groups_of_metafields_to_set = metafields_to_set | in_groups_of: 25, fill_with: false %}
{% for group_of_metafields_to_set in groups_of_metafields_to_set %}
{% action "shopify" %}
mutation {
metafieldsSet(
metafields: {{ group_of_metafields_to_set | graphql_arguments }}
) {
metafields {
id
namespace
key
type
value
owner {
... on ProductVariant {
id
}
}
}
userErrors {
code
field
message
}
}
}
{% endaction %}
{% endfor %}
{% endif %}
{% comment %}
-- metafields may be deleted in batches of 250
{% endcomment %}
{% if metafields_to_delete != blank %}
{% assign groups_of_metafields_to_delete = metafields_to_delete | in_groups_of: 250, fill_with: false %}
{% for group_of_metafields_to_delete in groups_of_metafields_to_delete %}
{% action "shopify" %}
mutation {
metafieldsDelete(
metafields: {{ group_of_metafields_to_delete | graphql_arguments }}
) {
deletedMetafields {
ownerId
namespace
key
}
userErrors {
field
message
}
}
}
{% endaction %}
{% endfor %}
{% endif %}