Streamline's document engine supports Smarty scripting directly inside your DOCX template files. You can write conditional logic, loops, inline calculations, and formatting modifiers in your template, and they are evaluated when the document is generated. This lets you build dynamic documents - showing or hiding content, repeating rows for each record in a collection, and formatting values in place - without adding separate Transform or Logic steps to your workflow.
Who Can Use This Feature?
Smarty scripting in document templates is available to all Builders and any role with edit access to a Dynamic Document template.
Note: This feature is currently available in limited release. Contact your Intellistack account team to request access.
Key Capabilities
Conditional content:
- Show or hide paragraphs, sections, table rows, and list items based on field values
- Use
{if}/{elseif}/{else}for inline conditional rendering within a cell or paragraph - Use
{tableif}and{listif}to conditionally render entire table rows or list items
Repeating sections:
- Iterate over a collection of records using
{foreach}to render one section per item - Use
{tablerow}and{listrow}to repeat entire table rows or list items for each record in a collection
Value formatting with modifiers:
- Format dates, numbers, currency, phone numbers, and text inline using pipe-style modifiers
- Chain multiple modifiers in sequence:
{$value|modifier1|modifier2}
Inline calculations:
- Assign intermediate variables and perform arithmetic directly in the template
- Use BCMath functions for precise decimal arithmetic
Variable assignment:
- Assign and reuse template variables with
{$var = expression}or{assign}
Image embedding:
- Embed an image from a URL field using
{$field|insert_image:width:height}
Part 1: Enabling Smarty on a Merge Field
By default, merge fields in a Dynamic Document template output their value as plain text. To use Smarty syntax on a field, you need to enable it in the field settings.
For a standard merge field
- Click the merge field in the document editor.
- In the Field settings panel on the left, toggle Smarty Mode on.
- Edit the field value in the document to include your Smarty expression.
Once enabled, the field value is evaluated as a Smarty expression at merge time. For example:
{( Subtotal + tax )|number_format:2}
For fields in repeating collections
When adding a field from a repeating data collection, use the Add repeated data wizard:
- In the document editor, click to insert a field from a repeating collection.
- The Add repeated data dialog opens. Under Display as, select Smarty syntax.
- Click Insert.
The field is inserted as a Smarty expression block you can edit directly in the template.
Note: Variable names are case-sensitive. Match the variable name exactly as it appears in the field mapping.
Part 2: Conditional Content
Conditional paragraphs and inline content
Use {if} / {elseif} / {else} to show or hide content based on field values.
{if $contract_type == "fixed"}
This agreement is for a fixed-price engagement.
{elseif $contract_type == "hourly"}
This agreement is billed at an hourly rate.
{else}
Please contact your account manager for pricing details.
{/if}
Supported comparison operators:
| Operator | Alias | Example |
|---|---|---|
== |
eq |
{if $status == "active"} |
!= |
ne |
{if $status != "closed"} |
> |
gt |
{if $amount > 1000} |
< |
lt |
{if $days lt 30} |
>= |
gte |
{if $score >= 90} |
<= |
lte |
{if $count lte 5} |
&& |
and |
{if $a > 0 and $b > 0} |
\|\| |
or |
{if $type == "A" or $type == "B"} |
Use empty() to check whether a field has a value:
{if !empty($middle_name)}
{$first_name} {$middle_name} {$last_name}
{else}
{$first_name} {$last_name}
{/if}
Conditional table rows
To conditionally show or hide an entire table row, use {tableif} instead of {if}. Place {tableif} and {/tableif} around the row in your template.
{tableif !empty($discount_amount)}
| Discount | {$discount_amount|currency_format} |
{/tableif}
Important: Use
{tableif}(not{if}) when the condition wraps an entire table row. Using plain{if}inside a table cell works for inline content within a cell, but cannot show or hide the entire row.
Conditional list items
To conditionally show or hide an entire paragraph or list item, use {listif}.
{listif $include_warranty == "yes"}
- 12-month warranty included
{/listif}
Part 3: Repeating Sections
Repeating content with {foreach}
Use {foreach} to iterate over an array of records and render content for each item.
{foreach $line_items as $item}
{$item.description}: {$item.quantity} x {$item.unit_price|currency_format}
{/foreach}
Use {foreachelse} to render fallback content when the collection is empty:
{foreach $line_items as $item}
{$item.description}
{foreachelse}
No items on this order.
{/foreach}
Useful properties inside a {foreach} loop:
| Property | What it gives you |
|---|---|
{$item@index} |
Zero-based position (0, 1, 2...) |
{$item@iteration} |
One-based count (1, 2, 3...) |
{$item@first} |
true on the first iteration |
{$item@last} |
true on the last iteration |
{$item@total} |
Total number of items in the collection |
Repeating table rows
To repeat an entire table row for each record in a collection, use {tablerow}. Place {tablerow} and {/tablerow} around the row.
{tablerow $line_items as $item}
| {$item.description} | {$item.quantity} | {$item.unit_price|currency_format} |
{/tablerow}
Repeating list items
To repeat a list item or paragraph for each record, use {listrow}.
{listrow $attendees as $person}
- {$person.name}, {$person.title}
{/listrow}
Part 4: Formatting Values with Modifiers
Apply modifiers to a variable using the pipe | character. Chain multiple modifiers left to right.
{$name|upper} → JOHN SMITH
{$name|lower} → john smith
{$name|capitalize} → John Smith
{$description|truncate:100} → First 100 characters...
{$text|strip_tags} → Plain text with HTML removed
{$field|default:"Not provided"} → Value, or "Not provided" if empty
Date formatting
Use date_format to format a date or timestamp field:
{$contract_date|date_format:"%B %d, %Y"} → July 1, 2026
{$contract_date|date_format:"%m/%d/%Y"} → 07/01/2026
{$contract_date|date_format:"%Y-%m-%d"} → 2026-07-01
Note:
strftimeis also available but is deprecated and will be removed in a future PHP version. Usedate_formatfor new templates.
To calculate and display an age from a date field:
{$birthdate|age} years old
{$birthdate|age_to_words} → e.g. "42 years"
Number and currency formatting
{$amount|number_format:2} → 1,234.56
{$amount|currency_format} → $1,234.56
{$amount|money_to_words} → one thousand two hundred thirty-four dollars and 56 cents
{$total|round:2} → 1234.56
{$count|number_to_words} → forty-two
String utilities
{$phone|phone_format:"(%3) %3-%4"} → (555) 123-4567
{$state|state_abbreviation} → CA
{$items|list:", ":"and"} → red, green, and blue
{$text|replace:"Corp":"Corporation"}
{$text|regex_replace:"/\s+/":" "}
Array utilities
{$tags|implode:", "} → Join array to a comma-separated string
{$tags|count} → Number of items in the array
{$rows|sort} → Sorted array
Part 5: Calculations and Variable Assignment
You can perform arithmetic directly in the template and assign results to variables for reuse.
{$subtotal = $qty * $unit_price}
{$tax = $subtotal * 0.08}
{$total = $subtotal + $tax}
Subtotal: {$subtotal|currency_format}
Tax (8%): {$tax|currency_format}
Total: {$total|currency_format}
Output an inline calculation without assigning it to a variable:
Total due: {($qty * $unit_price)|currency_format}
For precise decimal arithmetic (recommended for financial calculations), use BCMath functions:
{$total = bcadd($subtotal, $tax, 2)}
Feature Considerations
{eval} is not available: The {eval} tag is disabled. Dynamic template evaluation within a template is not supported.
Superglobals are not accessible: $_GET, $_POST, $_SERVER, and other PHP superglobals cannot be used in templates.
Modifier allow-list: Only modifiers on Streamline's approved list can be used. If a template references an unlisted modifier, the document step returns a clear error identifying the modifier name. This prevents silent failures and helps you identify the issue quickly.
strftime is deprecated: The strftime modifier is supported but deprecated. It will stop working in a future PHP version. Migrate date formatting to date_format when updating existing templates.
Network modifiers during validation: The get_file, expand_url, csv_to_array, and translate modifiers return empty values during template validation. This is expected - they make outbound calls only at merge time, not during validation.
{tableif} / {tablerow} vs. {if} / {foreach}: Use the {tableif}, {tablerow}, {listif}, and {listrow} constructs when the condition or loop wraps an entire table row or list item. Using plain {if} or {foreach} inside a cell works for inline conditional content but cannot show or hide the entire row.
Compliance
Templates are processed inside a security sandbox. Dangerous PHP functions (including file system access, network calls, and code execution primitives such as exec, system, and unserialize) are hard-blocked and cannot be invoked from a template, even if they would otherwise be accessible. All template rendering happens server-side within Streamline's secure document engine.
Troubleshooting
| Issue | Resolution |
|---|---|
| Document step returns a modifier error | The modifier name is not on the approved list. Check the modifier name for typos. Refer to the supported modifier reference for the correct name. |
| Date field renders as a raw timestamp or unexpected format | Verify the format string passed to date_format. Use strftime-style % codes (e.g., %B %d, %Y). |
| Table row is not showing or hiding conditionally | Use {tableif} / {/tableif} around the row instead of {if} inside a cell. Plain {if} inside a table cell cannot hide the entire row. |
| Repeating section produces no output | Confirm the collection field is mapped to the Document step and that it contains records. Use {foreachelse} to render fallback content when the collection is empty. |
| Variable renders as empty | Check that the variable name in the template matches the field mapping in the Document step exactly, including case. Variable names are case-sensitive. |
get_file or translate modifier returns empty during testing |
These modifiers short-circuit during template validation. They make outbound calls only at actual merge time. Test by running the workflow end-to-end. |
Modifier Reference
Standard Smarty Modifiers
These modifiers are part of the Smarty language and are available in Streamline document templates.
| Modifier | What it does | Example |
|---|---|---|
capitalize |
Capitalizes the first letter of each word | {$name\|capitalize} |
cat |
Appends a string onto the end of the value | {$name\|cat:" Jr."} |
count_characters |
Counts characters in a string | {$text\|count_characters} |
count_paragraphs |
Counts paragraphs in a string | {$text\|count_paragraphs} |
count_sentences |
Counts sentences in a string | {$text\|count_sentences} |
count_words |
Counts words in a string | {$text\|count_words} |
date_format |
Formats a date/timestamp using a format string | {$date\|date_format:"%B %d, %Y"} |
default |
Substitutes a fallback value when the variable is empty or unset | {$field\|default:"N/A"} |
escape |
Escapes a value for HTML, URL, quotes, or JavaScript | {$text\|escape} |
indent |
Indents each line by N characters | {$text\|indent:4} |
lower |
Lowercases the string | {$name\|lower} |
nl2br |
Converts newlines to line breaks | {$text\|nl2br} |
regex_replace |
Regular-expression search and replace | {$text\|regex_replace:"/\s+/":" "} |
replace |
Plain string search and replace | {$text\|replace:"Ltd":"Limited"} |
spacify |
Inserts a string between every character | {$code\|spacify:"-"} |
string_format |
Formats a value using a sprintf-style format string |
{$val\|string_format:"%.2f"} |
strip |
Collapses runs of whitespace into a single space | {$text\|strip} |
strip_tags |
Removes HTML and XML tags | {$html\|strip_tags} |
truncate |
Truncates to a length with an optional ellipsis | {$text\|truncate:100} |
unescape |
Reverses escape encoding |
{$text\|unescape:'html'} |
upper |
Uppercases the string | {$name\|upper} |
wordwrap |
Wraps text to a given column width | {$text\|wordwrap:80} |
Dates & Age
| Modifier | What it does | Example |
|---|---|---|
add_days |
Adds N days to a date; optional skip-weekends; returns Y-m-d |
{$date\|add_days:7} |
age |
Whole years between a date and now | {$birthdate\|age} |
age_to_words |
Largest time unit between a date and now, in words | {$birthdate\|age_to_words} |
time_to_words |
Converts seconds to a human-readable duration | {$seconds\|time_to_words} |
Numbers & Money
| Modifier | What it does | Example |
|---|---|---|
number_format |
Formats a number with decimals and thousands separators | {$amount\|number_format:2} |
number_to_words |
Converts a number to words | {$count\|number_to_words} |
decimal_to_words |
Converts integer and fractional parts to words | {$amount\|decimal_to_words} |
money_to_words |
Converts a monetary amount to words with currency | {$total\|money_to_words} |
currency_format |
Formats as currency with symbol, decimals, and separators | {$price\|currency_format} |
currency_format_india |
Formats with Indian lakh/crore grouping | {$amount\|currency_format_india} |
number_eu_to_us |
Converts EU number format to US format | {$val\|number_eu_to_us} |
number_us_to_eu |
Converts US number format to EU format | {$val\|number_us_to_eu} |
number |
Extracts a numeric value from a string; returns 0 if empty |
{$field\|number} |
int_number |
Normalizes a localized number to an integer-ish string | {$field\|int_number} |
round |
Rounds to a given number of decimal places | {$val\|round:2} |
ceil |
Rounds up to the next integer | {$val\|ceil} |
floor |
Rounds down to the nearest integer | {$val\|floor} |
Strings & Text
| Modifier | What it does | Example |
|---|---|---|
abbreviation |
Builds an acronym from word initials | {$name\|abbreviation} |
capitalize_sentences |
Uppercases the first letter of each sentence | {$text\|capitalize_sentences} |
mb_upper |
Multibyte-safe (UTF-8) uppercase | {$text\|mb_upper} |
pad |
Pads a string to a given length | {$code\|pad:10} |
strlen |
Returns the length of a string | {$text\|strlen} |
nl2 |
Replaces newlines with a given string | {$text\|nl2:", "} |
nl2p |
Wraps text in paragraph tags, converting newlines to paragraph breaks | {$text\|nl2p} |
list |
Joins an array into a readable list with a conjunction | {$items\|list:", ":"and"} |
phone_format |
Formats digits into a phone pattern | {$phone\|phone_format:"(%3) %3-%4"} |
state_abbreviation |
Maps a US state name to its 2-letter code | {$state\|state_abbreviation} |
translate |
Translates text to another language via Google Translate | {$text\|translate:"es"} |
HTML & Markup
| Modifier | What it does | Example |
|---|---|---|
markdown2html |
Converts Markdown to HTML | {$text\|markdown2html} |
text2html |
Converts plain text to HTML (newlines to <br/>, auto-links URLs) |
{$text\|text2html} |
html2text |
Strips HTML tags and decodes entities to plain text | {$html\|html2text} |
html_safe |
Escapes stray < characters that are not real tags |
{$text\|html_safe} |
Arrays
| Modifier | What it does | Example |
|---|---|---|
count |
Counts the number of elements in an array | {$items\|count} |
implode |
Joins an array into a string | {$tags\|implode:", "} |
in_array |
Returns true if a value is in the array | {if "red"\|in_array:$colors} |
sort |
Sorts an array ascending or descending | {$items\|sort} |
multisort |
Sorts an array of rows by up to three keys | {$rows\|multisort:"name"} |
array_chunk |
Splits an array into fixed-size chunks | {$items\|array_chunk:3} |
array_column |
Extracts a single column from an array of rows | {$rows\|array_column:"name"} |
csv_to_array |
Parses a CSV string into an array of rows | {$csv\|csv_to_array} |
Network & Files
These modifiers make outbound calls at merge time. They return empty values during template validation - this is expected behavior.
| Modifier | What it does |
|---|---|
get_file |
Fetches the body of a URL (SSRF-validated) |
expand_url |
Follows redirects to resolve a short URL to its destination |
parse_url |
Extracts a URL from a string value |
Summary
Smarty scripting in document templates is currently available in limited release to Builders and roles with edit access to Dynamic Document templates. Enable the Smarty Mode toggle on any merge field to write Smarty expressions directly in your template. For the full list of supported modifiers and constructs, refer to the modifier tables in the Key Capabilities and Part 4 sections of this article.
Comments
0 comments
Please sign in to leave a comment.