Mechanic is a development and ecommerce automation platform for Shopify. :)
Configure this task with search terms that describe certain products, and this task will apply the tags of your choice to every customer who purchases a matching product or product variant. Run this task manually to tag all customers who have a qualifying order already on file.
Runs Occurs whenever an order is paid, Occurs when a user manually triggers the task, and Occurs when a bulk operation is completed. Configuration includes search query, search for, customer tags to apply, and test mode.
Configure this task with search terms that describe certain products, and this task will apply the tags of your choice to every customer who purchases a matching product or product variant. Run this task manually to tag all customers who have a qualifying order already on file.
This task auto-tags customers who have paid orders on file for products or product variants that match the search query you add.
Sample searches:
sku:ABC123tag:holidayproduct_type:"Gift Card"title:"Short sleeve t-shirt"To ensure expected results, use this task with test mode enabled, before disabling test mode.
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/orders/paid mechanic/user/trigger mechanic/shopify/bulk_operation
{% assign search_query = options.search_query__required %}
{% assign search_for = options.search_for__choice_o1_products_o2_variants_required %}
{% assign customer_tags_to_apply = options.customer_tags_to_apply__required_array %}
{% assign test_mode = options.test_mode__boolean %}
{% assign cursor = nil %}
{% assign qualifier_resource_ids = array %}
{% assign qualifier_resource_summaries = array %}
{% assign jobs = array %}
{% for n in (1..100) %}
  {% capture query %}
    query {
      {% if search_for == "products" %}
        resources: products(
      {% else %}
        resources: productVariants(
      {% endif %}
        first: 250
        after: {{ cursor | json }}
        query: {{ search_query | json }}
      ) {
        pageInfo {
          hasNextPage
          endCursor
        }
        nodes {
          id
          legacyResourceId
          {% if search_for == "products" %}
            displayName: title
          {% else %}
            displayName
          {% endif %}
        }
      }
    }
  {% endcapture %}
  {% assign result = query | shopify %}
  {% if event.preview %}
    {% capture result_json %}
      {
        "data": {
          "resources": {
            "nodes": [
              {
                "id": "gid://shopify/Product/1234567890",
                "displayName": "ACME Widget",
                "legacyResourceId": "1234567890"
              }
            ]
          }
        }
      }
    {% endcapture %}
    {% assign result = result_json | parse_json %}
  {% endif %}
  {% log qualifier_resources: result.data.resources.nodes %}
  {% assign qualifier_resource_ids
    = result.data.resources.nodes
    | map: "legacyResourceId"
    | concat: qualifier_resource_ids
  %}
  {% if result.data.resources.pageInfo.hasNextPage %}
    {% assign cursor = result.data.resources.pageInfo.endCursor %}
  {% else %}
    {% break %}
  {% endif %}
{% endfor %}
{% if event.topic contains "shopify/orders/" %}
  {% if event.preview %}
    {% capture order_json %}
      {
        "financial_status": "paid",
        "name": "#1234",
        "customer": {
          "email": "customer@example.com",
          "tags": "",
          "admin_graphql_api_id": "gid://shopify/Customer/1234567890"
        },
        "line_items": [
          {
            "product_id": 1234567890,
            "variant_id": 1234567890,
            "title": "ACME Widget"
          }
        ]
      }
    {% endcapture %}
    {% assign order = order_json | parse_json %}
  {% endif %}
  {% assign order_qualifies = false %}
  {% assign order_qualifying_resource = nil %}
  {% if order.financial_status == "paid" and order.customer %}
    {% for line_item in order.line_items %}
      {% if search_for == "products" %}
        {% assign id = line_item.product_id | append: "" %}
      {% else %}
        {% assign id = line_item.variant_id | append: "" %}
      {% endif %}
      {% if qualifier_resource_ids contains id %}
        {% assign order_qualifies = true %}
        {% assign order_qualifying_resource = line_item.title %}
        {% break %}
      {% endif %}
    {% endfor %}
  {% endif %}
  {% if order_qualifies %}
    {% assign job = hash %}
    {% assign job["customer_id"] = order.customer.admin_graphql_api_id %}
    {% assign job["customer_email"] = order.customer.email %}
    {% assign job["customer_existing_tags"] = order.customer.tags | split: ", " %}
    {% assign job["reason"] = order_qualifying_resource | append: ", in order " | append: order.name %}
    {% assign jobs[jobs.size] = job %}
  {% endif %}
{% elsif event.topic == "mechanic/user/trigger" %}
  {% capture bulk_operation_query %}
    query {
      customers {
        edges {
          node {
            __typename
            id
            defaultEmailAddress {
              emailAddress
            }
            tags
            orders(query: "financial_status:paid") {
              edges {
                node {
                  __typename
                  id
                  name
                  lineItems {
                    edges {
                      node {
                        __typename
                        id
                        {% if search_for == "products" %}
                          resource: product {
                            legacyResourceId
                            displayName: title
                          }
                        {% else %}
                          resource: variant {
                            legacyResourceId
                            displayName
                          }
                        {% 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" %}
  {% if event.preview %}
    {% capture jsonl_string %}
      {"__typename":"LineItem","resource":{"legacyResourceId":"1234567890","displayName":"ACME Widget"},"__parent":{"name":"#1234","__parent":{"id": "gid://shopify/Customer/1234567890","defaultEmailAddress":{"emailAddress":"customer@example.com"}}}}
    {% endcapture %}
    {% assign bulkOperation = hash %}
    {% assign bulkOperation["objects"] = jsonl_string | parse_jsonl %}
  {% endif %}
  {% assign line_items
    = bulkOperation.objects
    | where: "__typename", "LineItem"
    | where: "resource"
  %}
  {% for line_item in line_items %}
    {% assign resource = line_item.resource %}
    {% assign order = line_item.__parent %}
    {% assign customer = order.__parent %}
    {% if qualifier_resource_ids contains resource.legacyResourceId %}
      {% assign job = hash %}
      {% assign job["customer_id"] = customer.id %}
      {% assign job["customer_email"] = customer.defaultEmailAddress.emailAddress %}
      {% assign job["customer_existing_tags"] = customer.tags %}
      {% assign job["reason"] = resource.displayName | append: ", in order " | append: order.name %}
      {% assign jobs[jobs.size] = job %}
    {% endif %}
  {% endfor %}
{% endif %}
{% assign customer_ids_with_jobs = jobs | map: "customer_id" | uniq %}
{% for customer_id in customer_ids_with_jobs %}
  {% assign customer_jobs = jobs | where: "customer_id", customer_id %}
  {% assign customer_existing_tags = customer_jobs[0].customer_existing_tags %}
  {% assign customer_email = customer_jobs[0].customer_email %}
  {% assign reasons = customer_jobs | map: "reason" %}
  {% assign tags_to_add = array %}
  {% for tag in options.customer_tags_to_apply__required_array %}
    {% unless customer_existing_tags contains tag %}
      {% assign tags_to_add = tags_to_add | push: tag %}
    {% endunless %}
  {% endfor %}
  {% if test_mode %}
    {% log
      customer_id: customer_id,
      customer_email: customer_email,
      customer_purchases: reasons,
      customer_existing_tags: customer_existing_tags,
      customer_tags_to_add: tags_to_add
    %}
  {% elsif tags_to_add == blank %}
    {% log %}
      "Customer {{ customer.id }} already has all applicable tags ({{ tags_applicable | join: ", " }}); nothing to do."
    {% endlog %}
  {% else %}
    {% action "shopify" %}
      mutation {
        tagsAdd(
          id: {{ customer_id | json }}
          tags: {{ tags_to_add | json }}
        ) {
          userErrors {
            field
            message
          }
        }
      }
    {% endaction %}
  {% endif %}
{% endfor %}
sku:ABC123
variants
true