Skip to main content

Liquid Filters

This page documents standard filters that are available with every Environment by default. See custom filters for examples of how to write your own and the extra filter reference for some non-standard filters.

info

Some of the examples here are borrowed from Shopify's Liquid documentation. You can find their license here.

abs

<number> | abs

Return the absolute value of a number. Works on integers, floats and string representations of integers or floats.

{{ -42 | abs }}
{{ 7.5 | abs }}
{{ '42.0' | abs }}
output
42
7.5
42.0

Given a value that can't be cast to an integer or float, 0 will be returned.

{{ 'hello' | abs }}
{{ nosuchthing | abs }}
output
0
0

append

<string> | append: <string>

Return the input value concatenated with the argument value.

{{ 'Hello, ' | append: 'World!' }}
output
Hello, World!

If either the input value or argument are not a string, they will be coerced to a string before concatenation.

{% assign a_number = 7.5 -%}
{{ 42 | append: a_number }}
{{ nosuchthing | append: 'World!' }}
output
427.5
World!

at_least

<number> | at_least: <number>

Return the maximum of the filter's input value and its argument. If either input value or argument are string representations of an integer or float, they will be cast to an integer or float prior to comparison.

{{ -5.1 | at_least: 8 }}
{{ 8 | at_least: '5' }}
output
8
8

If either input value or argument can not be cast to an integer or float, 0 will be used instead.

{{ "hello" | at_least: 2 }}
{{ "hello" | at_least: -2 }}
{{ -1 | at_least: "abc" }}
output
2
0
0

at_most

<number> | at_most: <number>

Return the minimum of the filter's input value and its argument. If either input value or argument are string representations of an integer or float, they will be cast to an integer or float prior to comparison.

{{ 5 | at_most: 8 }}
{{ '8' | at_most: 5 }}
output
5
5

If either input value or argument can not be cast to an integer or float, 0 will be used instead.

{{ "hello" | at_most: 2 }}
{{ "hello" | at_most: -2 }}
{{ -1 | at_most: "abc" }}
output
0
-2
-1

base64_decode

<string> | base64_decode

Decode a base64 encoded string. The decoded value is assumed to be UTF-8 and will be decoded as UTF-8.

caution

While Python Liquid assumes UTF-8 character encoding, Ruby Liquid does not seem to do so, potentially introducing byte strings into the render context.

{{ 'SGVsbG8sIFdvcmxkIQ==' | base64_decode }}
output
Hello, World!

If the input value is not a valid base64 encoded string, an exception will be raised.

{{ 'notbase64' | base64_decode }}
output
FilterError: invalid base64-encoded string, on line 1

base64_encode

<string> | base64_encode

Encode a string using base64.

info

Python Liquid returns a str from base64_encode, not bytes.

{{ 'Hello, World!' | base64_encode }}
output
SGVsbG8sIFdvcmxkIQ==

If the input value is not a string, it will be converted to a string before base64 encoding.

{{ 5 | base64_encode }}
output
NQ==

base64_url_safe_decode

<string> | base64_url_safe_decode

Decode a URL safe base64 encoded string. Substitutes - instead of + and _ instead of / in the standard base64 alphabet. The decoded value is assumed to be UTF-8 and will be decoded as UTF-8.

caution

While Python Liquid assumes UTF-8 character encoding, Ruby Liquid does not seem to do so, potentially introducing byte strings into the render context.

{{ 'SGVsbG8sIFdvcmxkIQ==' | base64_url_safe_decode }}
output
Hello, World!

If the input value is not a valid base64 encoded string, an exception will be raised.

{{ 'notbase64' | base64_url_safe_decode }}
output
FilterError: invalid base64-encoded string, on line 1

base64_url_safe_encode

<string> | base64_url_safe_encode

Encode a string using URL safe base64. Substitutes - instead of + and _ instead of / in the standard base64 alphabet.

info

Python Liquid returns a str from base64_url_safe_encode, not bytes.

{{ 'Hello, World!' | base64_url_safe_encode }}
output
SGVsbG8sIFdvcmxkIQ==

If the input value is not a string, it will be converted to a string before base64 encoding.

{{ 5 | base64_url_safe_encode }}
output
NQ==

capitalize

<string> | capitalize

Return the input string with the first character in upper case and the rest lowercase.

{{ 'heLLO, World!' | capitalize }}
output
Hello, world!

If the input value is not a string, it will be converted to a string.

