Shopify: Related Products

A feature clients constantly ask for in eCommerce is a method of showing recommended products from their product or category pages. Easily my favorite eCommerce system, Shopify, offers a great admin and template system, but no great built-in recommendation engine.

There are some code snippets on their forums for recommended products, and some apps in the store, but if you've found this blog then you're probably looking for something that you can quickly implement without paying money.

Recently, I wrote this snippet for calculating related products. It's a bit verbose and inefficient, but we'll talk about that after viewing the code.

{% if product != nil %}
{% assign number_of_related_products_to_show = 4 %}
{% assign number_of_related_products_found = 0 %}
{% assign product_vendor = product.vendor %}
{% assign current_product = product %}
{% if collection == null or collection.handle == 'frontpage' or collection.handle == 'all' %}
      {% assign found_a_collection = false %}
      {% for c in product.collections %}
        {% if found_a_collection == false and c.handle != 'frontpage' and c.handle != 'all' %}
          {% assign found_a_collection = true %}
          {% assign collection = c %}
        {% endif %}
      {% endfor %}
    {% endif %}
{% if collection and collection.all_products_count > 1 %}
{% assign current_product_found = false %}
{% paginate collection.all_products by collection.all_products_count %}
{% for product in collection.all_products %}
{% if current_product.handle != product.handle and number_of_related_products_found < number_of_related_products_to_show %}
              {% if current_product.vendor == product.vendor and current_product.type == product.type %}
                {% assign number_of_related_products_found = number_of_related_products_found | plus: 1 %}
                {% assign current_product_listing = product %}
                {% assign current_product_listing_var = product.variants[0] %}
                {% include 'snippet-related-product' %}
              {% endif %}
{% endif %}
{% endfor %}

{% if number_of_related_products_found < number_of_related_products_to_show %}
          {% for product in collection.all_products %}
              {% if current_product.handle != product.handle and number_of_related_products_found < number_of_related_products_to_show %}
                {% if current_product.vendor == product.vendor and current_product.type != product.type %}
                  {% assign number_of_related_products_found = number_of_related_products_found | plus: 1 %}
                  {% assign current_product_listing = product %}
                  {% assign current_product_listing_var = product.variants[0] %}
                  {% include 'snippet-related-product' %}
                {% endif %}
              {% endif %}
          {% endfor %}

          {% for product in collection.all_products %}
              {% if current_product.handle != product.handle and number_of_related_products_found < number_of_related_products_to_show %}
                {% if current_product.vendor != product.vendor and current_product.type == product.type %}
                  {% assign number_of_related_products_found = number_of_related_products_found | plus: 1 %}
                  {% assign current_product_listing = product %}
                  {% assign current_product_listing_var = product.variants[0] %}
                  {% include 'snippet-related-product' %}
                {% endif %}
              {% endif %}
          {% endfor %}

          {% for product in collection.all_products %}
              {% if current_product.handle != product.handle and number_of_related_products_found < number_of_related_products_to_show %}
                {% if current_product.vendor != product.vendor and current_product.type != product.type %}
                  {% assign number_of_related_products_found = number_of_related_products_found | plus: 1 %}
                  {% assign current_product_listing = product %}
                  {% assign current_product_listing_var = product.variants[0] %}
                  {% include 'snippet-related-product' %}
                {% endif %}
              {% endif %}
          {% endfor %}
{% endif %}

{% endpaginate %}
{% endif %}
{% endif %}


Let's look at what's going on here...

First, the code attempts to find alternate products that have the same Type as the product you're comparing, and is a part of the same collection.

If not enough products have been found yet, the code then checks for products that are the same vendor, but a different type.

The next section of code attempts to find products that are the same type as the target product, but any vendor will do.

And finally, if enough matches still haven't been found, the system will add products from the same category but ignore vendor and type.

The inefficiency comes into play if the number of recommended products is matched in the first very loop through the products. It is unnecessary to look at the remainder of the products. Feel free to check that for that condition with an if statement -- I chose not to for two reasons:

  1. The code is already ugly, I didn't want to make it even more difficult to read.
  2. Shopify renders pages in memory and caches the html. This code will technically only run the first time a page renders (or when you change something through the admin) so your page render time will not be affected.

This code does assume that there is a snippet named 'snippet-related-product.liquid' and this can display the product however you wish.

Hopefully this helps somebody in the future. I'll likely be posting liquid code snippets often as this very blog is built upon bzzbzz, which also utilizes the Liquid language.

comments powered by Disqus