Skip to main content

Basic Syntax of Kuroco Smarty

Kuroco uses Smarty as the template engine for custom processing and batch processing. This document covers the fundamental syntax elements you'll need to work with Kuroco's Smarty implementation.

Control Structures

if/else/elseif Statement

The {if} statement allows conditional processing based on expressions. Use {else} and {elseif} to handle multiple conditions.

Syntax

{if condition}
Process when condition is true
{elseif condition2}
Process when condition2 is true
{else}
Process when all conditions are false
{/if}

Example

{if $member.status == 'active'}
Welcome back!
{else}
Your account is inactive.
{/if}

Available PHP Functions in if Statement

The PHP functions available within {if} statements are limited to the following. Calling a function not in this list will result in a compile-time error.

  • is_null() - Check if a variable is null
  • count() - Count elements in an array
  • is_array() - Check if a variable is an array
  • in_array() - Check if a value exists in an array
  • isset() - Check if a variable is declared and is not null
  • is_object() - Check if a variable is an object

Note that null / NULL, true / TRUE, and false / FALSE can be written as bare words in conditions. For anything else, compute the boolean in advance with {assign} or a modifier, then test the result in {if}.

For details, see PHP Functions Available for Kuroco's Smarty.

Loop Structures

foreach Statement

The {foreach} statement iterates through arrays or objects.

Basic Syntax

{foreach from=$array item="item"}
{$item}
{/foreach}

With Index

{foreach from=$array item="item" key="key"}
{$key}: {$item}
{/foreach}

With Loop Counter

{foreach from=$array item="item" name="loop1"}
{$item}
{if !$smarty.foreach.loop1.last}
,
{/if}
{/foreach}

Example

{foreach from=$topics_list.list item="topics"}
{logger msg1=$topics.subject}
{/foreach}

Foreach Properties

When using the name attribute, you can access the following properties:

  • $smarty.foreach.name.first - True on the first iteration
  • $smarty.foreach.name.last - True on the last iteration
  • $smarty.foreach.name.index - Current array index (starting from 0)
  • $smarty.foreach.name.iteration - Current iteration count (starting from 1)
  • $smarty.foreach.name.total - Total number of iterations

Complex Example

{capture name="emailBody"}
{$member.name1},

You have a new notification.
{/capture}

{foreach from=$members item="member" name="memberLoop"}
{sendmail
var='result'
to=$member.email
subject='Notification'
contents=$smarty.capture.emailBody
from="noreply@example.com"
from_nm="System"}
{logger msg1="Sent" msg2=$member.email msg3=$smarty.foreach.memberLoop.iteration}
{if $smarty.foreach.memberLoop.last}
{logger msg1="All emails sent" msg2=$smarty.foreach.memberLoop.total}
{/if}
{/foreach}

section Statement

The {section} statement is an alternative loop structure.

Basic Syntax

{section name="name" loop=$array}
{$array[name]}
{/section}

Example

{section name="i" loop=$topics_list.list}
{logger msg1=$topics_list.list[i].subject}
{/section}

Section Properties

  • $smarty.section.name.first - True on the first iteration
  • $smarty.section.name.last - True on the last iteration
  • $smarty.section.name.index - Current index
  • $smarty.section.name.iteration - Current iteration count
  • $smarty.section.name.total - Total number of iterations

Loop Control

break

Exits the loop immediately.

{foreach from=$items item="item"}
{if $item.id == $target_id}
Found: {$item.name}
{break}
{/if}
{/foreach}

continue

Skips the remaining code in the current iteration and moves to the next iteration.

{foreach from=$items item="item"}
{if $item.status == 'draft'}
{continue}
{/if}
{logger msg1=$item.title}
{/foreach}

capture Statement

The {capture} statement captures output into a variable instead of displaying it.

Basic Syntax

{capture name="varname"}
Content to capture
{/capture}

Practical Example

{capture name="emailBody"}
Hello {$member.name1} {$member.name2},

Thank you for your registration.
Your member ID is: {$member.member_id}

Best regards,
Team
{/capture}

