Mechanic is a development and ecommerce automation platform for Shopify. :)
Run this task to scan all of your customers and their order histories in bulk, copying order and/or product tags to the relevant customer. Optionally, configure a specific set of tags to look for, when scanning. Optionally, choose to remove those tags if a qualifying source can't be found - useful for adding customer tags that expire after ordering!
Runs Occurs when a user manually triggers the task and Occurs when a bulk operation is completed. Configuration includes include order tags, include product tags, only include customers matching this query, only include orders matching this query, only copy these tags, remove those tags if a qualifying source cannot be found, and run daily.
Run this task to scan all of your customers and their order histories in bulk, copying order and/or product tags to the relevant customer. Optionally, configure a specific set of tags to look for, when scanning. Optionally, choose to remove those tags if a qualifying source can't be found - useful for adding customer tags that expire after ordering!
Run this task to scan all of your customers and their order histories in bulk, copying order and/or product tags to the relevant customer. Optionally, configure a specific set of tags to look for, when scanning. Optionally, choose to remove those tags if a qualifying source can't be found.
Both the customer and order query options support Liquid. This means that you can dynamically query for orders, based on things like the current time.
For example, use these options to achieve customer tags that auto-expire a year after the newest qualifying order:
created_at:>={{ "now" | date: "%s" | minus: 31536000 | date: "%Y-%m-%d" }}
Note: the 31536000 value is a quantity of seconds; 31536000 is the number of seconds in a year. To adjust, replace this value with the number of seconds you want to use. For example, 30 days is 2592000 seconds.
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?)
mechanic/user/trigger {% if options.run_daily__boolean %} mechanic/scheduler/daily {% endif %} mechanic/shopify/bulk_operation
{% comment %} Option order: {{ options.include_order_tags__boolean }} {{ options.include_product_tags__boolean }} {{ options.only_include_customers_matching_this_query }} {{ options.only_include_orders_matching_this_query }} {{ options.only_copy_these_tags__array }} {{ options.remove_those_tags_if_a_qualifying_source_cannot_be_found__boolean }} {{ options.run_daily__boolean }} {% endcomment %} {% if options.include_order_tags__boolean == false and options.include_product_tags__boolean == false %} {"error": "Choose at least one of 'Include order tags' and 'Include product tags'. :)"} {% endif %} {% if options.remove_those_tags_if_a_qualifying_source_cannot_be_found__boolean and options.only_copy_these_tags__array == blank %} {"error": "Mechanic can only remove tags it knows about. If you choose 'Remove those tags [...]', you must also fill in 'Only copy these tags'."} {% endif %} {% if event.topic == "mechanic/user/trigger" or event.topic contains "mechanic/scheduler/" %} {% capture bulk_operation_query %} query { customers(query: {{ options.only_include_customers_matching_this_query | json }}) { edges { node { __typename id tags orders(query: {{ options.only_include_orders_matching_this_query | json }}) { edges { node { __typename id {% if options.include_order_tags__boolean %} tags {% endif %} {% if options.include_product_tags__boolean %} lineItems { edges { node { __typename id product { __typename id tags } } } } {% endif %} } } } } } } } {% 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 customer_ids = bulkOperation.objects | where: "__typename", "Customer" | map: "id" %} {% assign tags_available_by_customer_id = hash %} {% if options.include_order_tags__boolean %} {% assign orders = bulkOperation.objects | where: "__typename", "Order" %} {% for order in orders %} {% assign customer = order.__parent %} {% if tags_available_by_customer_id[customer.id] == nil %} {% assign tags_available_by_customer_id[customer.id] = array %} {% endif %} {% assign tags_available_by_customer_id[customer.id] = tags_available_by_customer_id[customer.id] | concat: order.tags %} {% endfor %} {% endif %} {% if options.include_product_tags__boolean %} {% assign lineItems = bulkOperation.objects | where: "__typename", "LineItem" | where: "product" %} {% for lineItem in lineItems %} {% assign product = lineItem.product %} {% assign order = lineItem.__parent %} {% assign customer = order.__parent %} {% if tags_available_by_customer_id[customer.id] == nil %} {% assign tags_available_by_customer_id[customer.id] = array %} {% endif %} {% assign tags_available_by_customer_id[customer.id] = tags_available_by_customer_id[customer.id] | concat: product.tags %} {% endfor %} {% endif %} {% if event.preview %} {% assign preview_tags = "foo,bar,baz" | split: "," %} {% assign customer_ids[0] = "gid://shopify/Customer/1234567890" %} {% assign tags_available_by_customer_id["gid://shopify/Customer/1234567890"] = options.only_copy_these_tags__array | default: preview_tags %} {% assign bulkOperation = hash %} {% assign bulkOperation["objects"] = array %} {% assign bulkOperation["objects"][0] = '{"id":"gid://shopify/Customer/1234567890","tags":""}' | parse_json %} {% endif %} {% for customer_id in customer_ids %} {% assign customer = bulkOperation.objects | where: "id", customer_id | first %} {% assign tags_available = tags_available_by_customer_id[customer_id] | default: array %} {% if options.only_copy_these_tags__array == blank %} {% assign tags_applicable = tags_available %} {% else %} {% assign tags_applicable = array %} {% for whitelisted_tag in options.only_copy_these_tags__array %} {% if tags_available contains whitelisted_tag %} {% assign tags_applicable[tags_applicable.size] = whitelisted_tag %} {% endif %} {% endfor %} {% endif %} {% assign tags_applicable = tags_applicable | sort | uniq %} {% if tags_applicable != empty %} {% assign tags_to_copy = array %} {% for tag in tags_applicable %} {% unless customer.tags contains tag %} {% assign tags_to_copy[tags_to_copy.size] = tag %} {% endunless %} {% endfor %} {% if tags_to_copy == empty %} {% capture log_message %}Customer {{ customer.id }} already has all applicable tags ({{ tags_applicable | join: ", " }}); nothing to do.{% endcapture %} {"log": {{ log_message | json }}} {% else %} {% action "shopify" %} mutation { tagsAdd( id: {{ customer.id | json }} tags: {{ tags_to_copy | json }} ) { userErrors { field message } } } {% endaction %} {% endif %} {% endif %} {% if options.remove_those_tags_if_a_qualifying_source_cannot_be_found__boolean and options.only_copy_these_tags__array != blank %} {% assign tags_to_remove = array %} {% for tag in options.only_copy_these_tags__array %} {% unless tags_applicable contains tag %} {% if customer.tags contains tag %} {% assign tags_to_remove[tags_to_remove.size] = tag %} {% endif %} {% endunless %} {% endfor %} {% if tags_to_remove != empty %} {% action "shopify" %} mutation { tagsRemove( id: {{ customer.id | json }} tags: {{ tags_to_remove | json }} ) { userErrors { field message } } } {% endaction %} {% endif %} {% endif %} {% endfor %} {% endif %}
true