Templater is a template language that lets you insert variables and functions results into your notes. It will also let you execute JavaScript code manipulating those variables and functions.

With Templater, you will be able to create powerful templates to automate manual tasks.

Quick Example

The following template file, that is using Templater syntax:

creation date: <% tp.file.creation_date() %>
modification date: <% tp.file.last_modified_date("dddd Do MMMM YYYY HH:mm:ss") %>

<< [[<%"YYYY-MM-DD", -1) %>]] | [[<%"YYYY-MM-DD", 1) %>]] >>

# <% tp.file.title %>

<% tp.web.daily_quote() %>

Will produce the following result when inserted:

creation date: 2021-01-07 17:20
modification date: Thursday 7th January 2021 17:20:43

<< [[2021-04-08]] | [[2021-04-10]] >>

# Test Test

> Do the best you can until you know better. Then when you know better, do better.
> &mdash; <cite>Maya Angelou</cite>


You can install this plugin via the Community Plugins tab within Obsidian. Search for "Templater".

It's a good practice to restart the obsidian app after the installation of Templater, to make sure everything is working properly.


To understand how Templater works, let's define a few terms:

  • A template is a file that contains commands.
  • A text snippet that starts with an opening tag <%, ends with a closing tag %> is what we will call a command.
  • A function is an object that we can invoke inside a command and that returns a value (the replacement string)

There are two types of functions you can use:


The following template contains 2 commands, calling 2 different internal functions:

Yesterday: <%"YYYY-MM-DD") %>
Tomorrow: <%"YYYY-MM-DD") %>

We'll see in the next part the syntax required to write some commands.


Templater uses a custom templating engine (rusty_engine) syntax to declare a command. You may need a bit of time to get used to it, but once you get the idea, the syntax is not that hard.

All of Templater's functions are JavaScript objects that are invoked using a command.

Command syntax

A command must have both an opening tag <% and a closing tag %>.

A complete command using the internal function would be: <% %>

Function syntax

Objects hierarchy

All of Templater's functions, whether it's an internal function or a user function, are available under the tp object. You could say that all our functions are children of the tp object. To access the "child" of an object, we have to use the dot notation .

This means that a Templater function invocation will always start with tp.<something>

Function invocation

To invoke a function, we need to use a syntax specific to functions calls: appending an opening and a closing parenthesis after the function name.

As an example, we would use to invoke the internal function.

A function can have arguments and optional arguments. They are placed between the opening and the closing parenthesis, like so:, arg2_value, arg3_value, ...)

All arguments must be passed in the correct order.

The arguments of a function can have different types. Here is a non-exhaustive list of the possible types of a function:

  • A string type means the value must be placed within simple or double quotes ("value" or 'value')
  • A number type means the value must be an integer (15, -5, ...)
  • A boolean type means the value must be either true or false (completely lower case), and nothing else.

The type of an argument must be respected when calling a function, or it won't work.

Function documentation syntax

The documentation for the internal functions of Templater are using the following syntax:

tp.<my_function>(arg1_name: type, arg2_name?: type, arg3_name: type = <default_value>, arg4_name: type1|type2, ...)


  • arg_name represents a symbolic name for the argument, to understand what it is.
  • type represents the expected type for the argument. This type must be respected when calling the internal function, or it will throw an error.

If an argument is optional, it will be appended with a question mark ?, e.g. arg2_name?: type

If an argument has a default value, it will be specified using an equal sign =, e.g. arg3_name: type = <default_value>.

If an argument can have different types, it will be specified using a pipe |, e.g. arg4_name: type1|type2

Syntax warning

Please note that this syntax is for documentation purposes only, to be able to understand what arguments the function expects.

You mustn't specify the name nor the type nor the default value of an argument when calling a function. Only the value of the arguments are required, as explained here


Let's take the internal function documentation as an example: string = "YYYY-MM-DD", offset?: number|string, reference?: string, reference_format?: string)

This internal function has 4 optional arguments:

  • a format of type string, with a default value of "YYYY-MM-DD".
  • an offset of type number or of type string.
  • a reference of type string .
  • a reference_format of type string .

That means that valid invocations for this internal function are:

  • <% %>
  • <%"YYYY-MM-DD", 7) %>
  • <%"YYYY-MM-DD", 7, "2021-04-09", "YYYY-MM-DD") %>
  • <%"dddd, MMMM Do YYYY", 0, tp.file.title, "YYYY-MM-DD") %> *Assuming the file name is of the format: "YYYY-MM-DD"

