# Liquid

## DotLiquid on The Wallet Crew template Editor

This guide shows how to use DotLiquid templating inside The Wallet Crew platform to build smarter passes, personalise content, and automate the right message at the right moment.

No developer required for the basics.

### What’s inside

* [The two building blocks](#the-two-building-blocks)
* [Showing a value on a pass](#showing-a-value-on-a-pass)
* [Assign — create your own variable](#assign--create-your-own-variable)
* [if / elsif / else — smart content per customer](#if--elsif--else--smart-content-per-customer)
* [unless — the quiet condition](#unless--the-quiet-condition)
* [Operators — how to compare things](#operators--how-to-compare-things)
* [case / when — clean multi-tier logic](#case--when--clean-multi-tier-logic)
* [Filters — transform any value](#filters--transform-any-value)
* [String filters](#string-filters)
* [Number filters](#number-filters)
* [Array filters](#array-filters)
* [Date formatting](#date-formatting)
* [Date arithmetic](#date-arithmetic)
* [Date flags — is this pass still valid?](#date-flags--is-this-pass-still-valid)
* [now / today](#now--today)
* [Combining date filters](#combining-date-filters)
* [capture — build a message block](#capture--build-a-message-block)

### The two building blocks

Everything in DotLiquid comes down to two types of tags:

```
{{ }}   → Output something. Show it on the pass.
{% %}   → Logic. Conditions, loops, assignments.
```

Everything else is just text that gets printed as-is.

### Showing a value on a pass

{% hint style="info" %}
If you type `{{ }}` you will see a list of the possible variables.
{% endhint %}

Put any data field between `{{ }}` and it shows up on the pass.

```
{{ customer.first_name }}'s Loyalty Card
Points balance: {{ customer.points }}
Member since: {{ customer.signup_date }}
```

**What the customer sees on their pass:**

```
Marie's Loyalty Card
Points balance: 340
Member since: 2023-06-15
```

{% hint style="info" %}
If the field is empty, nothing shows. No error, no blank label.
{% endhint %}

### Assign and create your own variable

Need to compute something, label it, and reuse it? Use `assign`.

```
{% assign tier_label = "Gold Member" %}
Welcome back, {{ tier_label }}.
```

Or build it from existing data:

```
{% assign display_name = customer.first_name | upcase %}
{{ display_name }}, your exclusive offer awaits.
```

### if / elsif / else — smart content per customer

This is where passes get smart. Show different content depending on who’s holding the card.

```
{% if customer.points >= 1000 %}
	Platinum — you unlock free express shipping.
{% elsif customer.points >= 500 %}
	Gold — enjoy free standard shipping over €50.
{% elsif customer.points >= 200 %}
	Silver — 5% off your next visit.
{% else %}
	Welcome! Collect 200 points to reach Silver.
{% endif %}
```

> **Always close with `{% endif %}`.** It is the most common mistake.

Real Wallet Crew use case: show a different back-of-pass message per tier.

```
{% if customer.tier == "VIP" %}
	Priority access to all new collections. Show this pass at checkout.
{% else %}
	Earn 1 point for every €1 spent in store or online.
{% endif %}
```

### unless condition

`unless` runs the block when the condition is **not** true. Great for opt-out logic.

```
{% unless customer.push_disabled == true %}
	Push notifications are active on this pass.
{% endunless %}
```

Reads nicely in plain English: *unless push is disabled, show this.*

### Operators, how to compare things

| Operator   | What it does          | Pass example                           |
| ---------- | --------------------- | -------------------------------------- |
| `==`       | Exactly equal         | `tier == "Gold"`                       |
| `!=`       | Not equal             | `tier != "Standard"`                   |
| `>`        | Greater than          | `points > 500`                         |
| `<`        | Less than             | `points < 100`                         |
| `>=`       | Greater than or equal | `points >= 500`                        |
| `<=`       | Less than or equal    | `points <= 99`                         |
| `and`      | Both must be true     | `points > 100 and active == true`      |
| `or`       | At least one true     | `tier == "Gold" or tier == "Platinum"` |
| `contains` | Includes this value   | `tags contains "event_guest"`          |

### case / when, clean multi-tier logic

When comparing the same field against many possible values, `case` is cleaner than stacking `elsif`.

```
{% case customer.tier %}
	{% when "Platinum" %}
		Benefit: Unlimited free returns + personal shopper.
	{% when "Gold" %}
		Benefit: Free shipping on all orders.
	{% when "Silver" %}
		Benefit: Early access to sales.
	{% else %}
		Benefit: Welcome — earn points on every purchase.
{% endcase %}
```

Perfect for loyalty tiers, event ticket categories, or coupon-type labels.

### Filters, transform any value

Filters change a value before displaying it. Use the `|` pipe:

```
{{ value | filter }}
{{ value | filter: argument }}
```

Chain them left to right:

```
{{ customer.first_name | downcase | capitalize }}
```

### String filters

<table><thead><tr><th width="117.79998779296875">Filter</th><th width="127">What it does</th><th width="262.39996337890625">Example</th><th width="139.5875244140625">Result</th></tr></thead><tbody><tr><td><code>upcase</code></td><td>ALL CAPS</td><td><code>{{ "hello" | upcase }}</code></td><td><code>HELLO</code></td></tr><tr><td><code>downcase</code></td><td>all lowercase</td><td><code>{{ "HELLO" | downcase }}</code></td><td><code>hello</code></td></tr><tr><td><code>capitalize</code></td><td>First letter uppercase</td><td><code>{{ "marie" | capitalize }}</code></td><td><code>Marie</code></td></tr><tr><td><code>strip</code></td><td>Remove surrounding spaces</td><td><code>{{ " hi " | strip }}</code></td><td><code>hi</code></td></tr><tr><td><code>replace</code></td><td>Swap a word</td><td><code>{{ "Bonjour Monde" replace: "Monde", Marie" }}</code></td><td><code>Bonjour Marie</code></td></tr><tr><td><code>truncate</code></td><td>Cut to N characters</td><td><code>{{ "Long message here" | truncate: 10 }}</code></td><td><code>Long me</code></td></tr><tr><td><code>append</code></td><td>Add to the end</td><td><code>{{ "Gold" append: "Member" }}</code></td><td><code>Gold Member</code></td></tr><tr><td><code>prepend</code></td><td>Add to the start</td><td><code>{{ "Member" | prepend: "VIP" }}</code></td><td><code>VIP Member</code></td></tr></tbody></table>

Real example: clean up a name that came in messy from a form.

```
{% assign clean_name = customer.first_name | strip | capitalize %}
Welcome, {{ clean_name }}!
```

### Number filters

| Filter       | What it does        | Example              | Result               |        |
| ------------ | ------------------- | -------------------- | -------------------- | ------ |
| `plus`       | Add                 | `{{ customer.points` | plus: 50 }}\`        | `390`  |
| `minus`      | Subtract            | `{{ customer.points` | minus: 200 }}\`      | `140`  |
| `times`      | Multiply            | `{{ price`           | times: 1.2 }}\`      | `120`  |
| `divided_by` | Divide              | `{{ points`          | divided\_by: 10 }}\` | `34`   |
| `modulo`     | Remainder           | `{{ points`          | modulo: 100 }}\`     | `40`   |
| `round`      | Round to N decimals | `{{ 9.876`           | round: 2 }}\`        | `9.88` |
| `ceil`       | Always round up     | `{{ 9.1`             | ceil }}\`            | `10`   |
| `floor`      | Always round down   | `{{ 9.9`             | floor }}\`           | `9`    |

Show points until next tier:

```
{% assign points_needed = 500 | minus: customer.points %}
{% if points_needed > 0 %}
	{{ points_needed }} points to reach Gold 
{% endif %}
```

### Array filters

| Filter  | What it does                     |
| ------- | -------------------------------- |
| `first` | First item in a list             |
| `last`  | Last item in a list              |
| `size`  | How many items                   |
| `join`  | Combine items into a string      |
| `sort`  | Sort alphabetically or by field  |
| `uniq`  | Remove duplicates                |
| `map`   | Pull one property from all items |
| `where` | Filter items by a field value    |

Show how many rewards a customer has available:

```
You have {{ customer.available_rewards | size }} rewards ready to use.
```

List all active store locations:

```
{{ stores | where: "active", true | map: "city" | join: " · " }}
```

### Date formatting

Apply the `date` filter with a format string to display dates cleanly on a pass.

```
{{ pass.expiry_date | date: "%d/%m/%Y" }}
```

**Format tokens:**

| Token   | What it gives                   | Example     |
| ------- | ------------------------------- | ----------- |
| `%d`    | Day                             | `26`        |
| `%M`    | Month                           | `3`         |
| `%y`    | Short year                      | `25`        |
| `%A`    | Full day name                   | `Wednesday` |
| `%m`    | Minutes                         | `30`        |
| `%H`    | UTC hour with european standard | `13`        |
| `%h`    | UTC hour with american standard | `1`         |
| `%s`    | Seconds                         | `18`        |
| `%H:%M` | Time (24h)                      | `14:30`     |

**Shorthand tokens without `%`:**

| Token | What it gives                   | Example              |
| ----- | ------------------------------- | -------------------- |
| `D`   | Day, month, year                | `Thursday, March 26` |
| `H`   | UTC hour with european standard | `13`                 |
| `M`   | Months                          | `3`                  |
| `d`   | Day                             | `26`                 |
| `h`   | UTC hour with american standard | `1`                  |
| `m`   | Minutes                         | `30`                 |
| `s`   | Seconds                         | `18`                 |
| `y`   | Short year                      | `26`                 |
| `H:M` | Time (24h)                      | `14:30`              |

**Real pass example:**

```
Valid until {{ pass.expiry_date | date: "%d %B %Y" }}
```

→ `Valid until 31 December 2025`

<div data-with-frame="true"><figure><img src="/files/EjupTn9ROrjXyMfXJvgc" alt="Date Formatting example in our template editor" width="563"><figcaption><p>Date Formatting example in our template editor</p></figcaption></figure></div>

### Date arithmetic

Add or subtract time from a date. The trick is to convert to seconds first, do the maths, then reformat.

**1 day = 86400 seconds.**

```
{% assign expiry_ts = pass.expiry_date | date: "%s" | plus: 0 %}
{% assign grace_period_ts = expiry_ts | plus: 604800 %}
Grace period ends: {{ grace_period_ts | date: "%d/%m/%Y" }}
```

**Handy reference:**

| Duration | Seconds    |
| -------- | ---------- |
| 1 day    | 86 400     |
| 7 days   | 604 800    |
| 30 days  | 2 592 000  |
| 90 days  | 7 776 000  |
| 1 year   | 31 536 000 |

### Date flags — is this pass still valid?

Compare a pass date against today to show contextual messages.

```
{% assign today = 'now' | date: "%s" | plus: 0 %}
{% assign expiry = pass.expiry_date | date: "%s" | plus: 0 %}

{% if expiry < today %}
	This pass has expired. Visit us in store to renew.
{% elsif expiry < today | plus: 604800 %}
	Expiring in less than 7 days — use it before it's gone!
{% else %}
	Active pass
{% endif %}
```

**Event ticket use case:** show a different label before vs after the event.

```
{% assign now_ts = 'now' | date: "%s" | plus: 0 %}
{% assign event_ts = event.date | date: "%s" | plus: 0 %}

{% if now_ts < event_ts %}
	🎟 See you on {{ event.date | date: "%d %B" }}!
{% else %}
	Thanks for joining us. We hope you had a great time.
{% endif %}
```

{% hint style="warning" %}
Always convert both dates to Unix timestamps before comparing. Comparing raw date strings does not work.
{% endhint %}

### now / today

`'now'` gives the current moment. Use it anywhere today’s date is needed.

```
Pass generated on {{ 'now' | date: "%d/%m/%Y" }}
```

With a friendly format:

```
{{ customer.first_name }}, here's your status on {{ 'now' | date: "%A %d %B %Y" }}.
```

→ `Marie, here's your status on Wednesday 25 March 2025.`

### Combining date filters

Chain multiple steps together to compute, compare, and display dates in one flow.

**Show days remaining on a coupon:**

```
{% assign today_ts = 'now' | date: "%s" | plus: 0 %}
{% assign expiry_ts = coupon.expiry_date | date: "%s" | plus: 0 %}
{% assign days_left = expiry_ts | minus: today_ts | divided_by: 86400 %}

{% if days_left > 0 %}
	{{ days_left }} days left to use this coupon.
{% else %}
	This coupon has expired.
{% endif %}
```

**Show a renewal reminder 30 days before expiry:**

```
{% assign today_ts = 'now' | date: "%s" | plus: 0 %}
{% assign expiry_ts = pass.expiry_date | date: "%s" | plus: 0 %}
{% assign days_until_expiry = expiry_ts | minus: today_ts | divided_by: 86400 %}

{% if days_until_expiry <= 30 and days_until_expiry > 0 %}
	Your membership renews on {{ pass.expiry_date | date: "%d %B %Y" }}.
	Don’t let your benefits lapse. Renew in store or online.
{% endif %}
```

### capture — build a message block

`capture` lets you construct a full string and save it for later. Nothing is displayed until the variable is rendered.

```
{% capture loyalty_summary %}
	{{ customer.first_name }}, you have {{ customer.points }} points.
	Current tier: {{ customer.tier }}.
	Next tier in {{ next_tier_points | minus: customer.points }} points.
{% endcapture %}

{{ loyalty_summary }}
```

Great for building a push notification body, a back-of-pass description, or any content block that needs to be assembled in steps before showing it.

> **Questions?** Reach out to your Wallet Crew contact or check the [Knowledge Base](https://docs.thewalletcrew.io). Happy templating&#x20;


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.thewalletcrew.io/configure/wallet/template-configuration/liquid.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
