Auto-create collections by product type or vendor, with Mechanic.

Mechanic is a development and ecommerce automation platform for Shopify. :)

Auto-create collections by product type or vendor

When products are created, this task will auto-create smart collections by product type and/or vendor, if such collections don't already exist. Additionally, configuring one or more exact sales channel names will enable publishing of any newly created collections by this task to those sales channels.

Runs Occurs whenever a product is updated, or whenever a product is ordered, or whenever a variant is added, removed, or updated and Occurs when a user manually triggers the task. Configuration includes create collections by product type, create collections by vendor, and names of sales channels to publish collections to.

15-day free trial – unlimited tasks

Documentation

When products are created, this task will auto-create smart collections by product type and/or vendor, if such collections don't already exist. Additionally, configuring one or more exact sales channel names will enable publishing of any newly created collections by this task to those sales channels.

For example:

A new product is added with a vendor of "ACME". If a collection with that exact title does not already exist, then the task will create it with a title of "ACME" and add a rule of "vendor = ACME", which will allow Shopify to auto-populate the collection.

The task may also be run manually to gather all of the product types and vendors in your shop, and then making the same decisions on whether to create new collections and publish them.

Developer details

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?)

Open source
View on GitHub to contribute to this task
Subscriptions
shopify/products/update
mechanic/user/trigger
{% if options.names_of_sales_channels_to_publish_collections_to__array != blank %}
  mechanic/actions/perform
{% endif %}
Tasks use subscriptions to sign up for specific kinds of events. Learn more
Options
create collections by product type (boolean), create collections by vendor (boolean), names of sales channels to publish collections to (array)
Code
{% assign create_collections_by_product_type = options.create_collections_by_product_type__boolean %}
{% assign create_collections_by_vendor = options.create_collections_by_vendor__boolean %}
{% assign sales_channel_names = options.names_of_sales_channels_to_publish_collections_to__array %}

{% unless create_collections_by_product_type or create_collections_by_vendor %}
  {% error "Choose at least one 'Create collections by' option" %}
{% endunless %}

{% assign product_types = array %}
{% assign vendors = array %}

