Mechanic is a development and ecommerce automation platform for Shopify. :)
Use this task to automatically switch collections over to an appropriate theme template, when every product in the collection has gone completely out of stock, and to switch them back when inventory arrives.
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 collection template suffix when all products are out of stock, default collection template suffix, run every time an inventory level is updated, run daily, and run hourly.
Use this task to automatically switch collections over to an appropriate theme template, when every product in the collection has gone completely out of stock, and to switch them back when inventory arrives.
This task can be run manually (using the "Run task" button), or be configured to run daily/hourly. If you encounter performance issues when running every time an inventory level is updated, disable this option.
Note: For this task, products which do not track inventory in Shopify will be considered as in stock.
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?)
{% if options.run_every_time_an_inventory_level_is_updated__boolean %}shopify/inventory_levels/update{% endif %} mechanic/user/trigger {% if options.run_daily__boolean %}mechanic/scheduler/daily{% endif %} {% if options.run_hourly__boolean %}mechanic/scheduler/hourly{% endif %} mechanic/shopify/bulk_operation
{% assign out_of_stock_collection_template_suffix = options.collection_template_suffix_when_all_products_are_out_of_stock__required %} {% assign default_collection_template_suffix = options.default_collection_template_suffix %} {% if event.topic contains "shopify/inventory_levels/" %} {% comment %} -- get this product's total inventory, and up to 250 collections {% endcomment %} {% capture query %} query { inventoryItem(id: {{ inventory_level.inventory_item_id | prepend: "gid://shopify/InventoryItem/" | json }}) { variant { product { id totalInventory tracksInventory collections(first: 250) { nodes { id templateSuffix } } } } } } {% endcapture %} {% assign result = query | shopify %} {% if event.preview %} {% capture result_json %} { "data": { "inventoryItem": { "variant": { "product": { "id": "gid://shopify/Product/1234567890", "totalInventory": 0, "tracksInventory": true, "collections": { "nodes": [ { "id": "gid://shopify/Collection/1234567890", "templateSuffix": {{ default_collection_template_suffix | json }} } ] } } } } } } {% endcapture %} {% assign result = result_json | parse_json %} {% endif %} {% assign product = result.data.inventoryItem.variant.product %} {% assign collections = product.collections.nodes %} {% for collection in collections %} {% assign has_default_template = nil %} {% assign has_out_of_stock_template = nil %} {% assign has_a_product_in_stock = nil %} {% assign current_template_suffix = collection.templateSuffix %} {% comment %} -- Shopify stores this as *either* an empty string or as nil. Mechanic auto-nils empty strings for task options, so we coerce blanks to nils here. {% endcomment %} {% if current_template_suffix == blank %} {% assign current_template_suffix = nil %} {% endif %} {% if current_template_suffix == default_collection_template_suffix %} {% assign has_default_template = true %} {% elsif current_template_suffix == out_of_stock_collection_template_suffix %} {% assign has_out_of_stock_template = true %} {% endif %} {% comment %} -- if the product's stock status matches the paired collection template, then stop processing that collection -- NOTE: another product might cause the collection to change templates, but that should be handled in an inventory level event for that product {% endcomment %} {% if product.totalInventory <= 0 and product.tracksInventory %} {% if has_out_of_stock_template %} {% continue %} {% endif %} {% elsif has_default_template %} {% continue %} {% endif %} {% comment %} -- query collection for up to 25K products, getting inventory of each -- break the query loop early when at least one product is in stock and the collection has the out of stock template {% endcomment %} {% assign cursor = nil %} {% for n in (1..100) %} {% capture query %} query { collection(id: {{ collection.id | json }}) { products( first: 250 after: {{ cursor | json }} ) { pageInfo { hasNextPage endCursor } nodes { id totalInventory tracksInventory } } } } {% endcapture %} {% assign result = query | shopify %} {% if event.preview %} {% capture result_json %} { "data": { "collection": { "products": { "nodes": [ { "id": "gid://shopify/Product/1234567890", "totalInventory": 0, "tracksInventory": true } ] } } } } {% endcapture %} {% assign result = result_json | parse_json %} {% endif %} {% for product in result.data.collection.products.nodes %} {% if product.totalInventory > 0 or product.tracksInventory == false %} {% assign has_a_product_in_stock = true %} {% break %} {% endif %} {% endfor %} {% if has_a_product_in_stock %} {% break %} {% endif %} {% if result.data.collection.products.pageInfo.hasNextPage %} {% assign cursor = result.data.collection.products.pageInfo.endCursor %} {% else %} {% break %} {% endif %} {% endfor %} {% if has_a_product_in_stock %} {% unless has_default_template %} {% action "shopify" %} mutation { collectionUpdate( input: { id: {{ collection.id | json }} templateSuffix: {{ default_collection_template_suffix | json }} } ) { collection { id title templateSuffix } userErrors { field message } } } {% endaction %} {% endunless %} {% else %} {% unless has_out_of_stock_template %} {% action "shopify" %} mutation { collectionUpdate( input: { id: {{ collection.id | json }} templateSuffix: {{ out_of_stock_collection_template_suffix | json }} } ) { collection { id title templateSuffix } userErrors { field message } } } {% endaction %} {% endunless %} {% endif %} {% endfor %} {% elsif event.topic == "mechanic/user/trigger" or event.topic contains "mechanic/scheduler/" %} {% capture bulk_operation_query %} query { collections { edges { node { __typename id templateSuffix products { edges { node { __typename id totalInventory tracksInventory } } } } } } } {% endcapture %} {% action "shopify" %} mutation { bulkOperationRunQuery( query: {{ bulk_operation_query | json }} ) { bulkOperation { id status } userErrors { field message } } } {% endaction %} {% elsif event.topic == "mechanic/shopify/bulk_operation" %} {% if event.preview %} {% capture jsonl_string %} {"__typename":"Collection","id":"gid://shopify/Collection/1234567890","templateSuffix":{{ default_collection_template_suffix | json }}} {"__typename":"Product","id":"gid://shopify/Product/1234567890","totalInventory":0,"__parentId":"gid://shopify/Collection/1234567890"} {"__typename":"Product","id":"gid://shopify/Product/2345678901","totalInventory":0,"__parentId":"gid://shopify/Collection/1234567890"} {% endcapture %} {% assign bulkOperation = hash %} {% assign bulkOperation["objects"] = jsonl_string | parse_jsonl %} {% endif %} {% assign collections = bulkOperation.objects | where: "__typename", "Collection" %} {% assign products = bulkOperation.objects | where: "__typename", "Product" %} {% for collection in collections %} {% assign has_default_template = nil %} {% assign has_out_of_stock_template = nil %} {% assign has_a_product_in_stock = nil %} {% assign current_template_suffix = collection.templateSuffix %} {% comment %} -- Shopify stores this as *either* an empty string or as nil. Mechanic auto-nils empty strings for task options, so we coerce blanks to nils here. {% endcomment %} {% if current_template_suffix == blank %} {% assign current_template_suffix = nil %} {% endif %} {% if current_template_suffix == default_collection_template_suffix %} {% assign has_default_template = true %} {% elsif current_template_suffix == out_of_stock_collection_template_suffix %} {% assign has_out_of_stock_template = true %} {% endif %} {% assign collection_products = products | where: "__parentId", collection.id %} {% comment %} -- break the products loop early when at least one product is in stock {% endcomment %} {% for product in collection_products %} {% if product.totalInventory > 0 or product.tracksInventory == false %} {% assign has_a_product_in_stock = true %} {% break %} {% endif %} {% endfor %} {% if has_a_product_in_stock %} {% unless has_default_template %} {% action "shopify" %} mutation { collectionUpdate( input: { id: {{ collection.id | json }} templateSuffix: {{ default_collection_template_suffix | json }} } ) { collection { id title templateSuffix } userErrors { field message } } } {% endaction %} {% endunless %} {% else %} {% unless has_out_of_stock_template %} {% action "shopify" %} mutation { collectionUpdate( input: { id: {{ collection.id | json }} templateSuffix: {{ out_of_stock_collection_template_suffix | json }} } ) { collection { id title templateSuffix } userErrors { field message } } } {% endaction %} {% endunless %} {% endif %} {% endfor %} {% endif %}
out-of-stock
true