Platform CLI
Learn
Developer docs User guide Quickstart CLI and AI agents Blog
Company
Services About Contact Links Get started

How Liquid templates work in Raytha

Updated

Raytha templates are HTML with a few placeholders written in Liquid. If you can read HTML, you can read a Liquid template. This page teaches the handful of Liquid ideas you need to make small, safe changes to your theme.

The idea

A template is a page with blanks. Raytha fills the blanks with your data (a post's title, the site name, a list of events) and sends the finished HTML to the visitor. There are two kinds of placeholder:

  • {{ ... }} prints a value.
  • {% ... %} does something: a condition, a loop, a command. It prints nothing itself.

You edit templates under Themes, on a theme's Web templates or Widget templates tab. See Themes and web templates. Raytha checks the syntax when you save.

Where the data comes from

Every page template can read a few standard names. The editor's Variables side panel lists the ones available to the template you have open; click one to insert it.

NameWhat it is
TargetThe thing this page is about: the content item on a detail page, the list of items on a list page.
ContentTypeThe content type of the item or list (ContentType.LabelPlural, ContentType.DeveloperName).
CurrentOrganizationSite-wide settings such as OrganizationName and WebsiteUrl.
CurrentUserThe visitor: IsAuthenticated, IsAdmin, FirstName, FullName.
PathBaseText to put in front of site links when Raytha is served under a sub-path. Use it in internal links, as the built-in templates do.
widgetOnly in widget templates: the widget's settings as widget.settings.<name>.

Your own fields live under the content item. A field with developer name event_date is Target.PublishedContent.event_date. Most field values have two parts: .Text (ready to display) and .Value (the raw value).

Example 1: print a value

<h1>{{ Target.PrimaryField }}</h1>
<p>Part of {{ CurrentOrganization.OrganizationName }}</p>
<div>{{ Target.PublishedContent.content.Text }}</div>

PrimaryField is the item's name. content is the developer name of the rich text field that every new content type has. If you ask for a name that does not exist, you usually get nothing printed, not an error.

Example 2: format with filters

A filter changes a value. Put it after a vertical bar. Some filters take extra input after a colon.

{{ Target.PrimaryField | upcase }}
{{ Target.CreationTime | organization_time: "%b %e, %Y" }}
{{ Target.PublishedContent.content.Text | strip_html | truncate: 120, "..." }}

The first shows the title in capitals. The second prints the creation date in your site's time zone as, for example, Apr 18, 2026. The third removes HTML tags and cuts the text to 120 characters, which makes a handy preview. Filters chain left to right. Raytha adds its own filters on top of the standard Liquid ones: organization_time, attachment_public_url, attachment_redirect_url, groupby and json.

Example 3: show something only sometimes

{% if CurrentUser.IsAuthenticated %}
  Hello, {{ CurrentUser.FirstName }}
{% else %}
  <a href="{{ PathBase }}/account/login">Log in</a>
{% endif %}

Use {% if %} with {% elsif %}, {% else %} and {% endif %}. {% unless x %} is the opposite of {% if x %}. An empty value counts as false, so you can guard optional content, as the built-in templates do for images:

{% if Target.PublishedContent.featured_image %}
  <img src="{{ Target.PublishedContent.featured_image.Value | attachment_public_url }}" alt="">
{% endif %}

Image and file fields hold the file's key. Pass .Value to attachment_public_url to get the address.

Example 4: repeat for each item

On a list page, Target.Items is the page of items. Loop over it:

{% for item in Target.Items %}
  <h2><a href="{{ PathBase }}/{{ item.RoutePath }}">{{ item.PrimaryField }}</a></h2>
{% else %}
  <p>Nothing here yet.</p>
{% endfor %}

Inside the loop, item is one entry. The {% else %} branch runs when the list is empty. List pages also know Target.TotalCount, Target.PageNumber and Target.TotalPages for paging.

Example 5: show a menu

get_main_menu() fetches the menu marked as the main menu; get_menu("developer_name") fetches any other. See Manage navigation menus.

{% assign menu = get_main_menu() %}
<ul>
  {% for menuItem in menu.MenuItems %}
    {% unless menuItem.IsDisabled %}
      <li><a href="{{ menuItem.Url }}">{{ menuItem.Label }}</a></li>
    {% endunless %}
  {% endfor %}
</ul>

{% assign %} stores a value under a name. Each menu item also has OpenInNewTab, CssClassName and its own MenuItems for children. Raytha does not hide disabled items for you, which is why this example checks IsDisabled.

Example 6: pull in content from elsewhere

A template can fetch content that is not the page's own, for example your latest posts on the home page:

{% assign latest = get_content_items(ContentType="posts", Filter="", OrderBy="CreationTime desc", PageNumber=1, PageSize=3) %}
{% for post in latest.Items %}
  <a href="{{ PathBase }}/{{ post.RoutePath }}">{{ post.PrimaryField }}</a>
{% endfor %}

Only published items are returned. Filter and OrderBy use the same expression syntax as the REST API; see OData in templates. For no code at all, the Content List widget does the same job; see the widgets reference.

Layouts and sections

Two Raytha-specific tags tie templates together:

  • {% renderbody %} goes in a base layout. It marks where each child template's output is placed. Every layout must contain it.
  • {{ render_section("main") }} goes in a page template for site pages. It marks a section where the widgets you add in the page builder appear.
<main>
  {% renderbody %}
</main>

The same Liquid is used for email templates, with Target being the person receiving the email; see Modifying the built-in email templates.

Comments and mistakes

Wrap notes to yourself in {% comment %} ... {% endcomment %}; they are not sent to the visitor. If you save and see an error about syntax, check that every {% if %}, {% for %} and {% unless %} has its matching end tag, and that every {{ has a }}.

Gotchas

  • A saved template can still fail when rendered. Raytha refuses syntax errors when you save, but it cannot know whether the page has the data you asked for. Always load a page after changing it.
  • Template edits are live at once, with no draft. Revert from the template's Revisions panel; see Revisions and publishing.
  • Do not copy Liquid from other platforms blindly. The tags and filters Raytha supports are the ones in the editor's suggestions. Type {% or | to see them.
  • Use the exact developer name of a field. Copy it from the Variables panel or the content type's Fields page.

Next steps