{% if event.topic == "mechanic/user/trigger" or event.topic == "shopify/products/update" %}
  {% if event.topic == "mechanic/user/trigger" %}
    {% assign cursor = nil %}

    {% for n in (1..1000) %}
      {% capture query %}
        query {
          products(
            first: 250
            after: {{ cursor | json }}
          ) {
            pageInfo {
              hasNextPage
            }
            edges {
              cursor
              node {
                productType
                vendor
              }
            }
          }
        }
      {% endcapture %}

      {% assign result = query | shopify %}

      {% assign products = result.data.products.edges | map: "node" %}

      {% for product in products %}
        {% unless product.productType == blank or product_types contains product.productType %}
          {% assign product_types = product_types | push: product.productType %}
        {% endunless %}

        {% unless product.vendor == blank or vendors contains product.vendor %}
          {% assign vendors = vendors | push: product.vendor %}
        {% endunless %}
      {% endfor %}

      {% if result.data.products.pageInfo.hasNextPage %}
        {% assign cursor = result.data.products.edges.last.cursor %}
      {% else %}
        {% break %}
      {% endif %}
    {% endfor %}

  {% elsif event.topic == "shopify/products/update" %}
    {% unless product.product_type == blank %}
      {% assign product_types[0] = product.product_type %}
    {% endunless %}

    {% unless product.vendor == blank %}
      {% assign vendors[0] = product.vendor %}
    {% endunless %}
  {% endif %}

  {% if event.preview %}
    {% assign product_types[0] = "Widget" %}
    {% assign vendors[0] = "ACME" %}
  {% endif %}

  {% if sales_channel_names != blank %}
    {% assign publication_ids = array %}

    {% capture query %}
      query {
        publications(first: 250) {
          edges {
            node {
              id
              name
            }
          }
        }
      }
    {% endcapture %}

    {% assign result = query | shopify %}

    {% if event.preview %}
      {% capture result_json %}
        {
          "data": {
            "publications": {
              "edges": [
                {
                  "node": {
                    "id": "gid://shopify/Publication/1234567890",
                    "name": {{ sales_channel_names[0] | json }}
                  }
                }
              ]
            }
          }
        }
      {% endcapture %}

      {% assign result = result_json | parse_json %}
    {% endif %}

    {% assign publications = result.data.publications.edges | map: "node" %}
    {% assign publication_names = publications | map: "name" | sort %}
    {% assign publications_indexed_by_name = publications | index_by: "name" %}

    {% for sales_channel_name in sales_channel_names %}
      {% if publication_names contains sales_channel_name %}
        {% assign publication_ids = publication_ids | push: publications_indexed_by_name[sales_channel_name].id %}

      {% else %}
        {% unless event.preview %}
          {% error
            message: "A configured sales channel name does not match any of the publication names available in this shop.",
            sales_channel_name: sales_channel_name,
            publication_names: publication_names
          %}
        {% endunless %}
      {% endif %}
    {% endfor %}
  {% endif %}

  {% if create_collections_by_product_type %}
    {% for product_type in product_types %}
      {% capture query %}
        query {
          collections(
            first: 1
            query: {{ product_type | json | prepend: "title:" | json }}
          ) {
            edges {
              node {
                id
                title
                handle
              }
            }
          }
        }
      {% endcapture %}

      {% assign result = query | shopify %}

      {% if result.data.collections.edges != blank %}
        {% log
          message: "A collection title matching this product type already exists; skipping.",
          product_type: product_type,
          collection: result.data.collections.edges.first.node
        %}

      {% else %}
        {% capture mutation %}
          mutation {
            collectionCreate(
              input: {
                title: {{ product_type | json }}
                ruleSet: {
                  appliedDisjunctively: false
                  rules: [
                    {
                      column: TYPE
                      relation: EQUALS
                      condition: {{ product_type | json }}
                    }
                  ]
                }
              }
            ) {
              collection {
                id
                title
                handle
              }
              userErrors {
                field
                message
              }
            }
          }
        {% endcapture %}

        {% action %}
          {
            "type": "shopify",
            "options": {{ mutation | json }},
            "meta": {
              "publication_ids": {{ publication_ids | json }}
            }
          }
        {% endaction %}
      {% endif %}
    {% endfor %}
  {% endif %}

  {% if create_collections_by_vendor %}
    {% for vendor in vendors %}
      {% capture query %}
        query {
          collections(
            first: 1
            query: {{ vendor | json | prepend: "title:" | json }}
          ) {
            edges {
              node {
                id
                title
                handle
              }
            }
          }
        }
      {% endcapture %}

      {% assign result = query | shopify %}

      {% if result.data.collections.edges != blank %}
        {% log
          message: "A collection title matching this vendor already exists; skipping.",
          vendor: vendor,
          collection: result.data.collections.edges.first.node
        %}

      {% else %}
        {% capture mutation %}
          mutation {
            collectionCreate(
              input: {
                title: {{ vendor | json }}
                ruleSet: {
                  appliedDisjunctively: false
                  rules: [
                    {
                      column: VENDOR
                      relation: EQUALS
                      condition: {{ vendor | json }}
                    }
                  ]
                }
              }
            ) {
              collection {
                id
                title
                handle
              }
              userErrors {
                field
                message
              }
            }
          }
        {% endcapture %}

        {% action %}
          {
            "type": "shopify",
            "options": {{ mutation | json }},
            "meta": {
              "publication_ids": {{ publication_ids | json }}
            }
          }
        {% endaction %}
      {% endif %}
    {% endfor %}
  {% endif %}

{% elsif event.topic == "mechanic/actions/perform" %}
  {% if event.preview %}
    {% capture action_json %}
      {
        "type": "shopify",
        "meta": {
          "publication_ids": [
            "gid://shopify/Publication/1234567890"
          ]
        },
        "run": {
          "ok": true,
          "result": {
            "data": {
              "collectionCreate": {
                "collection": {
                  "id": "gid://shopify/Collection/1234567890",
                  "title": "ACME",
                  "handle": "acme"
                }
              }
            }
          }
        }
      }
    {% endcapture %}

    {% assign action = action_json | parse_json %}
  {% endif %}

  {% if action.run.ok %}
    {% assign collection_id = action.run.result.data.collectionCreate.collection.id %}
    {% assign publication_ids = action.meta.publication_ids %}

    {% assign mutations = array %}

    {% for publication_id in publication_ids %}
      {% capture mutation %}
          publishablePublish{{ forloop.index }}: publishablePublish(
            id: {{ collection_id | json }}
            input: {
              publicationId: {{ publication_id | json }}
            }
          ) {
            publishable {
              ... on Collection {
                id
                title
                handle
              }
            }
            userErrors {
              field
              message
            }
          }
        {% endcapture %}

        {% assign mutations = mutations | push: mutation %}
    {% endfor %}

    {% if mutations != blank %}
      {% action "shopify" %}
        mutation {
          {{ mutations | join: newline }}
        }
      {% endaction %}
    {% endif %}
  {% endif %}
{% endif %}
Task code is written in Mechanic Liquid, an extension of open-source Liquid enhanced for automation. Learn more