{{ 42 | capitalize }}
output
42

ceil

<number> | ceil

Round the input value up to the nearest whole number. The input value will be converted to a number if it is not an integer or float.

{{ 5.1 | ceil }}
{{ 5.0 | ceil }}
{{ 5 | ceil }}
{{ '5.4' | ceil }}
output
6
5
5
5

If the input is undefined or can't be converted to a number, 0 is returned.

{{ 'hello' | ceil }}
{{ nosuchthing | ceil }}
output
0
0

compact

<array> | compact[: <string>]

Remove nil (or None in Python) values from an array-like object. If given, the argument should be the name of a property that exists on each object (hash, dict etc.) in the array-like sequence.

If pages is an array of objects, some of which have a category property:

data
{
"pages": [
{ "category": "business" },
{ "category": "celebrities" },
{},
{ "category": "lifestyle" },
{ "category": "sports" },
{},
{ "category": "technology" }
]
}

Without compact, iterating those categories will include nil values.

{% assign categories = pages | map: "category" -%}

{% for category in categories -%}
- {{ category }}
{%- endfor %}
output
- business
- celebrities
-
- lifestyle
- sports
-
- technology

With compact, we can remove those missing categories before the loop.

{% assign categories = pages | map: "category" | compact %}

{% for category in categories %}
- {{ category }}
{% endfor %}
output
- business
- celebrities
- lifestyle
- sports
- technology

Using the optional argument to compact, we could avoid using map and create an array of pages with a category property, rather than an array of categories.

{% assign pages_with_category = pages | compact: "category" %}

{% for page in pages_with_category %}
- {{ page.category }}
{% endfor %}
output
- business
- celebrities
- lifestyle
- sports
- technology

concat

<array> | concat: <array>

Create a new array by joining one array-like object with another.

{% assign fruits = "apples, oranges, peaches" | split: ", " %}
{% assign vegetables = "carrots, turnips, potatoes" | split: ", " %}

{% assign everything = fruits | concat: vegetables %}

{% for item in everything %}
- {{ item }}
{% endfor %}
output
- apples
- oranges
- peaches
- carrots
- turnips
- potatoes

If the input value is not array-like, it will be converted to an array. No conversion is attempted for the argument value.

{% assign fruits = "apples, oranges, peaches" | split: ", " %}
{% assign things = "hello" | concat: fruits %}

{% for item in things %}
- {{ item }}
{% endfor %}
output
- hello
- apples
- oranges
- peaches

If the input is a nested array, it will be flattened before concatenation. The argument is not flattened.

data
{
"a": [
["a", "x"],
["b", ["y", ["z"]]]
],
"b": ["c", "d"]
}
{{ a | concat: b | join: '#' }}
output
a#x#b#y#z#c#d

date

<datetime> | date: <string>

Format a date and/or time according the the given format string. The input can be a string, in which case the string will be parsed as a date/time before formatting.

caution

Python Liquid uses dateutil for parsing strings to datetimes, and strftime for formatting. There are likely to be some inconsistencies between this and Ruby Liquid's Time.parse equivalent parsing and formatting of dates and times.

In general, Python Liquid will raise an exception if the input value can not be converted to a date and/or time. Whereas Ruby Liquid will usually return something without erroring.

{{ "March 14, 2016" | date: "%b %d, %y" }}
output
Mar 14, 16

The special 'now' or 'today' input values can be used to get the current timestamp. 'today' is an alias for 'now'. Both include time information.

{{ "now" | date: "%Y-%m-%d %H:%M" }}
output
2021-12-02 10:17

If the input is undefined, an empty string is returned.

{{ nosuchthing | date: "%Y-%m-%d %H:%M" }}

default

<object> | default[: <object>[, allow_false:<bool>]]

Return a default value if the input is undefined, nil, false or empty, or return the input unchanged otherwise.

info

The default filter is the only built-in filter to use a keyword argument.

{{ product_price | default: 2.99 }}

{%- assign product_price = "" %}
{{ product_price | default: 2.99 }}

{%- assign product_price = 4.99 %}
{{ product_price | default: 2.99 }}
output
2.99
2.99
4.99

If the optional allow_false argument is true, an input of false will not return the default. allow_false defaults to false.

{% assign product_reduced = false -%}
{{ product_reduced | default: true, allow_false: true }}
output
false

If no argument is given, the default value will be an empty string.

{{ product_price | default }}

