Rotate products through a featured collection with Mechanic.

Mechanic is the one-tool-does-it-all automation app for Shopify. :)

Rotate products through a featured collection

by Isaac Bowen (team@usemechanic.com)

This task features products on a schedule, optionally publishing/unpublishing as they're featured/unfeatured. Use this task to make available exclusive products on the hourly/daily/etc, or simply to showcase a rotating selection of your best products.

Runs when a user triggers the task. Configuration includes product ids to be featured, featured collection, number of products to feature at once, manage product publishing, maximum number of times to feature a product, price multiplier for featured products, tag to add after a product has been featured for the last time, run hourly, and run daily at midnight.

15-day free trial – unlimited tasks

Documentation

Configure this task by adding a list of product IDs to feature, in the order you'd like them to be featured, and setting the "Featured collection ID" to the ID of whatever collection you'd like this task to manage.* This task will feature a configurable number of products at a time, rotating through the list from top to bottom, beginning again at the top of the list when the final products are featured.

Feel free to add new IDs to the list over time, but don't remove IDs for products that are currently published! This task figures out what products are next, by looking up the currently-published products in the configured ID list.

Enable "Manage product publishing" to have this task publish products when they're featured, and unpublish products when they're done being featured.

Enable "Run hourly" or "Run daily at midnight" to have this task run automatically. Otherwise, use the "Run task" button to run this task on demand.

Enable "Maximum number of times to feature a product" to control how many times Mechanic will feature a product over its lifetime.

Configure "Price multiplier for featured products" to control pricing adjustments to apply only when a product is featured. For example, a multiplier of 0.5 would result in a product being featured for 50% off, being restored to its normal price when it is no longer featured. (This task will update the price for each of a product's variants, even if there is only one, but it will not modify any "compare at" prices.)

*To find IDs for your products or collections, navigate to the product or collection in the Shopify admin area, and use the number at the very end of the URL in your browser's address bar.

For example, a product located at example.myshopify.com/admin/products/1234567890 would have a product ID of 1234567890.

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)
Options
product ids to be featured (number, array, required), featured collection (number, required), number of products to feature at once (required, number), manage product publishing (boolean), maximum number of times to feature a product (number), price multiplier for featured products (number), tag to add after a product has been featured for the last time, run hourly (boolean), run daily at midnight (boolean)
Script
{% assign product_ids_to_be_featured = options.product_ids_to_be_featured__number_array_required %}
{% assign number_of_product_ids = product_ids_to_be_featured.size %}
{% assign featured_collection_id = options.featured_collection_id__number_required %}
{% assign number_of_products_to_feature_at_once = options.number_of_products_to_feature_at_once__required_number | round %}
{% assign manage_product_publishing = options.manage_product_publishing__boolean %}
{% assign max_feature_times = options.maximum_number_of_times_to_feature_a_product__number %}
{% assign price_multiplier = options.price_multiplier_for_featured_products__number %}
{% assign inverse_price_multiplier = nil %}
{% if price_multiplier != blank %}
  {% assign inverse_price_multiplier = 1.0 | divided_by: price_multiplier %}
{% endif %}

