Twig Conditionals

Complete guide to conditional statements in Total CMS Twig templates for controlling template flow based on dynamic data.

Overview

Conditional statements allow you to control the flow of your templates based on dynamic data. In Twig, you can use the {% if %} tag to test conditions and display content accordingly.

Basic syntax:

{% if condition %}
    Content to display if true
{% endif %}

With else:

{% if condition %}
    Content when true
{% else %}
    Content when false
{% endif %}

With elseif:

{% if condition1 %}
    Content for condition 1
{% elseif condition2 %}
    Content for condition 2
{% else %}
    Default content
{% endif %}

Basic Comparisons

Has Value (Truthy Test)

Tests if a variable has a "truthy" value. For booleans, it checks true/false. For variables, it returns false if undefined, null, empty string, empty array, or the number 0.

{% if post.draft %}
    This post is a draft
{% endif %}

Not (Negation)

Inverts the condition - returns true when the value is false or falsy.

{% if not post.featured %}
    This post is not featured
{% endif %}

String Equality

Checks if a string value exactly matches another string.

{% if page.name == "home" %}
    Welcome to the home page
{% endif %}

Boolean Comparison

Explicitly compares a boolean value. Can use == true or == false.

{% if blog.featured == true %}
    This is a featured post
{% endif %}

Numeric Comparisons

Compare numbers using operators: >, <, >=, <=, ==, !=

{% if product.inventory >= 10 %}
    In stock
{% elseif product.inventory > 0 %}
    Low stock
{% else %}
    Out of stock
{% endif %}

Not Equal

Checks if values are not equal using != operator.

{% if user.role != "guest" %}
    Welcome back, member!
{% endif %}

Existence & Type Checks

Variable Defined

Check if a variable has been defined in the template context.

{% if myobject is defined %}
    Object exists
{% endif %}

{% if myobject is not defined %}
    Object does not exist
{% endif %}

Null Check

Check if a variable is null (explicitly set to null, not just undefined).

{% if user.avatar is null %}
    <img src="default-avatar.png">
{% else %}
    <img src="{{ user.avatar }}">
{% endif %}

Empty Check

Tests if a variable is empty (empty string, empty array, or false).

{% if object.tags is empty %}
    No tags available
{% else %}
    {% for tag in object.tags %}
        {{ tag }}
    {% endfor %}
{% endif %}

File Exists

Check if a file exists in your Total CMS file system.

{% if fileExists('documents/report.pdf') %}
    <a href="documents/report.pdf">Download Report</a>
{% endif %}

Image Exists

Check if an image property exists for an object before attempting to display it.

{% if imageExists(post.image) %}
    {{ cms.image(post.id, {collection: 'blog', property: 'image'}) }}
{% else %}
    <img src="placeholder.jpg">
{% endif %}

Combining Conditions

OR - Either Condition

Returns true if either condition is true. You can chain multiple OR conditions.

{% if user.role == "editor" or user.role == "admin" %}
    You have editing permissions
{% endif %}

AND - Both Conditions

Returns true only if all conditions are true. You can chain multiple AND conditions.

{% if post.published == true and post.date < "now"|date %}
    This post is live
{% endif %}

Complex Combinations

Use parentheses to group conditions and control evaluation order.

{% if (user.role == "admin" or user.role == "editor") and post.draft == false %}
    Show edit button
{% endif %}

Array & Collection Tests

Value in Array

Check if a value exists within an array of values.

{% if post.category in ["news", "updates", "announcements"] %}
    This is a news-related post
{% endif %}

Array Contains Value (Reverse)

Check if an array variable contains a specific value.

{% if "admin" in user.groups %}
    Administrator access granted
{% endif %}

Array Length

Check the number of items in an array using the length filter.

{% if post.tags|length > 0 %}
    Tags: {{ post.tags|join(', ') }}
{% endif %}

{% if gallery.images|length >= 10 %}
    This gallery has {{ gallery.images|length }} images
{% endif %}

Collection Has Objects

Check if a collection has any objects before looping.

{% set posts = cms.objects('blog') %}
{% if posts|length > 0 %}
    {% for post in posts %}
        {{ post.title }}
    {% endfor %}
{% else %}
    No blog posts found
{% endif %}

Iterable Test

Check if a variable can be iterated over (arrays, objects, etc.).

{% if items is iterable %}
    {% for item in items %}
        {{ item }}
    {% endfor %}
{% endif %}

String Operations

Starts With

Check if a string begins with a specific substring.

{% if product.sku starts with "PROD-" %}
    Standard product
{% endif %}

Ends With

Check if a string ends with a specific substring.

