The Curious Case of the Undocumented Where Functionality
I was reading some chatter on the Shopify Partner Slack recently about the recently added liquid where
filter. Anybody who’s used Jekyll before might be used to it already, but it was only added to the Shopify flavour of liquid a few months ago. It turns out that this filter has an undocumented use that’s quite handy.
Who, What, Where?
The where
filter is used to filter arrays on objects. It takes 2 arguments: a property to check, and a value the property must match. For example, if you imagine that you’re creating a collection template for a clothes store, and you want to create a row of t shirts at the top, you could use the following snippet:
{% assign t_shirts = collection.products | where: 'type', 't shirt' %}
{% for t_shirt in t_shirts %}
{% include 'featured-product', product: t_shirt %}
{% endfor %}
In this example, the t_shirts
array will only contain products with a “type” of “t shirt”.
Great, so what’s the alternative method?
The discussion on Slack caught my eye, because somebody reported that they could check for the existence of a tag by passing only one argument. For example:
{% assign is_t_shirt = product.tags | where: 't-shirt' %}
Here, the where
filter is just checking for the existence of t-shirt
within the tags
array. This isn’t extremely useful in and of itself, but it did spark my curiosity.
Often tags are used to determine whether or not to render certain elements in a template, or they will affect an element being rendered based on their value. An example of this is how tags might be used for colour swatches. The following isn’t uncommon, using the following tag pattern colour <colour>
:
{% for tag in product.tags %}
{% if tag contains 'colour ' %}
{% assign swatch = tag | remove_first: 'colour ' %}
{% endfor %}
{% endfor %}
{% if swatch %}
{% include 'swatch' %}
{% endif %}
As it turns out, the where
filter essentially has the same functionality as the for-if
logic above. Using where
, it can be changed to:
{%
assign swatch = product.tags
| where: 'colour '
| first
| remove_first: 'colour '
%}
Despite the product tag being colour orange
, where
will still match the tag, because it includes the string it’s searching for. If you exclude the first
and remove_first
filters, you can print the tag(s) it returns still, but it’s interesting to note.
When just one argument is passed to the filter, it doesn’t match strings exactly, instead it compares strings by checking to see if they contain the provided string. This means it can be used on other properties too, such as description
, though I’m not aware of any great uses for those.
It’s worth noting though, the three filters provided in the example above must be used if you plan to retrieve a value from the tag. The where
filter actually returns an array, though you might not realise if you don’t apply any other filters. By using remove_first:
, the array then gets printed as if it’s a JSON array, hence, first
must be used so that we are only modifying the value of the first array item, rather than the whole array. If more than one item is contained within the array, remove_first:
will only remove the string from the first tag to contain it.
{%- assign swatch = product.tags | where: 'colour ' -%}
prints "colour orange"
{%- assign swatch = product.tags | where: 'colour ' | remove_first: 'colour' -%}
prints "["orange"]"
{%- assign swatch = product.tags | where: 'colour ' | first | remove_first: 'colour' -%}
prints "orange"