Skip to documentation content

Conditions Overview

Conditions Overview

How conditions work in Liquid: subject, operator, and operand, with comparison and type operators.

There are a few methods that evaluate objects based on conditions. The most basic and common of these is the {% if %} method. Each condition has 3 components:
• The subject: The object which you are checking the condition against. This is the only part of the condition that is required.
• The operator: Describes the type of conditional check you would like to perform. If there is no operator, the condition will return true if the left object exists and is non-null.
• The operand: The final argument for the condition. For comparison operators (==, !=, <>, <=, >=, contains, etc...) the operand is required and should be a second object to check against. For type operators (is_valid, is_boolean, is_date, etc...) the operand is not required. Some of the type operators (is_boolean, is_date, is_list, and is_number) may return a different result if you supply true as the operand.

Combining conditions with and and or
Several conditions may be joined in one {% if %} with and and or. The order those operators are applied in is unspecified and unstable, and it may change in future releases, so do not mix and and or in one conditional: a condition that mixes them may not group the way it reads, and may not group the same way twice. Nest {% if %} methods instead. The nesting says exactly which test runs inside which, it is safe against any future change, and it stays readable for whoever edits the template next.

==

Returns true if the subject and operand are equal.

Example Compare a field to one value with ==Equality is the plainest condition: one subject, one operand, and a block that runs when they match.
Liquid
{%- if entity.review_status.value == 'archived' -%}
	<p class="notice">This article is archived and may be out of date.</p>
{%- endif -%}

!=

Returns true if the subject and operand are NOT equal. This is identical to the <> condition.

Example Combine != with another testUse != as one part of a compound condition, where the whole test has to pass before the block runs.
Liquid
{%- var show_tags = entity.show_tags.checked -%}
{%- if show_tags and entity.layout.value != 'full-width' -%}
	{%- include "_tag_list" -%}
{%- endif -%}

<>

Returns true if the subject and operand are NOT equal. This is identical to the != condition.

Example Compare with the <> form of not equal<> is not equal. It behaves exactly like !=, and reads best as one half of a compound condition.
Liquid
{%- if entity.show_nav.checked and request.query_params.view <> 'print' -%}
	{%- include "_main_nav" -%}
{%- endif -%}

>

Returns true if the subject is greater than the operand. If the subject and operand are not the same object type (eg: number and string) then the template will attempt to convert the operand to the same type as the subject before the comparison.

Example Show a link only past a count with >Compare a count with > so the extra link appears only when the list was actually cut short.
Liquid
{%- blog_posts posts = blog:'news' start:1 limit:3 -%}
{%- for post in posts -%}
	<h3>{{ post.linked_title }}</h3>
{%- endfor -%}
{%- if posts.total_pages > 1 -%}
	<a href="/news">See all {{ posts.total_count }} posts</a>
{%- endif -%}

>=

Returns true if the subject is greater than or equal to the operand. If the subject and operand are not the same object type (eg: number and string) then the template will attempt to convert the operand to the same type as the subject before the comparison.

Example Include the boundary with greater than or equal toUse >= when the threshold itself should pass the test.
Liquid
{%- var order_total = session.order_total | to_int -%}
{%- if order_total >= 50 -%}
	<p>Your order ships free.</p>
{%- else -%}
	<p>Orders of $50 or more ship free.</p>
{%- endif -%}

<

Returns true if the subject is less than the operand. If the subject and operand are not the same object type (eg: number and string) then the template will attempt to convert the operand to the same type as the subject before the comparison.

Example Branch on less than and less than or equal toTwo boundaries, one page: < 2 means the results all fit, and <= 1 means there is nothing newer to link to.
Liquid
{%- blog_posts posts = blog:'news' limit:10 page:current_page -%}
{%- if posts.total_pages < 2 -%}
	{%- comment %}Everything fits on one page, so there is no pager{% endcomment -%}
{%- else -%}
	<nav class="pager">
		{%- if posts.page <= 1 -%}
			<span class="newer disabled">Newer</span>
		{%- else -%}
			<a class="newer" href="?page={{ posts.page | minus: 1 }}">Newer</a>
		{%- endif -%}
	</nav>
{%- endif -%}

<=

Returns true if the subject is less than or equal to the operand. If the subject and operand are not the same object type (eg: number and string) then the template will attempt to convert the operand to the same type as the subject before the comparison.