On the other hand, invalid invocations are:

  • string = "YYYY-MM-DD")
  • string = "YYYY-MM-DD", offset?: 0)


You can set a Template folder location to tell Templater to only check this folder for templates.

You can set a timeout for your system commands with the Timeout option. A system command that takes longer than what you defined will be canceled and considered as a failure.

You can set Templater to be triggered on new file creation. It will listen for the new file creation event and replace every command it finds in the new file's content.

This makes Templater compatible with other plugins like the Daily note core plugin, Calendar plugin, Review plugin, Note refactor plugin, ...

Security Warning

It can be dangerous if you create new files with unknown / unsafe content on creation. Make sure that every new file's content is safe on creation.

Folder Templates

You can specify a template that will automatically be used on a selected folder and children using the Folder Templates functionality.

Note: This setting is hidden by default. To view it first enable the Trigger Template on new file creation setting.

System Commands

You can enable system commands. This allows you to create user functions linked to system commands.

Arbitrary system commands

It can be dangerous to execute arbitrary system commands from untrusted sources. Only run system commands that you understand, from trusted sources.

Frequently Asked Questions

Unicode characters (emojis, ...) are not working on Windows ?

cmd.exe and powershell on Windows are known to have problems with unicode characters.

You can check for a solution.

Another good solution (probably the best) is to use Windows Terminal and set it as the default shell in Templater's setting.

Another resource containing solutions that could work for you:

Internal Functions

The different internal variables and functions offered by Templater are available under different modules, to sort them. The existing internal modules are:

If you understood the object hierarchy correctly, this means that a typical internal function call looks like this: <% tp.<module_name>.<internal_function_name> %>


I invite everyone to contribute to this plugin development by adding new internal functions. More information here.

Config Module

This module exposes Templater's running configuration.

This is mostly useful when writing scripts requiring some context information.



The active file (if existing) when launching Templater.


The RunMode, representing the way Templater was launched (Create new from template, Append to active file, ...)


The TFile object representing the target file where the template will be inserted.


The TFile object representing the template file.

Date Module

This module contains every internal function related to dates.


Function documentation is using a specific syntax. More information here string = "YYYY-MM-DD", offset?: number⎮string, reference?: string, reference_format?: string)

Retrieves the date.

  • format: Format for the date, refer to format reference

  • offset: Offset for the day, e.g. set this to -7 to get last week's date. You can also specify the offset as a string using the ISO 8601 format

  • reference: The date referential, e.g. set this to the note's title

  • reference_format: The date reference format. string = "YYYY-MM-DD")

Retrieves tomorrow's date.

Arguments string = "YYYY-MM-DD", weekday: number, reference?: string, reference_format?: string)

  • format: Format for the date, refer to format reference

  • reference: The date referential, e.g. set this to the note's title

  • reference_format: The date reference format.

  • weekday: Week day number. If the locale assigns Monday as the first day of the week, 0 will be Monday, -7 will be last week's day. string = "YYYY-MM-DD")

Retrieves yesterday's date.



Templater gives you access to the moment object, with all of its functionalities.

More information on moment.js here


Date now: <% %>
Date now with format: <%"Do MMMM YYYY") %>

Last week: <%"dddd Do MMMM YYYY", -7) %>
Today: <%"dddd Do MMMM YYYY, ddd") %>
Next week: <%"dddd Do MMMM YYYY", 7) %>

Last month: <%"YYYY-MM-DD", "P-1M") %>
Next year: <%"YYYY-MM-DD", "P1Y") %>

File's title date + 1 day (tomorrow): <%"YYYY-MM-DD", 1, tp.file.title, "YYYY-MM-DD") %>
File's title date - 1 day (yesterday): <%"YYYY-MM-DD", -1, tp.file.title, "YYYY-MM-DD") %>

Date tomorrow with format: <%"Do MMMM YYYY") %>    

This week's monday: <%"YYYY-MM-DD", 0) %>
Next monday: <%"YYYY-MM-DD", 7) %>
File's title monday: <%"YYYY-MM-DD", 0, tp.file.title, "YYYY-MM-DD") %>
File's title next monday: <%"YYYY-MM-DD", 7, tp.file.title, "YYYY-MM-DD") %>

Date yesterday with format: <%"Do MMMM YYYY") %>

File Module

This module contains every internal function related to files.


Function documentation is using a specific syntax. More information here


Retrieves the file's content