{% if event.preview %}
  {
    "action": {
      "type": "shopify",
      "options": [
        "create",
        "collect",
        {
          "product_id": 1234567890,
          "collection_id": 1234567890,
          "position": 0
        }
      ]
    }
  }

  {% assign product_updates = "" %}

  {% assign tags_to_save = nil %}
  {% if max_feature_times != blank and options.tag_to_add_after_a_product_has_been_featured_for_the_last_time != blank %}
    {% assign tags_to_save = options.tag_to_add_after_a_product_has_been_featured_for_the_last_time %}
  {% endif %}

  {% if tags_to_save %}
    {% capture product_updates %}
      {% if product_updates != blank %}{{ product_updates }}, {% endif %}
      "tags": {{ tags_to_save | json }}
    {% endcapture %}
  {% endif %}

  {% if manage_product_publishing %}
    {% capture product_updates %}
      {% if product_updates != blank %}{{ product_updates }}, {% endif %}
      "published": true
    {% endcapture %}
  {% endif %}

  {% if price_multiplier != blank %}
    {% capture product_updates %}
      {% if product_updates != blank %}{{ product_updates }}, {% endif %}
      "variants": [
        {
          "id": 1234567890,
          "price": {{ 10.0 | times: price_multiplier | json }}
        }
      ]
    {% endcapture %}
  {% endif %}

  {% if product_updates != blank %}
    {
      "action": {
        "type": "shopify",
        "options": [
          "update",
          ["product", 1234567890],
          {
            {{ product_updates }}
          }
        ]
      }
    }
  {% endif %}

  {% if max_feature_times != blank %}
    {
      "action": {
        "type": "shopify",
        "options": [
          "create",
          "metafield",
          {
            "owner_resource": "product",
            "owner_id": 1234567890,
            "namespace": "mechanic",
            "key": "feature_count",
            "value_type": "integer",
            "value": 1
          }
        ]
      }
    }
  {% endif %}
{% else %}
  {% assign featured_collection = shop.collections[featured_collection_id] %}
  {% assign currently_featured_collects = featured_collection.collects %}

  {% if featured_collection == nil %}
    {% capture message %}Collection {{ featured_collection_id | json }} not found - not going to do any work.{% endcapture %}
    {"log": {{ message | json }}}
  {% else %}
    {% for collect in currently_featured_collects %}
      {
        "action": {
          "type": "shopify",
          "options": [
            "delete",
            ["collect", {{ collect.id | json }}]
          ]
        }
      }

      {% assign product = shop.products[collect.product_id] %}
      {% assign product_updates = "" %}

      {% assign tags_to_save = nil %}
      {% if max_feature_times != blank and options.tag_to_add_after_a_product_has_been_featured_for_the_last_time != blank %}
        {% assign current_feature_count = product.metafields.mechanic.feature_count | default: 0 %}
        {% if current_feature_count >= max_feature_times %}
          {% assign tags_to_save = product.tags | add_tag: options.tag_to_add_after_a_product_has_been_featured_for_the_last_time %}
        {% endif %}
      {% endif %}

      {% if tags_to_save %}
        {% capture product_updates %}
          {% if product_updates != blank %}{{ product_updates }}, {% endif %}
          "tags": {{ tags_to_save | json }}
        {% endcapture %}
      {% endif %}

      {% if manage_product_publishing %}
        {% capture product_updates %}
          {% if product_updates != blank %}{{ product_updates }}, {% endif %}
          "published": false
        {% endcapture %}
      {% endif %}

      {% if inverse_price_multiplier != blank %}
        {% capture product_updates %}
          {% if product_updates != blank %}{{ product_updates }}, {% endif %}
          "variants": [
            {% for variant in product.variants %}
              {
                "id": {{ variant.id | json }},
                "price": {{ variant.price | times: inverse_price_multiplier | json }}
              }
              {% unless forloop.last %},{% endunless %}
            {% endfor %}
          ]
        {% endcapture %}
      {% endif %}

      {% if product_updates != blank %}
        {
          "action": {
            "type": "shopify",
            "options": [
              "update",
              ["product", {{ product.id | json }}],
              {
                {{ product_updates }}
              }
            ]
          }
        }
      {% endif %}
    {% endfor %}

    {% assign last_featured_index = -1 %}
    {% for collect in currently_featured_collects %}
      {% for product_id_to_be_featured in product_ids_to_be_featured %}
        {% if product_id_to_be_featured == collect.product_id and forloop.index0 > last_featured_index %}
          {% assign last_featured_index = forloop.index0 %}
        {% endif %}
      {% endfor %}
    {% endfor %}

    {% if last_featured_index == -1 %}
      {"log": "No matches found between the featured collection and the configured product ID list, so we're going to start by featuring the first product(s) in the list."}
    {% elsif product_ids_to_be_featured[last_featured_index] == product_ids_to_be_featured.last %}
      {"log": "We were previously at the end of the feature list; beginning again at the beginning"}
      {% assign last_featured_index = -1 %}
    {% endif %}

    {% for n in (1..number_of_products_to_feature_at_once) %}
      {% assign product_index_to_be_featured = last_featured_index | plus: n %}
      {% assign product_id_to_be_featured = product_ids_to_be_featured[product_index_to_be_featured] %}

      {% if product_id_to_be_featured == blank %}
        {"log": "Reached the end of the product ID list - no more products to feature."}
        {% break %}
      {% endif %}

      {% if max_feature_times != blank %}
        {% assign current_feature_count = shop.products[product_id_to_be_featured].metafields.mechanic.feature_count | default: 0 %}
        {% if current_feature_count >= max_feature_times %}
          {% capture message %}Product {{ product_id_to_be_featured }} has already been published {{ current_feature_count }} time(s); skipping{% endcapture %}
          {"log": {{ message | json }}}
          {% continue %}
        {% endif %}
      {% endif %}

      {
        "action": {
          "type": "shopify",
          "options": [
            "create",
            "collect",
            {
              "product_id": {{ product_id_to_be_featured | json }},
              "collection_id": {{ featured_collection_id | json }},
              "position": {{ n | json }}
            }
          ]
        }
      }

      {% assign product_updates = "" %}

      {% if manage_product_publishing %}
        {% capture product_updates %}
          {% if product_updates != blank %}{{ product_updates }}, {% endif %}
          "published": true
        {% endcapture %}
      {% endif %}

      {% if price_multiplier != blank %}
        {% capture product_updates %}
          {% if product_updates != blank %}{{ product_updates }}, {% endif %}
          "variants": [
            {% for variant in shop.products[product_id_to_be_featured].variants %}
              {
                "id": {{ variant.id | json }},
                "price": {{ variant.price | times: price_multiplier | json }}
              }
              {% unless forloop.last %},{% endunless %}
            {% endfor %}
          ]
        {% endcapture %}
      {% endif %}

      {% if product_updates != blank %}
        {
          "action": {
            "type": "shopify",
            "options": [
              "update",
              ["product", {{ product_id_to_be_featured | json }}],
              {
                {{ product_updates }}
              }
            ]
          }
        }
      {% endif %}

      {% if max_feature_times != blank %}
        {
          "action": {
            "type": "shopify",
            "options": [
              "create",
              "metafield",
              {
                "owner_resource": "product",
                "owner_id": {{ product_id_to_be_featured | json }},
                "namespace": "mechanic",
                "key": "feature_count",
                "value_type": "integer",
                "value": {{ current_feature_count | plus: 1 | json }}
              }
            ]
          }
        }
      {% endif %}
    {% endfor %}
  {% endif %}
{% endif %}
Mechanic tasks are written in Liquid, which makes them easy to write and easy to modify. Learn more about our platform.