Example Branch on less than and less than or equal toTwo boundaries, one page: < 2 means the results all fit, and <= 1 means there is nothing newer to link to.
Liquid
{%- blog_posts posts = blog:'news' limit:10 page:current_page -%}
{%- if posts.total_pages < 2 -%}
	{%- comment %}Everything fits on one page, so there is no pager{% endcomment -%}
{%- else -%}
	<nav class="pager">
		{%- if posts.page <= 1 -%}
			<span class="newer disabled">Newer</span>
		{%- else -%}
			<a class="newer" href="?page={{ posts.page | minus: 1 }}">Newer</a>
		{%- endif -%}
	</nav>
{%- endif -%}

is_valid

Returns false if the subject is null, empty, false, an empty guid, or is a Marketpath CMS object with is_valid == false. Otherwise returns true.

Example Check if an object or value is valid with is_validCheck whether an object or value is valid (non-empty, present) with is_valid before using it.
Liquid
{%- if random_object is_valid -%}
	{%- include "display_random_object" object:random_object -%}
{%- endif -%}

If field.is_valid

Liquid
{%- if field.is_valid -%}
	{{-field.value-}}
{%- endif -%}

Every field and most objects have an is_valid property that can be used to check if the field or object has a valid value (non-null, non-empty, non-false, published entity, etc.). If you expect the field to be an object with an is_valid property, then this is the best way to check if it has a valid value.

If variable is_valid

Liquid
{%- if varname is_valid -%}
	{{-varname-}}
{%- endif -%}

The is_valid conditional expression checks to see if a variable currently holds a valid value (non-null, non-empty, object with is_valid == true, etc.). This works for most cases, whether or not the variable is an object or a simple value

Unless variable is_valid

Liquid
{%- unless varname is_valid -%}
	... do something if varname is NOT valid...
{%- endunless -%}

The unless conditional makes it easy to do something if the is_valid condition does NOT evaluate to true

is_valid conditional when used on false values

Liquid
{%- var falsevar = false -%}
{%- if falsevar is_valid -%}
	false is_valid evaluates to TRUE!
{%- else -%}
	this will never be output
{%- endif -%}

When using the is_valid condition on a false value, it will evaluate to true. This is by design, allowing the is_valid condition to be used to check whether or not a boolean variable has been defined

is_string

Returns true if the subject is a string.

Example Handle a parameter that may arrive as a string or a numberA partial cannot see what its caller passed, so test the parameter before using it.
Liquid
{%- comment %}start may be passed as a letter or as a position in the alphabet{% endcomment -%}
{%- if start is_string -%}
	<p>This example starts at {{ start }}.</p>
{%- elsif start is_number -%}
	{%- var start_char = 'abcdefghijklmnopqrstuvwxyz' | slice: start, 1 -%}
	<p>This example starts at {{ start_char | default: 'the end' }}.</p>
{%- endif -%}

is_boolean

Returns true if the subject is true or false. If the operand is true, will check if the subject is a string that can be safely converted to true or false (eg: {% if subject is_boolean true %}).

Example Handle a parameter that may arrive as a boolean or a dateTwo callers, two shapes: one passes a flag, the other passes the date the flag would become true.
Liquid
{%- comment %}available may be passed as true/false, or as the date it opens{% endcomment -%}
{%- if available is_boolean -%}
	{%- if available -%}
		<span class="status">Available now</span>
	{%- else -%}
		<span class="status">Not available</span>
	{%- endif -%}
{%- elsif available is_date -%}
	<span class="status">Available {{ available | date: 'MMMM d' }}</span>
{%- endif -%}
Example Use the true operand to test a conversionis_number, is_boolean, and is_date take a true operand, which asks whether a string could be converted safely rather than what it already is.
Liquid
{%- comment %}Everything in the query string arrives as a string{% endcomment -%}
{%- var raw_count = request.query_params.count -%}
{%- var raw_since = request.query_params.since -%}
{%- var limit = 10 -%}
{%- if raw_count is_number true -%}
	{%- set limit = raw_count | to_int -%}
{%- endif -%}
{%- if raw_since is_date true -%}
	{%- blog_posts posts = start_date:raw_since limit:limit -%}
{%- else -%}
	{%- blog_posts posts = limit:limit -%}
{%- endif -%}

is_number

Returns true if the subject is a number. Note that a number may be 0, an integer, decimal, or a fractional number. If the operand is true, will check if the subject is a string that can be safely converted to a number (eg: {% if subject is_number true %}).

