Skip to main content

Advanced Liquid — Filters, Formatting & Troubleshooting

The power tools: currency and date filters, reusable values with assign and capture, repeating table rows in Word, client name templates, and how to fix a letter that won't generate.

Written by Blaine Korte

You've got variables merging and conditions branching — this article covers the power tools: formatting filters, reusable values, repeating table rows, client name templates, and what to do when a letter won't generate.

Filters

A filter reshapes a value before it prints. Chain it after the variable with a pipe:

{{ service.price | usd }}

Fidu's filters

Filter

Example

Prints

usd

{{ 1234.5 | usd }}

$1,234.50

ordinalize

{{ 21 | ordinalize }}

21st

usd is the right way to print any money amount — never rely on the raw number. ordinalize shines in legal boilerplate:

Executed on this {{ engagement.closing_day | ordinalize }} day of {{ engagement.closing_month }}.

Standard Liquid filters

Fidu's letter generation runs real Liquid, so the standard filters work too. The most useful:

Filter

Example

Prints

date

{{ engagement.closing_date | date: "%B %-d, %Y" }}

March 5, 2026

upcase

{{ client.name | upcase }}

ACME HOLDINGS LLC

capitalize

{{ engagement.entity_type | capitalize }}

Llc — be careful with acronyms

default

{{ client.legal_name | default: client.name }}

Falls back when the first value is blank

append / prepend

{{ engagement.matter_number | prepend: "Matter No. " }}

Matter No. 2026-014

replace

{{ client.name | replace: " LLC", "" }}

Strips a suffix

Common date patterns: %B %-d, %Y → March 5, 2026 · %m/%d/%Y → 03/05/2026 · %A → Thursday. Always verify date output with a test letter — the stored answer format determines what the filter can parse.

Filters chain left to right: {{ client.legal_name | default: client.name | upcase }}.

Reusable values with assign and capture

Compute a value once, use it many times:

{% assign fee = service.price | usd %}
The fee of {{ fee }} is due upon execution. … A late charge applies to any portion of the {{ fee }} not received…

capture does the same for a block of text:

{% capture full_address %}{{ client.address }}, {{ client.city }}, {{ client.province }} {{ client.postal_code }}{% endcapture %}
{{ full_address }}

Place assign/capture tags on their own line near the top of the document; each renders nothing itself.

Repeating table rows (Word templates only)

Word templates can repeat a table row per item in a list. The row-loop tags live in their own otherwise-empty table rows, using the {%tr … %} form:

  • Row 1 (tag only): {%tr for user in users %}

  • Row 2 (the template row): {{ user.name }} in one cell, {{ user.email }} in the next

  • Row 3 (tag only): {%tr endfor %}

The rows holding the {%tr%} tags disappear in the generated letter, leaving one populated row per item. One tag per row, nothing else in that row. Google Docs templates don't support table-row loops.

Client name templates

When your signup form has no Business/Client Name field (typical for individual clients), Fidu builds each new client record's name from the client name template — a small Liquid template on the letter template's Signup Form tab. The default is:

{{ user_first_name }} {{ user_last_name }}

Available variables: any named question on the signup form (by its bare name — {{ user_first_name }}, not the engagement. form), plus {{ external_name }} and {{ internal_name }} for the service's names. For example, to name records like "Nguyen — Estate Plan":

{{ user_last_name }} — Estate Plan

Authoring rules by document type

Both formats

  • A tag must not contain a line/paragraph break in the middle.

  • Use straight quotes inside tags (watch for Word/Google autocorrect).

  • Blocks must be balanced (if/endif, for/endfor).

  • Money math belongs in your data and prices; templates only format values.

Google Docs

  • Every tag must be uniformly styled — one font, weight, and size across the whole tag. Content between tags can be styled freely.

  • Loop bodies can't span multiple paragraphs, and table-row loops aren't supported.

  • Tags must be plain text — no inline images or page-number fields inside a tag.

Word

  • Table-row loops are supported via the {%tr%} form (above).

  • Within a tag, styling can vary; across paragraphs it cannot (a tag can't contain a hard break).

Troubleshooting

A variable printed nothing. Either the name is misspelled (copy it from the variables list) or the underlying value is genuinely blank (an optional answer, a missing phone number). Use default: or an {% if %} wrapper for values that may legitimately be empty. Test letters report which variables came out unresolved.

The letter failed to generate with a template error. The error message names the offending tag. The usual suspects:

  • an unclosed or mismatched block ({% if %} with no {% endif %}),

  • curly "smart" quotes inside a tag,

  • a tag split across lines or (in Google Docs) styled inconsistently,

  • a misspelled tag or filter name.

Fix the tag it names and regenerate.

A condition never fires. Compare against the exact answer label, capitalization included (== "Yes"), and check the quotes are straight.

Stray blank lines where a condition was false. Put the {% if %} and {% endif %} on their own lines wrapping whole paragraphs — paragraph-level conditions that come up empty are removed cleanly, inline ones leave the rest of their line.

When in doubt, generate a test letter. It runs the exact production merge with sample data and is always the fastest diagnostic.

Did this answer your question?