Empty strings, arrays and objects all cause the default value to be returned. 0 does not.

{{ "" | default: "hello" }}
{{ 0 | default: 99 }}
output
hello
0

divided_by

<number> | divided_by: <number>

Divide a number by another number. The result is rounded down to the nearest integer if the divisor is an integer.

{{ 16 | divided_by: 4 }}
{{ 5 | divided_by: 3 }}
output
4
1

If you divide by a float, the result will be a float.

{{ 20 | divided_by: 7 }}
{{ 20 | divided_by: 7.0 }}
output
2
2.857142857142857

If either the input or argument are not an integer or float, Liquid will try to convert them to an integer or float. If the input can't be converted, 0 will be used instead. If the argument can't be converted, an exception is raised.

{{ "20" | divided_by: "7" }}
{{ "hello" | divided_by: 2 }}
output
2
0

downcase

<string> | downcase

Return the input string with all characters in lowercase.

{{ 'Hello, World!' | downcase }}
output
hello, world!

If the input is not a string, Liquid will convert it to a string before forcing characters to lowercase.

{{ 5 | downcase }}
output
5

If the input is undefined, an empty string is returned.

escape

<string> | escape

Return the input string with characters &, < and > converted to HTML-safe sequences.

{{ "Have you read 'James & the Giant Peach'?" | escape }}
output
Have you read &#39;James &amp; the Giant Peach&#39;?

escape_once

<string> | escape_once

Return the input string with characters &, < and > converted to HTML-safe sequences, while preserving existing HTML escape sequences.

{{ "Have you read 'James &amp; the Giant Peach'?" | escape_once }}
output
Have you read &#39;James &amp; the Giant Peach&#39;?

first

<sequence> | first

Return the first item of the input sequence. The input could be array-like or a mapping, but not a string.

{{ "Ground control to Major Tom." | split: " " | first }}
output
Ground

If the input sequence is undefined, empty or not a sequence, nil is returned.

floor

<number> | floor

Return the input down to the nearest whole number. Liquid tries to convert the input to a number before the filter is applied.

{{ 1.2 | floor }}
{{ 2.0 | floor }}
{{ 183.357 | floor }}
{{ -5.4 | floor }}
{{ "3.5" | floor }}
output
1
2
183
-6
3

If the input can't be converted to a number, 0 is returned.

join

<array> | join[: <string>]

Return the items in the input array as a single string, separated by the argument string. If the input is not an array, Liquid will convert it to one. If input array items are not strings, they will be converted to strings before joining.

{% assign beatles = "John, Paul, George, Ringo" | split: ", " -%}

{{ beatles | join: " and " }}
output
John and Paul and George and Ringo

If an argument string is not given, it defaults to a single space.

{% assign beatles = "John, Paul, George, Ringo" | split: ", " -%}

{{ beatles | join }}
output
John Paul George Ringo

last

<array> | last

Return the last item in the array-like input.

{{ "Ground control to Major Tom." | split: " " | last }}
output
Tom.

If the input is undefined, empty, string or a number, nil will be returned.

lstrip

<string> | lstrip

Return the input string with all leading whitespace removed. If the input is not a string, it will be converted to a string before stripping whitespace.

{{ "          So much room for activities          " | lstrip }}!
output
So much room for activities          !

map

<array> | map: <string>

Extract properties from an array of objects into a new array.

If pages is an array of objects with a category property:

data
{
"pages": [
{ "category": "business" },
{ "category": "celebrities" },
{ "category": "lifestyle" },
{ "category": "sports" },
{ "category": "technology" }
]
}
{% assign categories = pages | map: "category" -%}

{% for category in categories -%}
- {{ category }}
{%- endfor %}
output
- business
- celebrities
- lifestyle
- sports
- technology

minus

<number> | minus: <number>

Subtract one number from another. If either the input or argument are not a number, Liquid will try to convert them to a number. If that conversion fails, 0 is used instead.

{{ 4 | minus: 2 }}
{{ "16" | minus: 4 }}
{{ 183.357 | minus: 12.2 }}
{{ "hello" | minus: 10 }}
output
2
12
171.157
-10

modulo

<number> | modulo: <number>

Return the remainder from the division of the input by the argument.

{{ 3 | modulo: 2 }}
{{ "24" | modulo: "7" }}
{{ 183.357 | modulo: 12 }}
output
1
3
3.357