Example Handle a parameter that may arrive as a string or a numberA partial cannot see what its caller passed, so test the parameter before using it.
Liquid
{%- comment %}start may be passed as a letter or as a position in the alphabet{% endcomment -%}
{%- if start is_string -%}
	<p>This example starts at {{ start }}.</p>
{%- elsif start is_number -%}
	{%- var start_char = 'abcdefghijklmnopqrstuvwxyz' | slice: start, 1 -%}
	<p>This example starts at {{ start_char | default: 'the end' }}.</p>
{%- endif -%}
Example Use the true operand to test a conversionis_number, is_boolean, and is_date take a true operand, which asks whether a string could be converted safely rather than what it already is.
Liquid
{%- comment %}Everything in the query string arrives as a string{% endcomment -%}
{%- var raw_count = request.query_params.count -%}
{%- var raw_since = request.query_params.since -%}
{%- var limit = 10 -%}
{%- if raw_count is_number true -%}
	{%- set limit = raw_count | to_int -%}
{%- endif -%}
{%- if raw_since is_date true -%}
	{%- blog_posts posts = start_date:raw_since limit:limit -%}
{%- else -%}
	{%- blog_posts posts = limit:limit -%}
{%- endif -%}

is_date

Returns true if the subject is a date object. If the operand is true,will check if the object is a string that can be safely converted to true or false (eg: {% if subject is_date true %}).

Example Handle a parameter that may arrive as a boolean or a dateTwo callers, two shapes: one passes a flag, the other passes the date the flag would become true.
Liquid
{%- comment %}available may be passed as true/false, or as the date it opens{% endcomment -%}
{%- if available is_boolean -%}
	{%- if available -%}
		<span class="status">Available now</span>
	{%- else -%}
		<span class="status">Not available</span>
	{%- endif -%}
{%- elsif available is_date -%}
	<span class="status">Available {{ available | date: 'MMMM d' }}</span>
{%- endif -%}
Example Use the true operand to test a conversionis_number, is_boolean, and is_date take a true operand, which asks whether a string could be converted safely rather than what it already is.
Liquid
{%- comment %}Everything in the query string arrives as a string{% endcomment -%}
{%- var raw_count = request.query_params.count -%}
{%- var raw_since = request.query_params.since -%}
{%- var limit = 10 -%}
{%- if raw_count is_number true -%}
	{%- set limit = raw_count | to_int -%}
{%- endif -%}
{%- if raw_since is_date true -%}
	{%- blog_posts posts = start_date:raw_since limit:limit -%}
{%- else -%}
	{%- blog_posts posts = limit:limit -%}
{%- endif -%}

is_list

Returns true if the subject is a list. If supplied, the operand is ignored. Note that while it is possible to enumerate through the characters in a string, a string will return false for the is_list condition.

Example Loop over POST parametersIterate over request.post_params (e.g. form fields) to list or process each parameter.
Liquid
<h4>Post Parameters</h4>
<dl>
{%- for param in request.post_params -%}
	<dt>{{param}}</dt>
	<dd>
		{%- if request.post_params.by_name[param] is_list -%}
			<ul>
				{%- for value in request.post_params.by_name[param] -%}
					<li>{{ value }}</li>
				{%- endfor -%}
			</ul>
		{%- else -%}
			{{- request.post_params.by_name[param] -}}
		{%- endif -%}
	</dd>
{%- endfor -%}
</dl>

is_simple_type

Returns true if the subject is a string, date, number, or boolean.

Example Separate a complex object from a simple valueis_object is true for a value with properties of its own; is_simple_type is true for a string, date, number, or boolean.
Liquid
{%- comment %}author may be an author object or just a name{% endcomment -%}
{%- if author is_object -%}
	<a href="{{ author.url }}">{{ author.first_name }} {{ author.last_name }}</a>
{%- elsif author is_simple_type -%}
	<span>{{ author }}</span>
{%- endif -%}

is_object

Returns true if the subject is a complex object (ie: if the object has its own properties). By default, is_object will return false for lists that do not have additional properties. However, if the operand is true, is_object will return true for lists as well as complex objects. Note that many objects may be treated as both complex objects and lists and those objects will always return true for the is_object condition.