{% if user.email ends with "@example.com" %}
    Internal user account
{% endif %}

Contains (Using 'in')

Check if a string contains a substring. Use |lower for case-insensitive matching.

{% if "urgent" in post.title|lower %}
    <span class="badge urgent">Urgent</span>
{% endif %}

Regular Expression Match

Test if a string matches a regular expression pattern. Use double backslashes for escape sequences.

{% if user.phone matches '/^[\\d\\.\\-\\(\\)\\s]+$/' %}
    Valid phone format
{% endif %}

{% if post.title matches '/\\d{4}/' %}
    Title contains a year
{% endif %}

Date & Time Comparisons

Date Before Now

Compare a date field to the current date/time.

{% if event.date < "now"|date %}
    This event has passed
{% endif %}

Date After Specific Date

Compare a date to a specific date string.

{% if post.date > "2024-01-01"|date %}
    Posted this year
{% endif %}

Date Range

Check if a date falls within a specific range. Use modifiers like +7 days, -1 month, etc.

{% if event.date >= "now"|date and event.date <= "+7 days"|date %}
    Happening this week
{% endif %}

Date Between Two Dates

Store dates in variables for cleaner comparisons.

{% set startDate = "2024-06-01"|date %}
{% set endDate = "2024-08-31"|date %}
{% if event.date >= startDate and event.date <= endDate %}
    Summer event
{% endif %}

Total CMS Specific Tests

Object Exists

Check if an object exists before using it.

{% set page = cms.object('pages', 'about') %}
{% if page %}
    {{ page.content }}
{% else %}
    Page not found
{% endif %}

Toggle State

Check a toggle's state from your Total CMS settings.

{% if cms.toggle('maintenance-mode') %}
    <div class="alert">Site under maintenance</div>
{% endif %}

Config Value

Access and test configuration values.

{% if cms.config('debug') == true %}
    Debug mode is enabled
{% endif %}

Environment Check

Check which environment the site is running in.

{% if cms.env == 'development' %}
    <div class="debug-bar">Development Mode</div>
{% endif %}

User Authentication

Check if a user is logged in.

{% if cms.user %}
    Welcome back, {{ cms.user.name }}!
{% else %}
    <a href="/login">Login</a>
{% endif %}

User Permission

Check if the logged-in user has specific roles or permissions.

{% if cms.user and "editor" in cms.user.roles %}
    <a href="/admin/edit">Edit Content</a>
{% endif %}

Advanced Tests

Default Values

Provide a default value if the variable is undefined or empty.

{% if product.rating|default(0) >= 4 %}
    Highly rated!
{% endif %}

Even/Odd Tests

Test if a number is even or odd. Useful for alternating row styles.

{% for post in posts %}
    <div class="{% if loop.index is even %}even{% else %}odd{% endif %}">
        {{ post.title }}
    </div>
{% endfor %}

Divisible By

Check if a number is divisible by another number. Great for grid layouts.

{% for item in items %}
    {{ item.name }}
    {% if loop.index is divisible by(3) %}
        </div><div class="row">
    {% endif %}
{% endfor %}

Same As

Check if two variables reference the exact same object (identity check, not equality).

{% if currentPage is same as(homePage) %}
    <span class="active">Home</span>
{% endif %}

Constant Check

Check if a value matches a defined constant.

{% if status is constant('STATUS_ACTIVE') %}
    Active status
{% endif %}

Ternary Operator

Inline conditional using the ternary operator condition ? true : false.

{{ post.featured ? 'Featured Post' : 'Regular Post' }}

{% set cssClass = post.published ? 'published' : 'draft' %}
<div class="{{ cssClass }}">{{ post.title }}</div>

Null Coalescing

Return the first defined value using the ?? operator. Similar to multiple |default filters.

{{ user.nickname ?? user.name ?? 'Guest' }}

{% set displayName = user.preferredName ?? user.firstName ?? user.username %}

Loop-Specific Conditionals

First Item

Check if current iteration is the first item in the loop.

{% for post in posts %}
    {% if loop.first %}
        <div class="featured">{{ post.title }}</div>
    {% else %}
        <div class="regular">{{ post.title }}</div>
    {% endif %}
{% endfor %}

Last Item

Check if current iteration is the last item (useful for adding separators).

{% for item in items %}
    {{ item.name }}{% if not loop.last %}, {% endif %}
{% endfor %}

Loop Index

Use loop.index (1-based) or loop.index0 (0-based) to check position.

{% for post in posts %}
    {% if loop.index <= 3 %}
        <div class="top-post">{{ post.title }}</div>
    {% endif %}
{% endfor %}