{sendmail
var='result'
to=$member.email
subject='Registration Complete'
contents=$smarty.capture.emailBody
from="noreply@example.com"
from_nm="System"}

Comments

Single-line Comment

{* This is a comment *}

Multi-line Comment

{*
This is a
multi-line
comment
*}

Variables

Calling Variables

Simple Variable

{$variable_name}

Example

{assign var="greeting" value="Hello, World!"}
{$greeting}

Array Element Access

Use bracket notation to access array elements.

{$array[index]}
{$array['key']}

Example

{$topics_list.list[0].subject}
{$topics_list.list[1].ymd}
{$members.list[0].email}

Accessing Keys Containing Hyphens

Smarty identifiers (variable names and array keys) cannot contain hyphens (-). This is a Smarty language specification. For example, writing $request.load-debug in dot notation is interpreted as a subtraction of debug from load, so the intended key cannot be accessed.

To access a key that contains a hyphen, specify it as a string key using bracket notation.

{$request['load-debug']}

Combined Access Example

{* Accessing object properties in a loop *}
{foreach from=$topics_list.list item="topics"}
{logger msg1=$topics.subject msg2=$topics.ymd}
{/foreach}

{* Nested objects and array index access *}
{logger msg1=$topics_list.list[0].subject msg2=$topics_list.pageInfo.totalCnt}

{* Loop counter combined with property access *}
{foreach from=$members.list item="member" name="loop"}
{logger msg1=$smarty.foreach.loop.iteration msg2=$member.name1 msg3=$member.email}
{/foreach}

Variable Expansion in Strings

