Conditionals and Operators

Conditionals work similarly to most programming languages.

{% assign age = 15 %}

{% if age > 18 %}
  You are an adult
{% elsif age > 12 %}
  You are a teenager
{% else %}
  You are a child
{% endif %}

Note the spelling of elsif.

There are no parentheticals allowed in Liquid. Any parenthetical logic needs to be created using nested conditionals.

If opposite of if is unless.

{% assign age = 19 %}

{% unless age > 17 %}
  You are not an adult
{% endunless %}

Operators

Equality is a double ==. Inequality is either != or <>

Other mathematical operators work as expected.

{% if age == 18 %}
{% if age <> 18 %}
{% if age != 18 %}
{% if age > 18 %}
{% if age < 18 %}
{% if age >= 18 %}
{% if age <= 18 %}

There is a contains operator. It works differently for three different types of values:

  • For a string it looks for the input string in the target string
  • For a simple array it looks for an element value of the input in the target array
  • For a dictionary it looks for the key of the input in the target dictionary

For any other type, it will return false.

There are also startswith and endswith operators.

  • For a string, it looks for the input string on either the start or end of the target string
  • For a simple array, it looks for the input string as an element value on either the start or the end of the target array

Some examples:

{% if name startswith "D" %}
{% if children contains "Alec" %}
{% if days endswith "Sunday" %}

Operators are customizable.

All the operators are simply registered in the parser. For example.

RegisteredOperators["startswith"] = (a, b) => new StartsWithBinaryExpression(a, b);
RegisteredOperators["endswith"] = (a, b) => new EndsWithBinaryExpression(a, b);
RegisteredOperators["=="] = (a, b) => new EqualBinaryExpression(a, b);
RegisteredOperators["!="] = (a, b) => new NotEqualBinaryExpression(a, b);
RegisteredOperators["<>"] = (a, b) => new NotEqualBinaryExpression(a, b);

(Note the exact same class mapped to both != and <>.)

We can write our own operators to create custom logic and behavior. For example, if we wanted to test whether a value is a direct multiple of another value, we could do this:

public class IsMultipleOfBinaryExpression : BinaryExpression
{
  public IsMultipleOfBinaryExpression(Expression left, Expression right) : base(left, right) { }

  public override async ValueTask<FluidValue> EvaluateAsync(TemplateContext context)
  {
    var leftValue = await Left.EvaluateAsync(context);
    var rightValue = await Right.EvaluateAsync(context);
    return BooleanValue.Create(leftValue.ToNumberValue() % rightValue.ToNumberValue() == 0); 
  }
}

Then we map it to an operator.

parser.RegisteredOperators["ismultipleof"] = (a,b) => new IsMultipleOfBinaryExpression(a, b);

Now we can use this syntax.

{% assign age = 50 %}
{% if age ismultipleof 10 %}
  This is a milestone year for you!
{% endif %}

There is another example of this at the end of the chapter on checking for values.