Loop Length

Access the total number of items being looped through.

{% for post in posts %}
    Post {{ loop.index }} of {{ loop.length }}
{% endfor %}

Best Practices

Always Check Object Existence

Always check if objects exist before accessing their properties to avoid errors:

{% set post = cms.object('blog', 'my-post') %}
{% if post %}
    {{ post.title }}
{% endif %}

Use Variables for Complex Conditions

Make complex conditions more readable by using variables:

{% set isAdmin = cms.user and "admin" in cms.user.roles %}
{% set isPublished = post.published and post.date <= "now"|date %}

{% if isAdmin or isPublished %}
    {{ post.content }}
{% endif %}

Combine Existence and Value Checks

For safety, combine existence and value checks:

{% if post.gallery is defined and post.gallery is not empty %}
    {{ cms.gallery(post.id) }}
{% endif %}

Performance Considerations

Avoid calling CMS functions multiple times in conditions:

{# Bad - calls function multiple times #}
{% if cms.objects('blog')|length > 0 %}
    {{ cms.objects('blog')|length }} posts
{% endif %}

{# Good - calls function once #}
{% set posts = cms.objects('blog') %}
{% if posts|length > 0 %}
    {{ posts|length }} posts
{% endif %}

Safe Image/File Access

Always check existence before accessing files or images:

{# Check if image exists #}
{% if imageExists(post.image) %}
    {{ cms.image(post.id, {property: 'hero'}) }}
{% endif %}

{# Check if file exists #}
{% if fileExists('downloads/brochure.pdf') %}
    <a href="downloads/brochure.pdf">Download</a>
{% endif %}

Quick Reference

Comparison Operators

Operator Description Example
== Equal to price == 10
!= Not equal to status != "draft"
< Less than age < 18
> Greater than count > 5
<= Less than or equal score <= 100
>= Greater than or equal rating >= 4

Logical Operators

Operator Description Example
and Both conditions true published and featured
or Either condition true admin or editor
not Negate condition not deleted
() Group conditions (a or b) and c

Tests

Test Description Example
defined Variable exists var is defined
null Value is null value is null
empty Value is empty array is empty
even Number is even num is even
odd Number is odd num is odd
iterable Can be looped items is iterable
divisible by Divisible by number num is divisible by(3)
same as Same object a is same as(b)
constant Matches constant x is constant('Y')

String Tests

Test Description Example
starts with String starts with str starts with "hello"
ends with String ends with str ends with ".com"
matches Matches regex str matches '/\\d+/'
in Contains substring "test" in str

Loop Variables

Variable Description Example
loop.index Current iteration (1-based) {{ loop.index }}
loop.index0 Current iteration (0-based) {{ loop.index0 }}
loop.first True if first iteration {% if loop.first %}
loop.last True if last iteration {% if loop.last %}
loop.length Total items in loop {{ loop.length }}
loop.parent Parent loop context {{ loop.parent.index }}

Common Patterns

Safe Navigation

{# Check nested properties safely #}
{% if user is defined and user.profile is defined and user.profile.avatar %}
    {{ user.profile.avatar }}
{% endif %}

{# Or use default values #}
{{ user.profile.avatar|default('default.jpg') }}

Multiple Fallbacks

{# Try multiple sources #}
{% set title = page.customTitle ?? page.title ?? 'Untitled' %}

{# Or with if statements #}
{% if page.customTitle %}
    {{ page.customTitle }}
{% elseif page.title %}
    {{ page.title }}
{% else %}
    Untitled
{% endif %}

Conditional Classes

{# Single condition #}
<div class="post {{ post.featured ? 'featured' : '' }}">

{# Multiple conditions #}
<div class="post
    {% if post.featured %}featured{% endif %}
    {% if post.draft %}draft{% endif %}
    {% if post.urgent %}urgent{% endif %}">

{# Complex logic #}
{% set statusClass = post.published ? 'published' : (post.draft ? 'draft' : 'pending') %}
<div class="post {{ statusClass }}">

Access Control

{# Check user permissions #}
{% set canEdit = cms.user and (
    "admin" in cms.user.roles or
    "editor" in cms.user.roles or
    cms.user.id == post.authorId
) %}

{% if canEdit %}
    <a href="/edit/{{ post.id }}">Edit</a>
{% endif %}

Smart Defaults

{# Provide sensible defaults #}
{% set perPage = request.query.limit|default(10) %}
{% set sortBy = request.query.sort|default('date') %}
{% set order = request.query.order|default('desc') %}

{# Validate and constrain values #}
{% if perPage > 100 %}
    {% set perPage = 100 %}
{% endif %}