If either the input or argument are not an integer or float, Liquid will try to convert them to an integer or float. If the input can't be converted, 0 will be used instead. If the argument can't be converted, an exception is raised.

newline_to_br

<string> | newline_to_br

Return the input string with \n and \r\n replaced with <br />\n.

{% capture string_with_newlines %}
Hello
there
{% endcapture %}

{{ string_with_newlines | newline_to_br }}
output


<br />
Hello<br />
there<br />

plus

<number> | plus: <number>

Add one number to another. If either the input or argument are not a number, Liquid will try to convert them to a number. If that conversion fails, 0 is used instead.

{{ 4 | plus: 2 }}
{{ "16" | plus: "4" }}
{{ 183.357 | plus: 12 }}
output
6
20
195.357

prepend

<string> | prepend: <string>

Return the argument concatenated with the filter input.

{{ "apples, oranges, and bananas" | prepend: "Some fruit: " }}
output
Some fruit: apples, oranges, and bananas

If either the input value or argument are not a string, they will be coerced to a string before concatenation.

{% assign a_number = 7.5 -%}
{{ 42 | prepend: a_number }}
{{ nosuchthing | prepend: 'World!' }}
output
7.542
World!

remove

<string> | remove: <string>

Return the input with all occurrences of the argument string removed.

{{ "I strained to see the train through the rain" | remove: "rain" }}
output
I sted to see the t through the

If either the filter input or argument are not a string, they will be coerced to a string before substring removal.

remove_first

<string> | remove_first: <string>

Return a copy of the input string with the first occurrence of the argument string removed.

{{ "I strained to see the train through the rain" | remove_first: "rain" }}
output
I sted to see the train through the rain

If either the filter input or argument are not a string, they will be coerced to a string before substring removal.

remove_last

<string> | remove_last: <string>

Return a copy of the input string with the last occurrence of the argument string removed.

{{ "I strained to see the train through the rain" | remove_last: "rain" }}
output
I strained to see the train through the

If either the filter input or argument are not a string, they will be coerced to a string before substring removal.

replace

<string> | replace: <string>[, <string>]

Return the input with all occurrences of the first argument replaced with the second argument. If the second argument is omitted, it will default to an empty string, making replace behave like remove.

{{ "Take my protein pills and put my helmet on" | replace: "my", "your" }}
output
Take your protein pills and put your helmet on

If either the filter input or argument are not a string, they will be coerced to a string before replacement.

replace_first

<string> | replace_first: <string>[, <string>]

Return a copy of the input string with the first occurrence of the first argument replaced with the second argument. If the second argument is omitted, it will default to an empty string, making replace_first behave like remove_first.

{{ "Take my protein pills and put my helmet on" | replace_first: "my", "your" }}
output
Take your protein pills and put my helmet on

If either the filter input or argument are not a string, they will be coerced to a string before replacement.

replace_last

<string> | replace_last: <string>, <string>

Return a copy of the input string with the last occurrence of the first argument replaced with the second argument.

{{ "Take my protein pills and put my helmet on" | replace_first: "my", "your" }}
output
Take my protein pills and put your helmet on

If either the filter input or argument are not a string, they will be coerced to a string before replacement.

reverse

<array> | reverse

Return a copy of the input array with the items in reverse order. If the filter input is a string, reverse will return the string unchanged.

{% assign my_array = "apples, oranges, peaches, plums" | split: ", " -%}

{{ my_array | reverse | join: ", " }}
output
plums, peaches, oranges, apples

round

<number> | round[: <number>]

Return the input number rounded to the given number of decimal places. The number of digits defaults to 0.

{{ 1.2 | round }}
{{ 2.7 | round }}
{{ 183.357 | round: 2 }}
output
1
3
183.36

If either the filter input or its optional argument are not an integer or float, they will be converted to an integer or float before rounding.

rstrip

<string> | rstrip

Return the input string with all trailing whitespace removed. If the input is not a string, it will be converted to a string before stripping whitespace.

{{ "          So much room for activities          " | rstrip }}!
output
          So much room for activities!

safe

<string> | safe

Return the input string marked as safe to use in an HTML or XML document. If the filter input is not a string, it will be converted to an HTML-safe string.

caution

safe is a non-standard feature added to Python Liquid for use with HTML auto-escaping.

With auto-escape enabled and the following global variables:

data
{
"username": "Sally",
"greeting": "</p><script>alert('XSS!');</script>"
}
template
<p>{{ greeting }}, {{ username }}</p>
<p>{{ greeting | safe }}, {{ username }}</p>
output
<p>&lt;/p&gt;&lt;script&gt;alert(&#34;XSS!&#34;);&lt;/script&gt;, Sally</p>
<p></p><script>alert('XSS!');</script>, Sally</p>

size

<object> | size

Return the size of the input object. Works on strings, arrays and hashes.

{{ "Ground control to Major Tom." | size }}
{{ "apples, oranges, peaches, plums" | split: ", " | size }}
output
28
4

slice

<sequence> | slice: <int>[, <int>]

Return a substring or subsequence of the input string or array. The first argument is the zero-based start index. The second, optional argument is the length of the substring or sequence, which defaults to 1.

{{ "Liquid" | slice: 0 }}
{{ "Liquid" | slice: 2 }}
{{ "Liquid" | slice: 2, 5 }}
{% assign beatles = "John, Paul, George, Ringo" | split: ", " -%}
{{ beatles | slice: 1, 2 | join: " " }}
output
L
q
quid
Paul George

If the first argument is negative, the start index is counted from the end of the sequence.

{{ "Liquid" | slice: -3 }}
{{ "Liquid" | slice: -3, 2 }}
{% assign beatles = "John, Paul, George, Ringo" | split: ", " -%}
{{ beatles | slice: -2, 2 | join: " " }}
output
u
ui
George Ringo

sort

<array> | sort[: <string>]

Return a copy of the input array with its elements sorted.

{% assign my_array = "zebra, octopus, giraffe, Sally Snake" | split: ", " -%}
{{ my_array | sort | join: ", " }}
output
Sally Snake, giraffe, octopus, zebra

The optional argument is a sort key. If given, it should be the name of a property and the filter's input should be an array of objects.

data
{
"collection": {
"products": [
{ "title": "A Shoe", "price": "9.95" },
{ "title": "A Tie", "price": "0.50" },
{ "title": "A Hat", "price": "2.50" }
]
}
}
template
{% assign products_by_price = collection.products | sort: "price" -%}
{% for product in products_by_price %}
<h4>{{ product.title }}</h4>
{% endfor %}
output
<h4>A Tie</h4>
<h4>A Hat</h4>
<h4>A Shoe</h4>

sort_natural

<array> | sort_natural[: <string>]

Return a copy of the input array with its elements sorted case-insensitively. Array elements compared by their string representations, forced to lowercase.

{% assign my_array = "zebra, octopus, giraffe, Sally Snake" | split: ", " -%}
{{ my_array | sort_natural | join: ", " }}
output
giraffe, octopus, Sally Snake, zebra

The optional argument is a sort key. If given, it should be the name of a property and the filter's input should be an array of objects. Array elements are compared using the lowercase string representation of that property.

data
{
"collection": {
"products": [
{ "title": "A Shoe", "company": "Cool Shoes" },
{ "title": "A Tie", "company": "alpha Ties" },
{ "title": "A Hat", "company": "Beta Hats" }
]
}
}
template
{% assign products_by_company = collection.products | sort_natural: "company" %}
{% for product in products_by_company %}
<h4>{{ product.title }}</h4>
{% endfor %}
output
<h4>A Tie</h4>
<h4>A Hat</h4>
<h4>A Shoe</h4>

split

<string> | split: <string>

Return an array of strings that are the input string split on the filter's argument string.

{% assign beatles = "John, Paul, George, Ringo" | split: ", " -%}

{% for member in beatles %}
{{- member }}
{% endfor %}
output
John
Paul
George
Ringo

If the argument is undefined or an empty string, the input will be split at every character.

{{ "Hello there" | split: nosuchthing | join: "#" }}
output
H#e#l#l#o# #t#h#e#r#e

strip

<string> | strip

Return the input string with all leading and trailing whitespace removed. If the input is not a string, it will be converted to a string before stripping whitespace.

{{ "          So much room for activities          " | strip }}!
output
So much room for activities!

strip_html

<string> | strip_html

Return the input string with all HTML tags removed.

{{ "Have <em>you</em> read <strong>Ulysses</strong>?" | strip_html }}
output
Have you read Ulysses?

strip_newlines

<string> | strip_newlines

Return the input string with \n and \r\n removed.

{% capture string_with_newlines %}
Hello
there
{% endcapture -%}

{{ string_with_newlines | strip_newlines }}
output
Hellothere

sum

<array> | sum[: <string>]

New in version 1.9.3

Return the sum of all numeric elements in an array.

{% assign array = '1,2,3' | split: ',' -%}
{{ array | sum }}
output
6

If the optional string argument is given, it is assumed that array items are hash/mapping-like, and the argument should be the name of a property/key. The values at array[property] will be summed.

times

<number> | times: <number>

Return the product of the input number and the argument number. If either the input or argument are not a number, Liquid will try to convert them to a number. If that conversion fails, 0 is used instead.

{{ 3 | times: 2 }}
{{ "24" | times: "7" }}
{{ 183.357 | times: 12 }}
output
6
168
2200.284

truncate

<string> | truncate[: <integer>[, <string>]]

Return a truncated version of the input string. The first argument, length, defaults to 50. The second argument defaults to an ellipsis (...).

If the length of the input string is less than the given length (first argument), the input string will be truncated to length minus the length of the second argument, with the second argument appended.

{{ "Ground control to Major Tom." | truncate: 20 }}
{{ "Ground control to Major Tom." | truncate: 25, ", and so on" }}
{{ "Ground control to Major Tom." | truncate: 20, "" }}
output
Ground control to...
Ground control, and so on
Ground control to Ma

truncatewords

<string> | truncatewords[: <integer>[, <string>]]

Return the input string truncated to the specified number of words, with the second argument appended. The number of words (first argument) defaults to 15. The second argument defaults to an ellipsis (...).

If the input string already has fewer than the given number of words, it is returned unchanged.

{{ "Ground control to Major Tom." | truncatewords: 3 }}
{{ "Ground control to Major Tom." | truncatewords: 3, "--" }}
{{ "Ground control to Major Tom." | truncatewords: 3, "" }}
output
Ground control to...
Ground control to--
Ground control to

uniq

<array> | uniq[: <string>]

Return a copy of the input array with duplicate elements removed.

{% assign my_array = "ants, bugs, bees, bugs, ants" | split: ", " -%}
{{ my_array | uniq | join: ", " }}
output
ants, bugs, bees

If an argument is given, it should be the name of a property and the filter's input should be an array of objects.

data
{
"collection": {
"products": [
{ "title": "A Shoe", "company": "Cool Shoes" },
{ "title": "A Tie", "company": "alpha Ties" },
{ "title": "Another Tie", "company": "alpha Ties" },
{ "title": "A Hat", "company": "Beta Hats" }
]
}
}
template
{% assign one_product_from_each_company = collections.products | uniq: "company" -%}
{% for product in one_product_from_each_company -%}
- product.title
{% endfor %}
output
- A Shoe
- A Tie
- A Hat

upcase

<string> | upcase

Return the input string with all characters in uppercase.

{{ 'Hello, World!' | upcase }}
output
HELLO, WORLD!

url_decode

<string> | url_decode

Return the input string with %xx escapes replaced with their single-character equivalents. Also replaces '+' with ' '.

{{ "My+email+address+is+bob%40example.com%21" | url_decode }}
output
My email address is bob@example.com!

url_encode

<string> | url_encode

Return the input string with URL reserved characters %-escaped. Also replaces ' ' with '+'.

{{ My email address is bob@example.com! | url_encode }}
output
My+email+address+is+bob%40example.com%21

where

<array> | where: <string>[, <object>]

Return a copy of the input array including only those objects that have a property, named with the first argument, equal to a value, given as the second argument. If a second argument is not given, only elements with the named property that are truthy will be included.

data
{
"products": [
{ "title": "Vacuum", "type": "house", "available": true },
{ "title": "Spatula", "type": "kitchen", "available": false },
{ "title": "Television", "type": "lounge", "available": true },
{ "title": "Garlic press", "type": "kitchen", "available": true }
]
}
All products:
{% for product in products -%}
- {{ product.title }}
{% endfor %}

{%- assign kitchen_products = products | where: "type", "kitchen" -%}

Kitchen products:
{% for product in kitchen_products -%}
- {{ product.title }}
{% endfor %}

{%- assign available_products = products | where: "available" -%}

Available products:
{% for product in available_products -%}
- {{ product.title }}
{% endfor %}
output
All products:
- Vacuum
- Spatula
- Television
- Garlic press

Kitchen products:
- Spatula
- Garlic press

Available product:
- Vacuum
- Television
- Garlic press