tp.file.create_new(template: TFile ⎮ string, filename?: string, open_new: boolean = false, folder?: TFolder)

Creates a new file using a specified template or with a specified content.

  • filename: The filename of the new file, defaults to "Untitled".

  • folder: The folder to put the new file in, defaults to obsidian's default location. If you want the file to appear in a different folder, specify it with app.vault.getAbstractFileByPath("FOLDERNAME")

  • open_new: Whether to open or not the newly created file. Warning: if you use this option, since commands are executed asynchronously, the file can be opened first and then other commands are appended to that new file and not the previous file.

  • template: Either the template used for the new file content, or the file content as a string. If it is the template to use, you retrieve it with tp.file.find_tfile(TEMPLATENAME)

tp.file.creation_date(format: string = "YYYY-MM-DD HH:mm")

Retrieves the file's creation date.

  • format: Format for the date, refer to format reference

tp.file.cursor(order?: number)

Sets the cursor to this location after the template has been inserted.

You can navigate between the different tp.file.cursor using the configured hotkey in obsidian settings.

  • order: The order of the different cursors jump, e.g. it will jump from 1 to 2 to 3, and so on. If you specify multiple tp.file.cursor with the same order, the editor will switch to multi-cursor.

tp.file.cursor_append(content: string)

Appends some content after the active cursor in the file.

  • content: The content to append after the active cursor

tp.file.exists(filename: string)

The filename of the file we want to check existence. The fullpath to the file, relative to the Vault and containing the extension, must be provided. e.g. MyFolder/SubFolder/MyFile.

  • filename: The filename of the file we want to check existence, e.g. MyFile.

tp.file.find_tfile(filename: string)

Search for a file and returns its TFile instance

  • filename: The filename we want to search and resolve as a TFile

tp.file.folder(relative: boolean = false)

Retrieves the file's folder name.

  • relative: If set to true, appends the vault relative path to the folder name.

