Template variables
A Raytha template reads a handful of top-level variables. This page lists all of them, says which template kinds receive which, and documents the members of each object, including the value objects that wrap your custom fields.
How variables reach a template
Raytha renders every public template and every email template against one wrapper object. Its properties are the top-level variables you type in Liquid:
| Variable | Content detail | List view | Site page | Account pages | Error pages | Widget | |
|---|---|---|---|---|---|---|---|
Target | item | list | site page | form model | error model | no | user model |
ContentType | yes | yes | no | no | no | no | no |
CurrentOrganization | yes | yes | yes | yes | yes | no | yes |
CurrentUser | yes | yes | yes | yes | yes | no | no |
PathBase | yes | yes | yes | yes | yes | no | no |
QueryParams | yes | yes | yes | yes | yes | no | empty |
RequestVerificationToken | yes | yes | yes | no (use Target.RequestVerificationToken) | yes | no | no |
ViewData | empty | empty | empty | empty | empty | no | no |
| Raytha functions | yes | yes | yes | yes | yes | most | yes |
A variable marked "no" is not an error. It reads as nothing. In a widget, widget carries everything the widget needs, and get_content_items and the other data functions work (see Widget templates). Base layouts are not a separate kind here: a layout is joined into the child's source, so it sees the child's variables.
Rules that apply to every variable
- Names are case-sensitive and use the .NET spelling.
Target.primaryfieldis nothing.Target.PrimaryFieldis the title. - A missing member renders as an empty string. It is not an error, so check the HTML.
- Output is not escaped. Use
| escapefor any text a person typed. - Ids reach the template as strings. Comparing
item.Id == Target.Idworks, whichever side came from a related item. - Dates are UTC
DateTimevalues. Convert with| organization_time: "format"(see Functions and filters).
Target
Content item detail
One item. Members: Id, PrimaryField, RoutePath, PublishedContent, CreationTime, LastModificationTime, CreatorUser, LastModifierUser, Template and ContentType. They are described under Detail views vs list views. CreatorUser and LastModifierUser have Id, FirstName, LastName, FullName and EmailAddress, or are nothing.
List view
Items, TotalCount, PageNumber, PageSize, TotalPages, PreviousDisabledCss, NextDisabledCss, FirstVisiblePageNumber, LastVisiblePageNumber, Search, Filter, OrderBy, RoutePath, Label, DeveloperName and Description. Each entry in Items has the members of a content item detail Target.
Site page
| Member | Type | Notes |
|---|---|---|
Target.Id | string | |
Target.Title | string | The page title. There is no PrimaryField on a site page. |
Target.RoutePath | string | No leading slash. |
Target.IsPublished, Target.IsDraft | boolean | Both can be true while a page has unpublished edits. |
Target.WebTemplateId, Target.WebTemplateDeveloperName | string | The page's template. |
Target.CreationTime, Target.LastModificationTime | date (UTC) | The second is nothing until the first edit is saved. |
The widgets of the page are not on Target. You place them with render_section and get_section, covered in Site pages and sections.
Error pages
The templates raytha_html_error_403 and raytha_html_error_404 get an error model. A raytha_html_error_500 template exists in every theme, but the public site never renders it: a failed render returns a plain 500 response instead.
| Member | Notes |
|---|---|
Target.ErrorId | A short id when Raytha generates one (an unknown route). Empty otherwise. |
Target.ErrorMessage | For example the reason a registration was refused. |
Target.StackTrace | Only meaningful in Development mode. |
Target.IsDevelopmentMode | Guard anything technical with it. Never print StackTrace otherwise. |
Account pages
Built-in account templates receive a form model. Every one has these three members:
| Member | Notes |
|---|---|
Target.RequestVerificationToken | Put it in a hidden input named __RequestVerificationToken in every form. |
Target.ValidationFailures | A dictionary of messages keyed by input name, plus __ValidationSummary for general errors. Nothing when there are no errors. Read it with Target.ValidationFailures["EmailAddress"]. |
Target.SuccessMessage | For example "Profile successfully updated." Nothing otherwise. |
| Template developer name | Extra Target members |
|---|---|
raytha_html_login_emailandpassword, raytha_html_login_magiclink | ReturnUrl, HasLoginByEmailAndPassword, HasLoginByMagicLink, HasLoginBySingleSignOn, ShowOrLoginWithSection, EmailAndPassword, MagicLink (each an authentication scheme or nothing), SingleSignOns and AuthenticationSchemes (arrays of schemes) |
raytha_html_login_magiclinksent | EmailAddress, ReturnUrl |
raytha_html_user_registration | EmailAddress, FirstName, LastName (what was typed, to refill the form) |
raytha_html_forgotpasswordcomplete | Token |
raytha_html_changeprofile, raytha_html_changepassword, raytha_html_forgotpassword | none beyond the three above |
raytha_html_user_registration_success, raytha_html_forgotpassword_reset_link_sent, raytha_html_forgotpasswordsuccess | An empty model. Target has no members. |
An authentication scheme has Id, Label, DeveloperName, IsBuiltInAuth, IsEnabledForUsers, IsEnabledForAdmins, SignInUrl, LoginButtonText and SignOutUrl. The change-profile template shows the current name through CurrentUser.FirstName and CurrentUser.LastName.
ContentType
Set for content item detail and list templates. It is the content type of the item or view.
| Member | Notes |
|---|---|
ContentType.Id | |
ContentType.DeveloperName | For example posts. |
ContentType.LabelSingular, ContentType.LabelPlural | For example "Post" and "Posts". |
ContentType.Description |
It does not list the fields. For those, call get_content_type_by_developer_name.
CurrentOrganization
| Member | Type | Notes |
|---|---|---|
OrganizationName | string | The site name from the settings. |
WebsiteUrl | string | The public base URL. Use it for absolute links in emails and canonical tags. |
TimeZone | string | The organization time zone that organization_time converts to. |
DateFormat | string | The organization's date format string. |
HomePageId | string | The id of the item, view or site page set as the home page. |
SmtpDefaultFromAddress, SmtpDefaultFromName | string | The default sender. Do not print them on public pages. |
EmailAndPasswordIsEnabledForUsers, EmailAndPasswordIsEnabledForAdmins | boolean | Use the first to hide the password link when that login is off. |
AuthenticationSchemes | array | All configured schemes, with the members listed under Account pages. |
CurrentUser
The signed-in public user. For a visitor who is not signed in, IsAuthenticated is false and the name and email members are empty strings.
| Member | Type | Notes |
|---|---|---|
IsAuthenticated | boolean | Test this first. |
UserId | string | |
FirstName, LastName, FullName, EmailAddress | string | FullName is first and last name joined by a space. |
IsAdmin | boolean | True when the user is an administrator. |
Roles | array of strings | Developer names of the user's roles. |
UserGroups | array of strings | Developer names of the user's groups. Test with CurrentUser.UserGroups contains 'members'. |
SsoId, AuthenticationScheme | string | How the user signed in. |
RemoteIpAddress | string | The address after Raytha's trusted-proxy handling. |
LastModificationTime | date or nothing |
Warning
CurrentUseronly changes what the template prints. It does not stop anyone from requesting the page. A members-only snippet hides markup from other visitors, but it is not access control for the content item itself.
PathBase, QueryParams, RequestVerificationToken, ViewData
PathBaseis a string: empty when Raytha is served at the root,/cmswhen it is served under that path. Start every internal URL with{{ PathBase }}/. A route path never has a leading slash, so{{ PathBase }}/{{ item.RoutePath }}is right.QueryParamsis a dictionary of the request's query string. ReadQueryParams.searchorQueryParams["search"]. A missing key is nothing. Keys are matched exactly as written in the URL. A repeated key (?a=1&a=2) arrives as one comma-joined string.RequestVerificationTokenis the anti-forgery token for the request, on every public kind except the account pages, which carry theirs onTarget.ViewDatais the ASP.NET view data of the request. No public page puts anything in it, so treat it as empty.
Field value objects
Everything under PublishedContent is keyed by the field's developer name. Every field is a value object with three members: Value, Text and HasValue. Text is the value as a string. A field that was never saved on the item is missing, which is the same as empty in practice.
| Field type | .Value | Notes |
|---|---|---|
| Single line text, Long text | string | Escape it. |
| Wysiwyg | string of HTML | Output raw. .Text is the same string. |
| Number | number or nothing | Format with filters such as round. HasValue is true for 0. |
| Checkbox | true, false or nothing | HasValue is true even when the box is unchecked. Test .Value to ask "is it ticked". |
| Date | date or nothing | A calendar date with no time zone. Format with | date: "%B %e, %Y", not organization_time, which would shift it a day in time zones behind UTC. |
| Dropdown, Radio | string | The developer name of the chosen choice, not its label. |
| Multiple select | array of strings | Developer names of the chosen choices. .Text is them joined by a comma and space. Test membership with .Value contains 'x'. |
| Attachment | string | The object key of the stored file. Turn it into a URL with | attachment_url or | attachment_public_url. |
| Color | string like #1e293b | Lowercase, six digits. |
| Repeater | array of rows | Each row is an object keyed by sub-field developer name: {% for row in x.Value %}{{ row.question }}{% endfor %}. .Text is the rows as JSON. |
| One-to-one relationship | not a value object | When set, the field is the related item: .Id, .PrimaryField, .RoutePath, .PublishedContent, .IsPublished. When unset it is an empty string. |
Examples of each shape, assuming fields named as in the comments:
{%- comment -%} number "price", checkbox "featured", date "published_on" {%- endcomment -%}
{% if Target.PublishedContent.price.HasValue %}${{ Target.PublishedContent.price.Value | round: 2 }}{% endif %}
{% if Target.PublishedContent.featured.Value %}<span class="badge">Featured</span>{% endif %}
{{ Target.PublishedContent.published_on.Value | date: "%B %e, %Y" }}
{%- comment -%} multiple select "tags" and repeater "links" {%- endcomment -%}
{% for tag in Target.PublishedContent.tags.Value %}<span>{{ tag | escape }}</span>{% endfor %}
{% for row in Target.PublishedContent.links.Value %}
<a href="{{ row.url | escape }}">{{ row.label | escape }}</a>
{% endfor %}
{%- comment -%} relationship "author" {%- endcomment -%}
{% assign author = Target.PublishedContent.author %}
{% if author.Id %}
<a href="{{ PathBase }}/{{ author.RoutePath }}">{{ author.PrimaryField | escape }}</a>
{% endif %}
A related item holds its own PublishedContent with field objects. It goes one level deep: a relationship field inside the related item is not expanded into a third item. To follow a chain, look the next item up with get_content_item_by_id.
Gotchas
- Never write
{% if Target.PublishedContent.summary %}to test for content. It is true for a saved empty field. Use.HasValue, or!= blankon.Value. {{ field | default: "x" }}does not apply, because the field object is not empty. Use{{ field.Value | default: "x" }}.- Dropdown values are developer names. To print the label, look the choice up in
get_content_type_by_developer_name(...).ContentTypeFields, or store labels as the developer names. - An attachment field stores the key, not a URL. Printing
.Valuein animg srcgives a broken image. - Never output
{{ Target | json }}or{{ item | json }}fromget_content_itemsin a public page. Items from the functions includeDraftContent, which holds unpublished edits.
Next steps
- Functions and filters
- Layouts and inheritance
- Email templates for the variables an email receives