To expand a variable inside a string, wrap the variable in backticks (`).

{api_internal
var='topics'
status_var='status'
endpoint="/rcms-api/3/topics/details/`$topics_id`"
method='GET'
member_id="1"}

In particular, when the variable inside a double-quoted string contains characters that Smarty does not treat as part of an identifier — such as ., [, ], or -> — you must wrap the whole variable in backticks. Otherwise the dotted / bracketed / arrow expression cannot be parsed inside the string and the template fails to compile. This is the standard Smarty "embedded variables" syntax (see the Smarty manual).

{* OK: a simple $-variable inside a double-quoted attribute *}
{assign var="aa" value="$arg"}

{* OK: backticks let Smarty parse the full expression inside the string *}
{assign var="aa" value="`$arg.name`"}
{assign var="aa" value="`$item[0].title`"}
{assign var="aa" value="`$obj->prop`"}

{* OK: no quotes at all — passes the expression as a raw value *}
{assign var="aa" value=$arg.name}

{* NG: dotted variable inside a double-quoted string without backticks
— Smarty raises a syntax error and the template fails to compile *}
{assign var="aa" value="$arg.name"}

It is easy to overlook and often misread by tooling/AI, so prefer the backtick form whenever the variable expression includes ., [], or -> inside a double-quoted attribute value.

To include " in a string value, escape it with a backslash. This can be combined with backtick variable expansion.

{assign var="email" value="example@diverta.co.jp"}
{assign var="filter" value="from_mail = \"`$email`\" and receive_date >:relatively \"`$from_date`\""}

Undefined Variables and Array Keys

When accessing undefined variables or undefined array keys, they are treated as null.

{assign_array var="member" values=""}
{append var="member" index="age" value=48}
{if $member.name === null}
$member.name is null
{else}
$member.name is not null
{/if}

{if $undefined === null}
$undefined is null
{else}
$undefined is not null
{/if}

In the above example, both $member.name and $undefined are treated as null, so the conditional branches output "$member.name is null" and "$undefined is null".

Additionally, when attempting to access a key of an undefined variable (e.g., {$undefined.attr}), evaluation stops at the undefined part and it is treated as null. This behaves similarly to JavaScript's optional chaining operator (?.).

{if $undefined.attr === null}
$undefined.attr is null
{else}
$undefined.attr is not null
{/if}

In the above example, since $undefined is undefined, accessing $undefined.attr stops evaluation and is treated as null, so "$undefined.attr is null" is output.

caution

There is an exception to this safe array access. When a reference-taking modifier (|@sort, |@rsort, |@asort, |@arsort, |@ksort, |@krsort, |@array_push, |@array_pop, |@array_shift, |@shuffle) is the first operand in the chain, this safety net is not applied. When using those, make sure the variable is actually defined before applying the modifier.

Creating Variables

Simple Assignment

Use {assign} to create or update a variable.

{assign var="variable_name" value="value"}

Example

{assign var="title" value="Welcome"}
{assign var="count" value=10}
{assign var="price" value=1500}
{assign var="is_active" value=true}

Using Existing Variables

{assign var="full_name" value=$member.name1|cat:" "|cat:$member.name2}

Creating Arrays

Use {assign_array} to create an array.

Empty Array

{assign_array var="my_array" values=""}

Array with Values

{assign_array var="fruits" values="apple,banana,orange"}
{assign_array var="numbers" values="1,2,3,4,5"}

Custom Delimiter

{assign_array var="items" values="item1;item2;item3" delimiter=";"}

Associative Array

{assign_array var="person" keys="name,age,email" values="John,25,john@example.com"}

Creating Objects (Associative Arrays)

Use {assign_array} to create an empty object, then {append} to add properties.

Basic Object Creation

{assign_array var="member" values=""}
{append var="member" index="name" value="John Doe"}
{append var="member" index="age" value=30}
{append var="member" index="email" value="john@example.com"}

{* Access properties *}
{$member.name}
{$member.age}
{$member.email}

Nested Objects

Suppose you want to create an object like the following JSON:

{
"name": "John Doe",
"address": {
"city": "Tokyo",
"zip": "100-0001"
}
}

Create the inner address object first, then add it to the outer object.

{* Create address object *}
{assign_array var="address" values=""}
{append var="address" index="city" value="Tokyo"}
{append var="address" index="zip" value="100-0001"}

{* Create person object with nested address *}
{assign_array var="person" values=""}
{append var="person" index="name" value="John Doe"}
{append var="person" index="address" value=$address}

{* Access nested properties *}
{$person.name}
{$person.address.city}
{$person.address.zip}

Modifying Arrays

Adding Elements

{assign_array var="list" values=""}
{append var="list" value="first item"}
{append var="list" value="second item"}
{append var="list" value="third item"}

As a Kuroco-specific extension, you can also use {assign} to add elements:

{assign_array var="list" values=""}
{assign var="list." value="first item"}
{assign var="list." value="second item"}
{assign var="list." value="third item"}

Adding Elements with Index

{assign_array var="settings" values=""}
{append var="settings" index="theme" value="dark"}
{append var="settings" index="language" value="en"}
{append var="settings" index="notifications" value=true}

As a Kuroco-specific extension, you can also use {assign} to add elements with index (dot notation nesting supports up to 4 levels):

{assign_array var="settings" values=""}
{assign var="settings.theme" value="dark"}
{assign var="settings.language" value="en"}
{assign var="settings.notifications" value=true}

Practical Example: Building API Request Parameters

{* Create query parameters for API *}
{assign_array var="method_params" values=""}
{assign_array var="method_params.topics_group_id" values="1"}

{assign_array var="request_params" values=""}
{assign var="request_params.cnt" value=20}
{assign var="request_params.pageID" value=1}

{api_method
var="topics_list"
model="Topics"
method="list"
version="1"
method_params=$method_params
request_params=$request_params}

{foreach from=$topics_list.list item="topics"}
{$topics.subject}
{/foreach}

Building arrays in templates — best practices

Smarty 2 has no built-in array literal syntax, so Kuroco templates rely on a small set of helpers. Pick the pattern that matches your shape:

1. Initialize, then push (most common)

The canonical pattern: declare an empty array with assign_array, then add elements one by one with append. This is what most existing Kuroco templates use.

{assign_array var=items values=""}
{append var=items value="first"}
{append var=items value="second"}
{append var=items value=$dynamic_value}

For associative arrays, pass index to {append}:

{assign_array var=person values=""}
{append var=person index="name" value="Katoh"}
{append var=person index="age" value=28}
2. One-shot literal from a delimited string

When the values are static, build the array in a single tag:

{* List *}
{assign_array var=colors values="red,green,blue"}

{* Custom delimiter (when values contain commas) *}
{assign_array var=paths values="/a;/b;/c" delimiter=";"}

{* Associative (keys and values must have the same count) *}
{assign_array var=opts keys="host,port,ssl" values="example.com,443,true"}
3. Dot notation for nested structures

The {assign} tag accepts dot-paths in the variable name to create nested arrays in one step (up to 4 levels deep):

{assign var="user.profile.name" value="Katoh"}
{assign var="user.profile.age" value=28}
{assign var="user.roles." value="admin"} {* trailing dot pushes to $user.roles *}
{assign var="user.roles." value="editor"}

Result:

user => Array
profile => Array (name=Katoh, age=28)
roles => Array ("admin", "editor")
4. Immutable variant — keep the original array unchanged

{append} mutates var in place. When you need to derive a new array without touching the source, use assign_array_set:

{assign_array_set var=updated from=$original key="status" value="done"}
{* $original is unchanged; $updated has the extra key *}
Picking between the patterns
ShapeRecommended pattern
Indexed list, items known statically{assign_array values="a,b,c"}
Indexed list, items added in a loop{assign_array values=""} + {append}
Flat associative map, ≤ 1 level{assign_array keys=... values=...} or {append index=...}
Nested structure (object-like){assign var="a.b.c" value=...} dot notation
Need to preserve the original{assign_array_set}
Array-specific pitfalls
  • Do not rely on accidental indexing into a string or scalar. Because of the safe array access behavior, {$x[0]} against a non-array silently returns null — easy to misread as a real value. Initialize arrays explicitly with {assign_array} before indexing into them.
  • Always initialize an array before {append}-ing to it. Start every list with {assign_array var=foo values=""} so the receiving variable is guaranteed to be an array. Calling {append} on a variable that hasn't been initialized (or that was set to a scalar) does not produce the expected array, especially across {include} boundaries.

Variable Modifiers

Variables can be modified by applying modifiers with the pipe (|) character.

Basic Syntax

{$variable|modifier}
{$variable|modifier:parameter}
{$variable|modifier1|modifier2}

Common Examples

{* Truncate string *}
{$description|truncate:100}

{* Format date *}
{$date|date_format:"Y-m-d"}

{* Format number *}
{$price|number_format}

{* Multiple modifiers *}
{$text|strip_tags|truncate:50}

Array Modifiers

To pass an entire array as a single value to a modifier, prefix with @:

{* Count array elements *}
{$items|@count}

{* Get array values *}
{assign var="values" value=$array|@array_values}

{* Sort array *}
{assign var="sorted" value=$array|@rcms_sort}

{* JSON encode *}
{assign var="json" value=$array|@json_encode}
info

The @ prefix retains its standard Smarty meaning (pass the array as a whole rather than mapping the modifier over each element); it is not a Kuroco-specific marker.

Two sources of modifiers

Modifiers in Kuroco templates come from two distinct sources, and it matters which one you're using:

  1. Modifier plugins — files such as modifier.count.php, modifier.empty.php, modifier.in_array.php, modifier.split.php, modifier.to_object.php. Each plugin defines a modifier of the same name, and works regardless of the PHP-function allow-list. Examples: {$arr|@count}, {$user|empty}, {$item|to_object}. See Smarty Plugin for the available plugins.
  2. PHP-function pass-through — any function in Kuroco's MODIFIER_FUNCS allow-list can be used as a modifier even though no plugin file exists for it. The call goes through a type-validation wrapper, so if an argument's type does not match the function's signature the result is null (and the error is surfaced through Kuroco's error pipeline outside of validation mode) — there is no PHP fatal error. See PHP Functions Available for Kuroco's Smarty for the list.
{$text|strlen}              {* PHP-function pass-through *}
{$arr|@count} {* served by modifier.count.php plugin *}
{$value|intval} {* PHP-function pass-through *}

Reference-taking functions (sort, push, etc.) interact with the safe array access behavior described under Undefined Variables and Array Keys — see the exception there.

Suppressing default modifiers (|smarty:nodefaults / |raw)

If a global default modifier chain is configured, prefix a variable's modifier chain with |smarty:nodefaults (or its alias |raw) to suppress it for that specific output.

{$html_content|raw}              {* skip default escape/etc. *}
{$untrusted|smarty:nodefaults} {* same effect *}

Date Handling

Date Formatting

Use the date_format modifier to format dates in a specified format.

Basic Syntax

{$date|date_format:"format"}

Example

{$date|date_format:"Y-m-d"}
{$date|date_format:"Y/m/d"}
{$date|date_format:"H:i:s"}

Date Format Specifiers

Kuroco's date_format supports format specifiers from PHP's date() function. When the format string contains %, strftime-style codes are internally converted to PHP date() format before processing.

SpecifierDescriptionExample
Y4-digit year2024
y2-digit year24
mMonth (01-12)01, 12
nMonth (1-12)1, 12
dDay (01-31)01, 31
jDay (1-31)1, 31
HHour (00-23)00, 23
hHour (01-12)01, 12
iMinutes (00-59)00, 59
sSeconds (00-59)00, 59
wDay of week (0-6, 0=Sunday)0, 6
DShort day nameMon, Sun
lFull day nameMonday, Sunday
MShort month nameJan, Dec
FFull month nameJanuary, December
AAM/PM (uppercase)AM, PM
aAM/PM (lowercase)am, pm

Common Format Examples

{* YYYY-MM-DD format *}
{$date|date_format:"Y-m-d"}

{* YYYY/MM/DD format *}
{$date|date_format:"Y/m/d"}

{* YYYY-MM-DD HH:MM:SS format *}
{$date|date_format:"Y-m-d H:i:s"}
tip

$smarty.now returns the current timestamp. Placing the following code at the beginning of a custom function restricts execution to Mondays only.

{if $smarty.now|date_format:"D" != "Mon"}{return}{/if}

When run on any other day, {return} exits immediately. This is useful when you want to schedule a batch process to run daily but limit the actual processing to Mondays only.

strftime Format Specifiers

strftime format specifiers (such as %Y, %m, %d) can also be used. Format strings containing % are automatically converted to PHP date() format internally.

Relative Date Processing

Use PHP's strtotime function to process relative date strings.

Basic Syntax

{$date_string|strtotime|date_format:"format"}

Example

{* Last day of next month *}
{assign var="day" value="last day of next month"|strtotime|date_format:"Y-m-d"}

Function Calls

function Statement

Use the {function} statement to call another custom function.

Basic Syntax

{function name="function_name" var="result_variable" param1="value1" param2="value2"}

The calling and called functions have separate scopes. Pass values as arguments and use {return} to return results.

Example

{* Calling function *}
{function name="send_notification" var="send_result" to=$member.email subject="Registration Complete" message=$greeting}

{if $send_result}
Email sent successfully
{else}
Email sending failed
{/if}

For details, see Smarty Plugin.

Kuroco-specific Smarty behavior and restrictions

The {php} block cannot be used

Standard Smarty 2's {php}...{/php} block and inline <?php ?> tags cannot be used in Kuroco templates. Kuroco runs Smarty in security mode and does not permit raw PHP from a template. Use plugin tags ({assign}, {assign_array}, {append}, {api}, etc.) and the allow-listed function calls instead.

Kuroco-specific behavior of $smarty.*

ReferenceBehavior in Kuroco
$smarty.cookiesDisabled. Always null. Read cookies on the server side.
$smarty.envDisabled. Always null.
$smarty.serverAvailable, but sensitive keys such as DOCUMENT_ROOT, SCRIPT_FILENAME, SERVER_SOFTWARE, SERVER_ADDR, SERVER_PORT, REMOTE_PORT, and REDIRECT_STATUS are stripped before the template receives it. Other keys can be referenced as usual.
$smarty.rcms_validateKuroco-specific. True when the template is running in validation mode. Use it to skip side-effecting operations during a dry run.
{if !$smarty.rcms_validate}
{* skip while validating *}
{api endpoint="..." method="POST" var=resp}
{/if}

Support

If you have any other questions, please contact us or check out Our Slack Community.