Sort by colour in Shopify 1st October 2018

We were recently approached by a client who wanted to revamp their online store and move over to Shopify from Magento. They had been experiencing appalling performance issues and constantly running out of disk space as a result of Magento's bloated nature and resource-hungry code, whilst also becoming exasperated with the lack of usability in the backend. Their shared hosting costs were spiralling and it was time for a change.

For all its faults, Magento did do one thing that was not possible out-of-the-box with Shopify or with any of the apps in the App Store — sorting collections (categories) by colour. Our initial thought was "it's not possible", but we weren't going to be beaten that easily.

After some considerable playing with Liquid — Shopify's templating language — we came up with a solution.

In essence, the process was as follows:

  1. Create a theme setting to define the colours that we're going to sort and in which order,
  2. Loop through each colour and find matching products,
  3. Display the matching colours on the page.

From the outset, this appears quite straightforward, however we also had to take into account pagination. Typically, if the collection template is set to display, for example, 20 products per page, the code will simply return the first 20 products (or second 20 products for page 2, and so on). It then becomes immediately apparent that in order to display the first 20 'green' products, we need to go beyond the first page.

The solution here was to trick the pagination function to return all products, but then to stop displaying products after we have found the first 20 matching ones, or when we get to the last product.

The initial code stores the actual number of products to display on each page and also the first and last elements for the page number we are currently viewing. In addition, it retrieves the list of colours from a comma-separated theme setting and converts it into an array (list).

{%- assign actual_per_page = products_per_page -%}
{%- assign products_per_page = 99999 -%}

{%- assign first = current_page | minus: 1 | times: actual_per_page -%}
{%- assign last = first | plus: actual_per_page | minus: 1 -%}
{%- assign total = collection.all_products_count -%}
{%- assign counter = 0 -%}

{%- assign colours = section.settings.colours | split: ',' -%}

Then, we loop through all the products in the collection, looking for products tagged with the current colour whilst also checking if we need to start or stop displaying products (depending on page number). Below is a simplified version of the code:

{% paginate collection.products by products_per_page %}
  {%- assign counter = 0 -%}
  {%- assign colours = section.settings.colours | split: ',' -%}

  {%- for colour in colours -%}
    {%- for product in collection.products -%}

      {%- if counter >= last or counter >= total -%}
        {%- break -%}
      {%- endif -%}

      {%- if product.tags contains colour -%}
        {%- increment counter -%}
        {%- if counter >= first -%}
          {% include 'product-list-item', product: product %}
        {%- endif -%}
      {%- endif -%}

      {%- if counter >= last or counter >= total -%}
        {%- break -%}
      {%- endif -%}

    {%- endfor -%}
  {%- endfor -%}
{% endpaginate %}

As we've tampered with the {% paginate %} function, we now need to manually generate the next and previous links as well as the page numbering:

<ul class="pagination">

  {%- capture base -%}{{ canonical_url | split: '?page=' | first }}?page={%- endcapture -%}

  {%- if first > 0 -%}
    <li class="previous"><a href="{{ base }}{{ first | divided_by: actual_per_page }}">Previous</a></li>
  {%- endif -%}

  {%- assign pages = total | divided_by: actual_per_page | ceil | plus: 1 -%}
  {%- for page in (1..pages) -%}
    <li{% if current == page %} class="active"{% endif %}><a href="{{ base }}{{ page }}">{{ page }}</a></li>
  {%- endfor -%}

  {%- if counter < total -%}
    <li class="next"><a href="{{ base }}{{ first | divided_by: actual_per_page | plus: 2 }}">Next</a></li>
  {%- endif -%}


To complete the functionality, we then added a dropdown box whereby customers could filter the collection by a specific colour.

It must be pointed out that this type of code can drastically increase load times for large inventories due to the nature of looping all the products in the collection on every page view, however it has a negligible affect on small to medium collections.

This version of the code is also case sensitive. In the production environment, we used the 'downcase' Liquid filter to normalise the colours and used the following format for the tags: "colour_Red". That way, we could omit those tags from other areas of the site and ensure we are getting exact matches on the colour tags that we're searching for.

To view the code in action, head over to the Birdie Fortescue store.

Want to find out more?

If you'd like to find out more about how Shopify could help your business or to discuss your project in more detail with us, then get in touch today.