Example Separate a complex object from a simple valueis_object is true for a value with properties of its own; is_simple_type is true for a string, date, number, or boolean.
Liquid
{%- comment %}author may be an author object or just a name{% endcomment -%}
{%- if author is_object -%}
	<a href="{{ author.url }}">{{ author.first_name }} {{ author.last_name }}</a>
{%- elsif author is_simple_type -%}
	<span>{{ author }}</span>
{%- endif -%}
Example Use the true operand so a list counts as an objectis_object is false for a plain list until you pass true as the operand.
Liquid
{%- comment %}By default a plain list is not an object{% endcomment -%}
{%- if selection is_object -%}
	<p>One record: {{ selection.title }}</p>
{%- elsif selection is_object true -%}
	<p>{{ selection | size }} records</p>
{%- endif -%}

has_key

For lists of key value pairs, returns true if the subject has the operand key.

Example Include sidebar template unless a query param is falseInclude a sidebar template only when a query parameter is not false, using unless.
Liquid
{%- unless request.query_params contains "show_sidebar=false" -%}
	{%- if request.query_params has_key "show_sidebar" -%}
		{%- include "_custom_sidebar" type:request.query_params.show_sidebar -%}
	{%- else -%}
		{%- include "_default_sidebar" type:request.query_params.show_sidebar -%}
	{%- endif -%}
{%- endunless -%}

has_value

For lists of key value pairs, returns true if the subject has the operand value.

Example Match on the value rather than the key with has_valuehas_value searches the values of a key/value list, where has_key searches the keys.
Liquid
{%- comment %}Any parameter set to print turns on the print stylesheet{% endcomment -%}
{%- if request.query_params has_value 'print' -%}
	<link rel="stylesheet" href="/css/print.css">
{%- endif -%}

contains

If the subject is a string, will return true if the subject contains the operand as a string. If the subject is a list, will return true if the subject contains the operand. This is most useful for strings and for lists of strings.

Example Include sidebar template unless a query param is falseInclude a sidebar template only when a query parameter is not false, using unless.
Liquid
{%- unless request.query_params contains "show_sidebar=false" -%}
	{%- if request.query_params has_key "show_sidebar" -%}
		{%- include "_custom_sidebar" type:request.query_params.show_sidebar -%}
	{%- else -%}
		{%- include "_default_sidebar" type:request.query_params.show_sidebar -%}
	{%- endif -%}
{%- endunless -%}
Example contains on a list rather than a stringGiven a list, contains asks whether one whole item matches; given a string, it asks whether the text appears anywhere inside.
Liquid
{%- var labels = item.label_list.value | split: ',' -%}
{%- if labels contains 'featured' -%}
	<span class="badge">Featured</span>
{%- endif -%}

starts_with

If the subject is a string, will return true if the string starts with the operand as a string. If the subject is a list, will return true if the first item in the list is the operand.

Example Tell an internal link from an external one with starts_withstarts_with tests the beginning of a string, which is enough to tell a site-relative link from an absolute one.
Liquid
{%- var href = item.cta_link.value -%}
{%- if href starts_with '/' -%}
	<a href="{{ href }}">Read more</a>
{%- else -%}
	<a href="{{ href }}" target="_blank" rel="noopener">Read more</a>
{%- endif -%}
Example starts_with and ends_with on a listGiven a list rather than a string, starts_with tests the first item and ends_with tests the last one.
Liquid
{%- var segments = request.path | remove_first: '/' | split: '/' -%}
{%- if segments starts_with 'docs' -%}
	{%- include "_docs_breadcrumbs" -%}
{%- endif -%}
{%- if segments ends_with 'archive' -%}
	{%- include "_archive_header" -%}
{%- endif -%}

ends_with

If the subject is a string, will return true if the subject ends with the operand as a string. If the subject is a list, will return true if the last item in the list is the operand.

Example Match a file extension with ends_withends_with tests the end of a string, which is how you match a file extension.
Liquid
{%- var display_name = entity.attachment_text.value -%}
{%- var file_url = entity.attachment_url.value -%}
<a href="{{ file_url }}">
	{{ display_name }}
	{%- if file_url ends_with '.pdf' -%}
		<span class="badge">PDF</span>
	{%- endif -%}
</a>
Example starts_with and ends_with on a listGiven a list rather than a string, starts_with tests the first item and ends_with tests the last one.
Liquid
{%- var segments = request.path | remove_first: '/' | split: '/' -%}
{%- if segments starts_with 'docs' -%}
	{%- include "_docs_breadcrumbs" -%}
{%- endif -%}
{%- if segments ends_with 'archive' -%}
	{%- include "_archive_header" -%}
{%- endif -%}