---
url: https://docs.juniper.bot/en/message-templates/advanced/tags.md
description: Template Engine Tags
---

# Tags

Tags are a set of various built-in constructs and operations over a template. They are declared using [code islands](code-islands) and defines the behavior of the template.

::: tip Recommendation
It is recommended to check [Data Types](../types/index) and [Type Conversion](../types/type-convert) articles before you proceed to tags.
:::

## Commands { #commands }

Command constructs allows one to run specific commands against template. An important aspect common to all commands is
that they never produce content, they only produce side effects.

### `set`

The `set` command allows to specify an assignment operation inside a template, it will assign to the result of an expression to the specified variable:

```template
{% set five = 2 + 3 %}
```

In previous example we assigned the result of evaluating the expression `2 + 3` to the variable `five`.

The `set` command also supports compound assignment operators using common [binary operators](expressions#binary) for
arithmetic operations (`+`, `-`, `*`, `**`, `/`, `//`) and string concatenation (`~`):

```template
{% set value = 2 %}
{% set value += 3 %}
```

In previous example the resulting value of variable will be 5.

Variable name is an [identifier](expressions#identifiers) and can only contain alphanumeric (latin) characters and
underscores, but cannot start with digits.

Note again that the output of previous example will be empty because, as mentioned before, `set` as a command, does not
produce content, it just affects the context defining, or redefining a variable.

### `global`

Variables defined using command `set` have local scope and will be only available in the template where they are defined.
The `global` command is the same as `set` but it will assign the result of evaluating the expression in global context.

It means the global variable will be available in [macros](#macro), following template values of message template and in
the action executed by [`run`](#run). For example, a global variable defined in Message Content Template will be also
available in Embed Content Template.

```template
{% global six = 3 + 3 %}
```

In previous example we assigned the result of evaluating the expression `3 + 3` to the variable `six` and will be available globally.

::: tip Local override

Variable defined using `set` command has local scope, so it can override the value of a previously defined
`global` variable with the same name. It will not overwrite the global variable's actual value, but override it.

You can reset `set` override, so global value would be in effect again by redefining it with undefined value:

```template
{% global value = 'global_value' %}
{{ value }}
{# ^ prints "global_value" #}
{% set value = 'set_value' %}
{{ value }}
{# ^ prints "set_value" #}
{% set value = undefined %}
{# ^ "undefined" can be any variable name that has been never defined #}
{{ value }}
{# ^ prints "global_value" #}
```

:::

### `do`

The `do` command just evaluates a given expression, nothing will be printed to the template.

```template
{% do channel.sendMessage('Моё сообщение!') %}
```

It might be useful for invoking a function or object method silently.

### `require`

The `require` is an extension of [`return`](#return):

```template
{% require expression returning 'Some error just happened!' %}
```

This command will only return an error if result of evaluating the expression is `false` according the `Type Convert`.

You can pass an [Embed](../types/discord/embed) instead of string (but keep in mind that you shouldn't send it using its `send` method).

Being an extension of [`return`](#return), this tag does have the same behavior in [transformations](#transforms) and [macros](#macro).

### `use`

The `use` command enables additional template behaviour.

#### strict

Enables template evaluation in strict mode. This means that the Template Engine will return a compilation error in the following cases:

* Attempt to output an undefined variable;
* Attempt to access a non-existent property of an object;
* An attempt to call a non-existent function, object method or with incorrectly passed arguments.

You can enable this behavior the following way:

```template
{% use 'strict' %}
```

### `run`

The `run` command is used to run specified [Action](../../cmd/custom/actions/index) and optionally pass there some parameters.
This operation will interrupt current running action.

::: warning
This tag is only working in Custom Commands [Actions](../../cmd/custom/actions/index) so you can "route" one action to another.
:::

Use action's UUID to run it:

```template
{% run 'aebf9ae8-c62a-4348-b153-a7c0a0173da1' %}
```

::: info
You can get this UUID from action form itself in the command settings (press "i" icon).

Both actions must be the part of the same exact command, e.g. you can't run action of command A from the action of command B.
:::

Use this syntax to pass some parameters to child action:

```template
{% run 'aebf9ae8-c62a-4348-b153-a7c0a0173da1' with { 'param1': 123 } %}
```

The expression after `with` is just a [map](../types/index#maps), so you can use a predefined variable instead.
Those parameters will be available as part of [parameters](../types/custom-commands/parameters) variable in child action:

```template
{{ parameters.param1 }}
```

Template above will print `123` in child action.

You can also use the [parameters](../types/custom-commands/parameters) itself in the parent action to pass the data to child action.
The following example will do the same thing as previous, just in a different way:

```template
{% do parameters.store('param1', 123) %}
{% run 'aebf9ae8-c62a-4348-b153-a7c0a0173da1' %}
```

::: warning
Actions may run each other in chain up to 3 times. Methods quotas will be shared across the whole chain.
:::

## Control Flow { #control }

Template Engine implements basic control flow constructs such as `if` conditions and `for` loops.

### Conditions — `if/elseif/else` { #if }

`If` conditions are the simplest control flow in Template Engine. It supports consecutive `elseif` conditions and the common `else` construct too.

```template
{% if (expression) %}
... content if expression is evaluated to true ...
{% elseif (anotherExpression) %}
... content if anotherExpression is evaluated to true ...
{% else %}
... content if none of previous conditions are met ...
{% endif %}
```

Note that the whole `if` construct will only output the content of the first block which condition is evaluated to `true`
according to [Type Conversion](../types/type-convert).

In terms of variable scoping, `if` inner content shares the context with the parent context, this means `if` conditions
can affect variables in the outer scope.

```template
{% set variable = "a" %}
{% if (true) %}
    {% set variable = "b" %}
{% endif %}
{{ variable }}
```

Previous example will output `b` which illustrates how scoping works on if conditions by sharing the context with the parent construct.

```template
{% if (1 != 2) %}
    {% return '1 is not 2. Oh wow!' %}
{% endif %}
This text will not be printed because the error.
```

Previous example will conditionally return an error.

### Loops — `for` { #loops }

Template Engine allows iterating over a list or a map.

```template
{# Example with list #}
{% for item in list %}
... content using variable item ...
{% endfor %}

{# Example with map #}
{% for key, value in map %}
... content using variables key and value ...
{% endfor %}
```

The scope of iterator variables (`item`, `key`, and `value` in the examples above) is limited solely to the loop block,
even if they are redefined using the [`set`](#set) command.

#### `loop` variable { #loop-variable }

`for` loops come with an extra variable defined in the context, the `loop` variable. The loop variable provides a set of
useful properties when within a for loop, check below the properties exposed by this variable:

| Property    | Description                                                                   |
|:------------|:------------------------------------------------------------------------------|
| `length`    | Size of the list or map being iterated                                        |
| `index`     | Current iteration count starting in 1                                         |
| `index0`    | Current iteration count starting in 0                                         |
| `revindex`  | Remaining number of iterations to reach the end of the list or map, ends in 1 |
| `revindex0` | Remaining number of iterations to reach the end of the list or map, ends in 0 |
| `first`     | Boolean property only `true` in the first iteration                           |
| `last`      | Boolean property only `true` in the last iteration                            |
| `parent`    | Accessing the parent context                                                  |

```template
{% for item in [1, 2, 3] %}
    {% if (loop.first) %}
        Start
    {% endif %}
{% endfor %}
```

Previous example will output `Start` only once.

This `loop` variable is only bound to the `for` context, it means this variable will not be visible outside the for loop
scope. If there is a `loop` variable in the context, it will not be overridden but to access it one need to get the parent context, for example:

```template
{% set loop = 1 %}
{% for item in [1, 2, 3] %}
    {% if (loop.first) %}
        {{ loop.parent.loop }}
        {% set loop = 2 %}
    {% endif %}
{% endfor %}
{{ loop }}
```

Previous template will print `1 2`. Note that setting `loop` inside the for loop will write to the context, but won't
override the for loop bound variable. The value `loop` variable defined inside the loop is then available outside the loop scope.

::: warning Limitations

1. The maximum allowed nested loops depth is 2;
2. The maximum amount of iterations of loop including iterations of its nested loops is 3000.

:::

### Transformations — `transform` { #transforms }

Transformation is a variant of `for` loops used to transform one list to another.
Each transform iteration expects `return` tag to return new list element accordingly:

```template
{% transform item in [1, 2, 3] as newList %}
    {% return 'element:' ~ item %}
{% endtransform %}
{{ newList }}
```

Previous example will transform `[1, 2, 3]` list to `['element:1', 'element:2', 'element:3']` and saves the result to `newList` variable.

In case then `return` tag hasn't executed in iteration, corresponding list element will be skipped. Thus, we can use this to filter the list:

```template
{% transform item in [1, 2, 3] as newList %}
    {% if (item != 2) %}
        {% return item %}
    {% endif %}
{% endtransform %}
{{ newList }}
```

Previous example will transform `[1, 2, 3]` list to `[1, 3]`, excluding second element from the result according to condition.

::: info
Transformations inherits all `for` loops behavior, including `loop` variable and parent context.
:::

::: warning
Transformations cannot use nested lists/maps, such elements will be excluded from the result. In other words, you can't make list of lists or list of maps.

Also, transformations cannot print anything, output code islands inside transformations will be ignored.
:::

### `break/continue` { #break-continue }

You can interrupt [for loops](#loops) and [transformations](#transforms) iterations using `break` and `continue` tags.

`break` will break current and all next iterations of loop:

```template
{% for item in [1, 2, 3, 4] %}
    start:{{item}}
    {% if (item > 2) %}
        {% break %}
    {% endif %}
    end:{{item}}
{% endfor %}
```

Previous example will output `start:1 end:1 start:2 end:2 start:3` as third and all next iterations are being interrupted by `item > 2` condition.

`continue` will only break the current iteration of loop:

```template
{% for item in [1, 2, 3] %}
    start:{{item}}
    {% if (item == 2) %}
        {% continue %}
    {% endif %}
    end:{{item}}
{% endfor %}
```

Previous example will output `start:1 end:1 start:2 start:3 end:3`. Note that it lacks of `end:2` part as second iterations is being interrupted by `item == 2` condition.

### `return`

The `return` tag will interrupt template evaluation with an error returned to the user.
This tag is also used in [transformations](#transforms) and [macros](#macro).

```template
{% return 'Some error just happened!' %}
```

You can pass an [Embed](../types/discord/embed) instead of string (but keep in mind that you shouldn't send it using its `send` method).

You can also pass a `null`, this will prevent any template result, including any errors, from getting sent:

```template
{% return null %}
```

## Other { #other }

### `macro`

Macro constructs allows the user to reduce template code duplication.

This can be achieved by associating pieces of reusable templates to a specific named `macro/endmacro` constructs that
also allows them to receive arguments.

```template
{% macro macroName(firstArgument, secondArgument, ...) %}
  ... reusable template content ....
{% endmacro %}
```

#### Macro Name { #macro-name }

The macro name is an [identifier](expressions#identifiers) used to reference the macro. It must be unique inside a
template and must be defined only once. Attempt to define one more macro with the same name will lead to template execution error.

#### Macro Arguments { #macro-arguments }

Macro arguments is a list of identifiers representing input variables which can then be used inside the macro body
definition. All arguments are optional, it's up to the caller to provide such arguments or not. You can have macros without arguments at all.

#### Scope { #macro-scope }

Macros have access to the limited set of variables:

* Arguments passed to macros;
* [Global](#global) variables defined at the moment of macro execution;
* Default template variables.

Variables defined inside the macro are only available in scope of this macro. [Global](#global) will be available everywhere.

#### Execute Macro { #macro-execute }

You can execute defined macros just like [functions](functions). Think of macros like "user functions".

```template
{% macro fullname(firstName, lastName) %}
  {{ firstName ~ ' ' ~ lastName }}
{% endmacro %}

{{ fullname('Elon', 'Mask') }}
```

This example has a simple macros to get a full name based on two arguments (first name and last name).
Result of macro execution is string built by rendering its template with specified arguments.

Also, you can use [return](#return) tag in case you want to return specific data from macros (like value of variable or expression):

```template
{% macro fullname(firstName, lastName) %}
  Blahblahblah
  {% return firstName ~ ' ' ~ lastName %}
{% endmacro %}

{{ fullname('Elon', 'Mask') }}
```

Result of this template is the same as the previous one. Note that "Blahblahblah" text will not be present in result since macro uses [return](#return) to return specific data.

::: warning
Macros can't execute another macros.
:::

### `include`

This tag can be used to include Shared Template into current template.
Please visit [Shared Templates](../shared-templates) article for more detailed information.

```template
{% include 'my_template' %}
```

In previous example we have included Shared Template with name `my_template`.

#### Scope { #include-scope }

Shared Template will be executed in parent template context by default.
Simply put, it will be executed if you would paste the whole content of your Shared Template instead of its `include` tag.

All variables defined in parent template will be available in Shared Template as well as all variables defined in Shared
Template will be available in parent template after `include` tag.

However, this behavior can be changed by using `scoped` keyword:

```template
{% include 'my_template' scoped %}
```

In this case Shared Template will be executed in its own context. It can't access variables defined in parent template
and parent template will not be able to access variables defined as result of executing the Shared Template.

::: warning
[Global variables](#global) and [macros](#macro) are exceptions to this rule.

They will be available in Shared Template even in `scoped` mode, and their defining inside Shared Template will
make them available in parent template as well.
:::

If you still need to pass some data to Shared Template while using `scoped` mode, you can do that like this:

```template
{% include 'my_template' scoped with { 'param1': 123 } %}
```

The expression after `with` is just a [map](../types/index#maps), so you can use a predefined variable instead.
The key-value pairs will be available as usual variables inside Shared Template.

In previous, Shared Template will have `param1` variable assigned with value `123`;

### `filter`

The `filter` construct is the way apply [functions](functions) to a given content. It uses the provided body as the
first argument in the specified function.

```template
{% filter lower | capitalize -%}
HELLO WORLD
{%- endfilter %}
```

Previous example will produce `Hello world`. As we can see, the filter specified results in the composition of two
distinct functions, it will first apply the `lower` function to the content `HELLO WORLD`, producing `hello world` and
then apply the `capitalize` function producing `Hello world`.

### `verbatim`

The `verbatim` tag is useful avoiding the specifics around Template Engine syntax, as it will not try to parse the content.

```template
{% verbatim %}
{{ test }}
{% endverbatim %}
```

The output of previous template will be `{{ test }}`.
