Auto-generate SKUs, with Mechanic.

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

Auto-generate SKUs

Save time by letting this task keep your SKUs up to date, generating them based on your product handle, and the initials of each variant option. Optionally, choose to have the task skip updating variants that already have SKUs. Useful for large catalogs, or for anyone who has a consistent SKU format.

Runs Occurs whenever a product is created and Occurs whenever a product is updated, ordered, or variants are added, removed or updated. Configuration includes skip variants that already have skus and product options to keep unabbreviated.

15-day free trial – unlimited tasks

Documentation

Save time by letting this task keep your SKUs up to date, generating them based on your product handle, and the initials of each variant option. Optionally, choose to have the task skip updating variants that already have SKUs. Useful for large catalogs, or for anyone who has a consistent SKU format.

Please note: This task updates SKUs for all products, whether or not they're configured with options and variants.

This task automatically maintains SKUs by combining these elements and joining them with a dash:

  1. The last portion of the product handle (e.g. 503, if your product is available at myshop.com/products/stylish-shirt-503)
  2. The capital letters of the variant's first option, if there is one (e.g. H if the option is Heather gray, or HG if the option is Heather Gray)
  3. The capital letters of the variant's second option, if there is one
  4. The capital letters of the variant's third option, if there is one

(To use the product option's full value, instead of abbreviating it, add the option name to the "Product options to keep unabbreviated" list.)

To illustrate, a shirt available at myshop.com/products/stylish-shirt-503, with options for size and color, might have these SKUs auto-generated:

  • Medium, Black: 503-M-B
  • XL, Heather gray: 503-XL-H
  • Small, Red: 503-S-R

To update your product handle, so as to control the first portion of generated SKUs, open the product in the Shopify admin, scroll to the bottom of the page, click the edit icon next to "Search engine listing", and update the "URL handle" field to taste. :)

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/create
shopify/products/update
Tasks use subscriptions to sign up for specific kinds of events. Learn more
Options
skip variants that already have skus (boolean), product options to keep unabbreviated (array)
Code
{% assign skip_variants_that_already_have_skus = options.skip_variants_that_already_have_skus__boolean %}
{% assign product_options_to_keep_unabbreviated = options.product_options_to_keep_unabbreviated__array %}

{% assign allowed_characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" %}

{% assign sku_base = product.handle | split: "-" | last | upcase %}

{% if event.preview %}
  {% assign sku_base = "503" %}
{% endif %}

{% assign cursor = nil %}
{% assign variants = array %}

{% for n in (1..8) %}
  {% capture query %}
    query {
      product(id: {{ product.admin_graphql_api_id | json }}) {
        id
        handle
        variants(
          first: 250
          after: {{ cursor | json }}
        ) {
          pageInfo {
            hasNextPage
            endCursor
          }
          nodes {
            inventoryItem {
              id
            }
            sku
            selectedOptions {
              name
              value
            }
          }
        }
      }
    }
  {% endcapture %}

  {% assign result = query | shopify %}

  {% if event.preview %}
    {% capture result_json %}
      {
        "data": {
          "product": {
            "variants": {
              "nodes": [
                {
                  "inventoryItem": {
                    "id": "gid://shopify/InventoryItem/1234567890"
                  },
                  {% unless skip_variants_that_already_have_skus %}"sku": "503-XL-G",{% endunless %}
                  "selectedOptions": [
                    {
                      "name": "Size",
                      "value": "XL"
                    },
                    {
                      "name": "Color",
                      "value": "Heather Grey"
                    }
                  ]
                }
              ]
            }
          }
        }
      }
    {% endcapture %}

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

  {% assign variants = variants | concat: result.data.product.variants.nodes %}

  {% if result.data.product.variants.pageInfo.hasNextPage %}
    {% assign cursor = result.data.product.variants.pageInfo.endCursor %}
  {% else %}
    {% break %}
  {% endif %}
{% endfor %}

{% for variant in variants %}
  {% if skip_variants_that_already_have_skus and variant.sku != blank %}
    {% log
      message: "variant already has a sku; skipping",
      original_sku: variant.sku
    %}
    {% continue %}
  {% endif %}

  {% assign variant_sku_generated = sku_base %}

  {% for selected_option in variant.selectedOptions %}
    {% if product_options_to_keep_unabbreviated contains selected_option.name %}
      {% assign variant_sku_generated = variant_sku_generated | append: "-" | append: selected_option.value %}

    {% else %}
      {% assign variant_option_abbreviation = "" %}
      {% assign variant_option_characters = selected_option.value | split: "" %}

      {% for variant_option_character in variant_option_characters %}
        {% if allowed_characters contains variant_option_character %}
          {% assign variant_option_abbreviation = variant_option_abbreviation | append: variant_option_character %}
        {% endif %}
      {% endfor %}

      {% if variant_option_abbreviation == blank %}
        {% assign variant_option_abbreviation = variant_option_characters[0] | upcase %}
      {% endif %}

      {% assign variant_sku_generated = variant_sku_generated | append: "-" | append: variant_option_abbreviation %}
    {% endif %}
  {% endfor %}

  {% if variant_sku_generated != variant.sku %}
    {% log
      message: "updating sku",
      original_sku: variant.sku,
      generated_sku: variant_sku_generated
    %}

    {% comment %}
      -- as of the 2024-07 API, SKUs are updated on inventory items instead of variants
    {% endcomment %}

    {% action "shopify" %}
      mutation {
        inventoryItemUpdate(
          id: {{ variant.inventoryItem.id | json }}
          input: {
            sku: {{ variant_sku_generated | json }}
          }
        ) {
          inventoryItem {
            variant {
              id
              displayName
              sku
            }
          }
          userErrors {
            field
            message
          }
        }
      }
    {% endaction %}
  {% endif %}
{% endfor %}
Task code is written in Mechanic Liquid, an extension of open-source Liquid enhanced for automation. Learn more
Defaults
Skip variants that already have SKUs
true