Introduction to templates
Every public page in Raytha is a Liquid template rendered on the server against one model. This page shows the path from URL to HTML, lists the kinds of template you can write, and points to the page that documents each part.
How a request becomes HTML
Raytha serves the public site from one catch-all route. For a request such as GET /blog/hello, it does this:
- It looks the path up in the route table. An empty path means the home page, which is a content item, a list view or a site page (you choose in the admin). Any other path must match one route, and each route points at exactly one of: a content item, a list view, a site page or a Raytha Function.
- It loads the target. A content item or site page that is not published returns the 404 error template. A list view that is not published does the same.
- It picks a template from the active theme. A content item uses the template bound to it, a list view uses the template bound to the view, a site page uses its own template. When nothing is bound, Raytha falls back to the built-in
raytha_html_content_item_detailorraytha_html_content_item_list. - It builds the template source. The template's parent layouts are joined into one string (see Layouts and inheritance).
- It renders that string with Fluid, the .NET Liquid engine, against a model that holds
Target,CurrentOrganization,CurrentUser,PathBase,QueryParamsand a few others (see Template variables). - It writes the result as
text/html.
Account pages (/account/login, /account/me and so on) and error pages follow the same last four steps, with a built-in template looked up by developer name in the active theme.
A first template
This is a complete detail template for a content type whose primary field is the title and that has a content field of type Wysiwyg. Put it in a template that has the base layout as its parent.
<article class="container py-5">
<h1>{{ Target.PrimaryField | escape }}</h1>
<p class="text-muted">
{{ Target.CreationTime | organization_time: "%B %e, %Y" }}
{% if Target.CreatorUser %}by {{ Target.CreatorUser.FullName | escape }}{% endif %}
</p>
{% if Target.PublishedContent.content.HasValue %}
{{ Target.PublishedContent.content.Value }}
{% endif %}
<p><a href="{{ PathBase }}/{{ ContentType.DeveloperName }}">Back to {{ ContentType.LabelPlural | escape }}</a></p>
</article>
Three habits in that snippet apply everywhere:
- Field values are objects.
Target.PublishedContent.contenthas.Value,.Textand.HasValue. Test.HasValue, not the field itself, because the field object is always truthy. - Output is not HTML-escaped. Escape anything an editor or visitor typed with
| escape. Only output a Wysiwyg field raw, because it is meant to contain HTML. - Prefix internal links with
{{ PathBase }}. It is empty when Raytha is hosted at the root of its domain and/somethingwhen it is not.
Template kinds
| Kind | Used for | Target is |
|---|---|---|
| Base layout | The shared page shell. Contains {% renderbody %} where the child goes. | Whatever the child page's Target is |
| Content item detail | One content item at its route. | A content item |
| Content item list | A list view of one content type, with paging. | A list result with Items |
| Site page | A page made of widgets in named sections. | A site page (Title, RoutePath, ...) |
| Widget template | One block on a site page, with its own settings form. | Not available. Use widget.settings. |
| Login, registration, profile | Built-in account pages (raytha_html_login_*, raytha_html_changeprofile ...). | A form model with ValidationFailures and SuccessMessage |
| Error pages | raytha_html_error_403 and raytha_html_error_404. | An error model (ErrorId, ErrorMessage, ...) |
| Email templates | Subject and body of system emails. Not part of a theme. | A user-specific model |
Detail and list templates are covered in Detail views vs list views. Site pages and widgets are covered in Site pages and sections and Widget templates. Emails are covered in Email templates.
Liquid and Fluid
Raytha renders with Fluid 2.31, a .NET implementation of Shopify's Liquid. The language basics ({{ output }}, {% if %}, {% for %}, {% assign %}, {% capture %}, {% case %}, filters with |) work as in any Liquid reference. Fluid differs from Shopify in a few ways that matter here:
- Member names are case-sensitive and use the .NET names:
Target.PrimaryField,item.RoutePath,CurrentUser.IsAuthenticated. A misspelled name renders as nothing. It does not raise an error. - Empty strings and the number
0are truthy. Onlyfalseand a missing value are falsy. Compare withblankto catch both an empty string and nothing:{% if x != blank %}. {% include %}and{% render %}parse, but Raytha configures no file provider, so they fail when the page renders. Reuse markup with layouts and widgets instead.- There is no
{% layout %}tag. Inheritance is set in the template's settings, not in its source. - The
{% liquid %}tag does not work reliably in Fluid 2.31. Avoid it. - Raytha adds functions (
get_content_items,render_sectionand others) and filters (organization_time,attachment_public_urland others). They are listed in Functions and filters.
Templates are cached by their source text after the first parse, so a repeat request costs only the render.
What happens when a template is wrong
- A syntax error is rejected when you save a web template. The same check runs for
raytha theme push. - A runtime error happens when a visitor loads the page. The response is HTTP 500 with an empty body in production. In Development mode the body is a plain-text message that names the template. Raytha does not show your 500 error template for these.
- An invalid
Filterpassed toget_content_items(or a bad?filter=on a list view) returns HTTP 400 with the parser's message as plain text, in every environment. - A typo in a variable name is not an error. Check the HTML you get back, not only the status code.
Where to go next in these docs
| You want to | Read |
|---|---|
| See every variable and what it holds | Template variables |
| Share a header and footer between templates | Layouts and inheritance |
| Fetch other content from inside a template | Functions and filters and Filtering and sorting |
| Build pages from blocks | Site pages and sections, Widget templates |
| Work in files, in git | Themes and the command line tool |
| Copy a working snippet | Template recipes |