Auto-tag orders that contain a matching product, with Mechanic.

Mechanic is an automation development platform for Shopify. :)

Auto-tag orders that contain a matching product

by Isaac Bowen (team@usemechanic.com)

This task watches for incoming orders, and tags them if they contain a product that matches by title or by product tags. Run this task manually to scan your store's order history, tagging older orders that qualify.

Runs when an order is created, when a user triggers the task, and when a bulk operation finishes. Configuration includes required product title, required product tags, and order tags to apply.

15-day free trial – unlimited tasks

Documentation

Note: If more than one required product tag is specified, this task will look for products that individually contain all of the tags provided.

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 an order is created (shopify/orders/create)
when a user triggers the task (mechanic/user/trigger)
when a bulk operation finishes (mechanic/shopify/bulk_operation)
Options
required product title, required product tags (array), order tags to apply (required, array)
Script
{% comment %}
  Ordering the task options:

  {{ options.required_product_title }}
  {{ options.required_product_tags__array }}
  {{ options.order_tags_to_apply__required_array }}
{% endcomment %}

{% if options.required_product_title == blank and options.required_product_tags__array == blank %}
  {"error": "Fill in at least one of 'Required product title' and 'Required product tags'. :)"}
{% endif %}

{% if event.topic contains "shopify/orders/" %}
  {% if event.preview %}
    {% assign order = hash %}
    {% assign order["admin_graphql_api_id"] = "gid://shopify/Order/1234567890" %}
    {% assign order["line_items"] = array %}

    {% assign product = hash %}
    {% if options.required_product_title != blank %}
      {% assign product["title"] = options.required_product_title %}
    {% endif %}
    {% if options.required_product_tags__array  != blank %}
      {% assign product["tags"] = options.required_product_tags__array | join: ", " %}
    {% endif %}

    {% assign order["line_items"][0] = hash %}
    {% assign order["line_items"][0]["product"] = product %}
  {% endif %}

  {% assign order_qualifies = false %}
  {% assign order_qualifies_by_tag = nil %}
  {% assign order_qualifies_by_title = nil %}

  {% assign order_products = order.line_items | map: "product" %}

  {% if options.required_product_title != blank %}
    {% assign order_qualifies_by_title = false %}

    {% assign order_product_titles = order_products | map: "title" %}
    {% if order_product_titles contains options.required_product_title %}
      {% assign order_qualifies_by_title = true %}
    {% endif %}
  {% endif %}

  {% if options.required_product_tags__array != blank %}
    {% assign order_qualifies_by_tag = false %}

    {% for order_product in order_products %}
      {% assign order_product_tags = order_product.tags | split: ", " %}
      {% assign order_product_qualifies_by_tag = true %}
      {% for required_tag in options.required_product_tags__array %}
        {% unless order_product_tags contains required_tag %}
          {% assign order_product_qualifies_by_tag = false %}
          {% break %}
        {% endunless %}
      {% endfor %}

      {% if order_product_qualifies_by_tag %}
        {% assign order_qualifies_by_tag = true %}
        {% break %}
      {% endif %}
    {% endfor %}
  {% endif %}

  {% comment %}
    Make sure *at least one* of the two qualifications were evaluated,
    and make sure neither of them outright failed.
  {% endcomment %}
  {% if order_qualifies_by_tag != nil or order_qualifies_by_title != nil %}
    {% if order_qualifies_by_tag != false and order_qualifies_by_title != false %}
      {% assign order_qualifies = true %}
    {% endif %}
  {% endif %}

  {% if order_qualifies %}
    {% action "shopify" %}
      mutation {
        tagsAdd(
          id: {{ order.admin_graphql_api_id | json }}
          tags: {{ options.order_tags_to_apply__required_array | json }}
        ) {
          userErrors {
            field
            message
          }
        }
      }
    {% endaction %}
  {% endif %}
{% elsif event.topic == "mechanic/user/trigger" %}
  {% capture bulk_operation_query %}
    query {
      orders {
        edges {
          node {
            __typename
            id
            tags
            lineItems {
              edges {
                node {
                  __typename
                  id
                  product {
                    id
                    title
                    tags
                  }
                }
              }
            }
          }
        }
      }
    }
  {% 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 %}
    {% assign bulkOperation = hash %}
    {% assign bulkOperation["objects"] = array %}

    {% assign order = hash %}
    {% assign order["__typename"] = "Order" %}
    {% assign order["id"] = "gid://shopify/Order/1234567890" %}
    {% assign order["tags"] = array %}

    {% assign product = hash %}
    {% assign product["title"] = options.required_product_title %}
    {% assign product["tags"] = options.required_product_tags__array %}

    {% assign lineItem = hash %}
    {% assign lineItem["__typename"] = "LineItem" %}
    {% assign lineItem["__parent"] = order %}
    {% assign lineItem["product"] = product %}

    {% assign bulkOperation["objects"][0] = order %}
    {% assign bulkOperation["objects"][1] = lineItem %}
  {% endif %}

  {% assign qualifying_order_ids = array %}
  {% assign order_ids_that_already_have_tags = array %}

  {% for object in bulkOperation.objects %}
    {% case object.__typename %}
    {% when "Order" %}
      {% assign order_already_has_tags = true %}
      {% for tag in options.order_tags_to_apply__required_array %}
        {% unless object.tags contains tag %}
          {% assign order_already_has_tags = false %}
        {% endunless %}
      {% endfor %}

      {% if order_already_has_tags %}
        {% assign order_ids_that_already_have_tags[order_ids_that_already_have_tags.size] = object.id %}
      {% endif %}
    {% when "LineItem" %}
      {% assign product = object.product %}

      {% assign product_qualifies = false %}
      {% assign product_qualifies_by_tag = nil %}
      {% assign product_qualifies_by_title = nil %}

      {% if options.required_product_title != blank %}
        {% assign product_qualifies_by_title = false %}

        {% if product.title == options.required_product_title %}
          {% assign product_qualifies_by_title = true %}
        {% endif %}
      {% endif %}

      {% if options.required_product_tags__array != blank %}
        {% assign product_qualifies_by_tag = true %}
        {% for required_tag in options.required_product_tags__array %}
          {% unless product.tags contains required_tag %}
            {% assign product_qualifies_by_tag = false %}
            {% break %}
          {% endunless %}
        {% endfor %}
      {% endif %}

      {% comment %}
        Make sure *at least one* of the two qualifications were evaluated,
        and make sure neither of them outright failed.
      {% endcomment %}
      {% if product_qualifies_by_tag != nil or product_qualifies_by_title != nil %}
        {% if product_qualifies_by_tag != false and product_qualifies_by_title != false %}
          {% assign product_qualifies = true %}
        {% endif %}
      {% endif %}

      {% if product_qualifies %}
        {% assign qualifying_order_ids[qualifying_order_ids.size] = object.__parent.id %}
      {% endif %}
    {% endcase %}
  {% endfor %}

  {% assign qualifying_order_ids = qualifying_order_ids | uniq %}
  {% assign order_ids_that_already_have_tags = order_ids_that_already_have_tags | uniq %}

  {% for order_id in qualifying_order_ids %}
    {% unless order_ids_that_already_have_tags contains order_id %}
      {% action "shopify" %}
        mutation {
          tagsAdd(
            id: {{ order_id | json }}
            tags: {{ options.order_tags_to_apply__required_array | json }}
          ) {
            userErrors {
              field
              message
            }
          }
        }
      {% endaction %}
    {% endunless %}
  {% endfor %}
{% endif %}
Mechanic tasks are written in Liquid, which makes them easy to write and easy to modify. Learn more about our platform.