Copy order tags to customers with Mechanic.

Mechanic is an automation and development platform for Shopify. :)

Copy order tags to customers

by Isaac Bowen (team@usemechanic.com)

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.

Runs when a user triggers the task and when a bulk operation finishes. Configuration includes include order tags, include product tags, only include customers matching this query, only include orders matching this query, and only copy these tags.

15-day free trial – unlimited tasks

Documentation

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.

This task operates in two phases: it first submits a bulk query from Shopify, and then it processes the query's results, performing any tagging necessary.

Please note: While Shopify's bulk operations API is in beta, this task must be configured to use the "unstable" Shopify API version. You can configure this by clicking "Show advanced", in the task's options.

Developer details

Mechanic is designed to benefit everybody: merchants, customers, developers, agencies, Gurus, 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.

Events
when a user triggers the task (mechanic/user/trigger)
when a bulk operation finishes (mechanic/shopify/bulk_operation)
Options
include order tags (boolean), include product tags (boolean), only include customers matching this query, only include orders matching this query, only copy these tags (array)
Script
{% 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 event.topic == "mechanic/user/trigger" %}
  {% if task.shopify_api_version != "unstable" %}
    {"error": "To run manually, change this task's Shopify API version to 'unstable'."}
  {% endif %}

  {% 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 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 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 keyval in tags_available_by_customer_id %}
    {% assign customer_id = keyval[0] %}
    {% assign customer = bulkOperation.objects | where: "id", customer_id | first %}

    {% assign tags_available = keyval[1] %}

    {% 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 %}
  {% endfor %}
{% endif %}
Mechanic tasks are written in Liquid, which makes them easy to write and easy to modify. Learn more about our platform.