Includes the file's link content. Templates in the included content will be resolved.

  • include_link: The link to the file to include, e.g. [[MyFile]], or a TFile object. Also supports sections or blocks inclusions, e.g. [[MyFile#Section1]]

tp.file.last_modified_date(format: string = "YYYY-MM-DD HH:mm")

Retrieves the file's last modification date.

  • format: Format for the date, refer to format reference.

tp.file.move(new_path: string, file_to_move?: TFile)

Moves the file to the desired vault location.

  • new_path: The new vault relative path of the file, without the file extension. Note: the new path needs to include the folder and the filename, e.g. /Notes/MyNote

tp.file.path(relative: boolean = false)

Retrieves the file's absolute path on the system.

  • relative: If set to true, only retrieves the vault's relative path.

tp.file.rename(new_title: string)

Renames the file (keeps the same file extension).

  • new_title: The new file title.


Retrieves the active file's text selection.


Retrieves the file's tags (array of string)


Retrieves the file's title.


File content: <% tp.file.content %>

File creation date: <% tp.file.creation_date() %>
File creation date with format: <% tp.file.creation_date("dddd Do MMMM YYYY HH:mm") %>

File creation: [[<% (await tp.file.create_new("MyFileContent", "MyFilename")).basename %>]]

File cursor: <% tp.file.cursor(1) %>

File cursor append: <% tp.file.cursor_append("Some text") %>
File existence: <% await tp.file.exists("MyFolder/") %>
File existence of current file: <% await tp.file.exists(tp.file.folder(true)+"/"+tp.file.title+".md") %>

File find TFile: <% tp.file.find_tfile("MyFile").basename %>
File Folder: <% tp.file.folder() %>
File Folder with relative path: <% tp.file.folder(true) %>

File Include: <% tp.file.include("[[Template1]]") %>

File Last Modif Date: <% tp.file.last_modified_date() %>
File Last Modif Date with format: <% tp.file.last_modified_date("dddd Do MMMM YYYY HH:mm") %>

File Move: <% await tp.file.move("/A/B/" + tp.file.title) %>
File Move + Rename: <% await tp.file.move("/A/B/NewTitle") %>

File Path: <% tp.file.path() %>
File Path with relative path: <% tp.file.path(true) %>

File Rename: <% await tp.file.rename("MyNewName") %>
Append a "2": <% await tp.file.rename(tp.file.title + "2") %>

File Selection: <% tp.file.selection() %>

File tags: <% tp.file.tags %>

File title: <% tp.file.title %>
Strip the Zettelkasten ID of title (if space separated): <% tp.file.title.split(" ")[1] %>

Frontmatter Module

This modules exposes all the frontmatter variables of a file as variables.



Retrieves the file's frontmatter variable value.

If your frontmatter variable name contains spaces, you can reference it using the bracket notation like so:

<% tp.frontmatter["variable name with spaces"] %>


Let's say you have the following file:

alias: myfile
note type: seedling

file content

Then you can use the following template:

File's metadata alias: <% tp.frontmatter.alias %>
Note's type: <% tp.frontmatter["note type"] %>

Obsidian Module

This module exposes all the functions and classes from the obsidian API.

This is mostly useful when writing scripts.

Refer to the obsidian API declaration file for more information.

System Module

This module contains system related functions.


Function documentation is using a specific syntax. More information here


Retrieves the clipboard's content

tp.system.prompt(prompt_text?: string, default_value?: string, throw_on_cancel: boolean = false, multiline?: boolean = false)

Spawns a prompt modal and returns the user's input.

  • default_value: A default value for the input field

  • multiline: If set to true, the input field will be a multiline textarea

  • prompt_text: Text placed above the input field

  • throw_on_cancel: Throws an error if the prompt is canceled, instead of returning a null value

tp.system.suggester(text_items: string[] ⎮ ((item: T) => string), items: T[], throw_on_cancel: boolean = false, placeholder: string = "", limit?: number = undefined)

Spawns a suggester prompt and returns the user's chosen item.

  • items: Array containing the values of each item in the correct order.

  • limit: Limit the number of items rendered at once (useful to improve performance when displaying large lists)

  • placeholder: Placeholder string of the prompt

  • text_items: Array of strings representing the text that will be displayed for each item in the suggester prompt. This can also be a function that maps an item to its text representation.

  • throw_on_cancel: Throws an error if the prompt is canceled, instead of returning a null value


Clipboard content: <% tp.system.clipboard() %>

Entered value: <% tp.system.prompt("Please enter a value") %>
Mood today: <% tp.system.prompt("What is your mood today ?", "happy") %>

Mood today: <% tp.system.suggester(["Happy", "Sad", "Confused"], ["Happy", "Sad", "Confused"]) %>
Picked file: [[<% (await tp.system.suggester((item) => item.basename, app.vault.getMarkdownFiles())).basename %>]]

const execution_value = await tp.system.suggester(["Yes", "No"], ["true", "false"])
Are you using Execution Commands: <%*  tR + execution_value %>

Web Module

This modules contains every internal function related to the web (making web requests).


Function documentation is using a specific syntax. More information here


Retrieves and parses the daily quote from the API

tp.web.random_picture(size?: string, query?: string, include_size?: boolean)

Gets a random image from

  • include_size: Optional argument to include the specified size in the image link markdown. Defaults to false

  • query: Limits selection to photos matching a search term. Multiple search terms can be passed separated by a comma ,

  • size: Image size in the format <width>x<height>


Web Daily quote:  
<% tp.web.daily_quote() %>

Web Random picture: 
<% tp.web.random_picture() %>

Web Random picture with size: 
<% tp.web.random_picture("200x200") %>

Web random picture with size + query: 
<% tp.web.random_picture("200x200", "landscape,water") %>


You can contribute to Templater by developing a new internal function / variable.

The process to develop a new one is really easy.

Keep in mind that only pertinent submissions will be accepted, don't submit a very specific internal variable / function that you'll be the only one using.


Internal variables / functions are sorted by modules. Each module has a dedicated folder under src/InternalTemplates.

Let's take the date module as an example.

It contains an InternalModuleDate file where all our internal date's related variables and functions are defined and registered:

export class InternalModuleDate extends InternalModule {
    name = "date";

    async createStaticTemplates() {
        this.static_templates.set("now", this.generate_now());
        this.static_templates.set("tomorrow", this.generate_tomorrow());
        this.static_templates.set("yesterday", this.generate_yesterday());

    async updateTemplates() {}

    generate_now() {
        return (format: string = "YYYY-MM-DD", offset?: number, reference?: string, reference_format?: string) => {
            if (reference && !window.moment(reference, reference_format).isValid()) {
                throw new Error("Invalid title date format, try specifying one with the argument 'reference'");
            return get_date_string(format, offset, reference, reference_format);

    generate_tomorrow() {
        return (format: string = "YYYY-MM-DD") => {
            return get_date_string(format, 1);

    generate_yesterday() {
        return (format: string = "YYYY-MM-DD") => {
            return get_date_string(format, -1);

Every module extends the InternalModule abstract class, which means they contain the following attributes and methods:

  • attribute: the obsidian API App object.
  • this.file attribute: The destination file where the template will be inserted.
  • this.plugin attribute: The Templater plugin object.
  • this.static_templates attribute: A map containing all (name; variable/function) that are static. A static variable / function means that it doesn't depend on the file when executed. These type of variables / functions won't be updated each time we insert a new template, to save some overhead.
  • this.dynamic_templates attribute: Same as static_templates except that it contains variables / functions dependent on the file when executed.
  • this.createStaticTemplates() method: Registers all static internal variable / function for that module.
  • this.updateTemplates() method: Registers every dynamic internal variable / function for that module.

You can use these attributes in your new internal variable / function if you need them.

Registering a new internal variable / function

Here are the different steps you need to follow, in order to register a new internal variable / function in a module.

1st step: Create a method inside the module called generate_<internal_variable_or_function_name>() that will generate your internal variable / function, that means it will return either a lambda function (representing the internal function) or directly the internal variable you want to expose.

All generation methods are ordered by alphabetical order based on the internal variable / function name.

Try to give a good, self-explanatory name for your variable / function.

2nd step: Register your internal variable / function in the static_templates or dynamic_templates map depending on whether your internal variable / function on the file when executed. The registration happens either in createStaticTemplates or updateTemplates.

To register your variable / function, use your this.generate_<internal_variable_or_function_name>() method you defined earlier:

this.static_templates.set(<internal_variable_or_function_name>, this.generate_<internal_variable_or_function_name>());
this.dynamic_templates.set(<internal_variable_or_function_name>, this.generate_<internal_variable_or_function_name>());

Internal variable / function registrations are also ordered by alphabetical order based on the variable / function name.

3rd step: Add your internal variable / function documentation to Templater's documentation.

And you are done ! Thanks for contributing to Templater !

Now, just submit a pull request on Github, I'll try to be as reactive as possible.

User Functions

You can define your own functions in Templater.

There are two types of user functions you can use:

Invoking User Functions

You can call a user function using the usual function call syntax: tp.user.<user_function_name>(), where <user_function_name> is the function name you defined.

For example, if you defined a system command user function named echo, a complete command invocation would look like this:

<% tp.user.echo() %>

No mobile support

Currently user functions are unavailable on Obsidian for mobile.

Script User Functions

This type of user functions allows you to call JavaScript functions from JavaScript files and retrieve their output.

To use script user functions, you need to specify a script folder in Templater's settings. This folder needs to be accessible from your vault.

Define a Script User Function

Let's say you specified the Scripts folder as your script folder in Templater's settings.

Templater will load all JavaScript (.js files) scripts in the Scripts folder.

You can then create your script named Scripts/my_script.js (The .js extension is required) for example.

You will then be able to call your scripts as user functions. The function name corresponds to the script file name.

Scripts should follow the CommonJS module specification, and export a single function.

Let's have an example with our previous script my_script.js.

Note that instead of outputting directly to the console, as we did earlier, a user script needs to return its output:

function my_function (msg) {
    return `Message from my script: ${msg}`;
module.exports = my_function;

In our previous example, a complete command invocation would look like this:

<% tp.user.my_script("Hello World!") %>

Which would print Message from my script: Hello World! in the console.

Global namespace

In script user functions, you can still access global namespace variables like app or moment.

However, you can't access the template engine scoped variables like tp or tR. If you want to use them, you must pass them as arguments for your function.

Functions Arguments

You can pass as many arguments as you want to your function, depending on how you defined it.

You can for example pass the tp object to your function, to be able to use all of the internal variables / functions of Templater: <% tp.user.<user_function_name>(tp) %>

System Command User Functions

This type of user functions allows you to execute system commands and retrieve their output.

System command user functions need to be enabled in Templater's settings.

Define a System Command User Function

To define a new system command user function, you need to define a function name, associated with a system command.

To do that, go to the plugin's settings and click Add User Function.

Once this is done, Templater will create a user function named after what you defined, that will execute your system command and return its output.

Just like internal functions, user functions are available under the tp JavaScript object, and more specifically under the tp.user object.


Functions Arguments

You can pass optional arguments to user functions. They must be passed as a single JavaScript object containing properties and their corresponding values: {arg1: value1, arg2: value2, ...}.

These arguments will be made available for your programs / scripts in the form of environment variables.

In our previous example, this would give the following command declaration: <% tp.user.echo({a: "value 1", b: "value 2"}).

If our system command was calling a bash script, we would be able to access variables a and b using $a and $b.

Internal functions in system commands

You can use internal functions inside your system command. The internal functions will be replaced before your system command gets executed.

For example, if you configured the system command cat <% tp.file.path() %>, it would be replaced with cat /path/to/file before the system command gets executed.


Command Types

Templater defines 3 types of opening tags, that defines 3 types of commands:

  • <%: Interpolation command. It will output the result of the expression that's inside.
  • <%*: JavaScript execution command. It will execute the JavaScript code that's inside. It does not output anything by default.

The closing tag for a command is always the same: %>

Command utilities

In addition to the 3 different types of commands, you can also use command utilities. They are also declared in the opening tag of the command, and they work with all the command types. Available command utilities are:

Dynamic Commands

With this command utility, you can declare a command as "dynamic", which means that this command will be resolved when entering preview mode.

To declare a dynamic command add a plus + sign after the command opening tag: <%+

That's it, your command will now be executed only in preview mode.

This is useful for internal functions like tp.file.last_modified_date for example:

Last modified date: <%+ tp.file.last_modified_date() %>

Refresh problems

One "downside" of the preview mode is that it puts the rendered note in cache, to speed things up.

This means that your dynamic command will be rendered only once, when you open the note, but won't be refreshed after.

If you want to refresh it, you must close the note to clear the cache and open it again.

Javascript Execution Command

This type of command allows us to execute JavaScript code.

With a JavaScript Execution command, we can pretty much do everything that JavaScript allows us to do. Some examples are given below.

We can still access the tp object and all the internal variables / functions from this type of command.

JavaScript Execution commands let you access global namespace variables. This means you can access things like app or moment.

Asynchronous functions

Some internal functions are asynchronous. When calling such functions inside a JavaScript execution command, don't forget to use the await keyword if necessary.

How to output a value from a JavaScript Execution Command ?

Sometimes, you may want to output something when using a JS execution command.

When our templating engine generates a replacement string using all of our commands results, it is stored in a variable named tR. This is the string that will contain the processed file content. You are allowed to access that variable from a JS execution command.

This means that, to output something from a JS execution command, you just need to append what you want to output to that tR string variable.

For example, the following command: <%* tR += "test" %> will output test.

Suggesters and Prompts

It is important to note that the tp.system.prompt() and tp.system.suggester() both require a await statement to save the value to a variable


Here are some examples of things you can do using JavaScript Execution Commands:

<%* if (tp.file.title.startsWith("Hello")) { %>
This is a hello file !
<%* } else { %>
This is a normal file !
<%* } %>
<%* if (tp.frontmatter.type === "seedling") { %>
This is a seedling file !
<%* } else { %>
This is a normal file !
<%* } %>
<%* if (tp.file.tags.contains("#todo")) { %>
This is a todo file !
<%* } else { %>
This is a finished file !
<%* } %>

function log(msg) {
<%* log("Title: " + tp.file.title) %>
<%* tR += tp.file.content.replace(/stuff/, "things"); %>

Whitespace Control

By default, commands in Templater are not removing any newlines. Commands are replaced with their values and that's it.

It can sometimes be useful to have some whitespace control after commands are inserted, which is exactly what this command utility offers.

Let's have an example. The following template:

<%* if (tp.file.title == "MyFile" ) { %>
This is my file!
<%* } else { %>
This isn't my file!
<%* } %>
Some content ...

Will produce the following output if the condition is false (the same happens when it's true), notice the blank lines:

This isn't my file!

Some content ...

You may want to remove the blank lines produced by the execution commands, that do not produce any output.

A specific syntax exists for whitespace control:

  • An underscore _ at the beginning of a tag (<%_) will trim all whitespace before the command
  • An underscore _ at the end of a tag (_%>) will trim all whitespace after the command
  • A dash - at the beginning of a tag (<%-) will trim one newline before the command
  • A dash - at the end of a tag (-%>) will trim one newline after the command.

In our example, to fix our template to remove the blank lines, we would use the following template (notice the dashes - at the end of the tags), to remove the blank newlines after the execution commands:

<%* if (tp.file.title == "MyFile" ) { -%>
This is my file!
<%* } else { -%>
This isn't my file!
<%* } -%>
Some content ...

Which would produce the following output:

This isn't my file!
Some content ...