Detail views vs list views
A public route in Raytha shows either one content item (a detail view) or a published list of items of one content type (a list view). The two use different templates and a different Target. This page shows both, with paging and search.
The two kinds of route
| Detail view | List view | |
|---|---|---|
| What it shows | One content item | Items of one content type, filtered, sorted and paged by the view's settings |
| URL | The item's route path, for example /blog/hello | The view's route path, for example /blog |
Target | One item | A list result: Target.Items, Target.TotalCount and the paging variables |
ContentType | The item's content type | The view's content type |
| Template chosen by | The template bound to that item in the active theme, else raytha_html_content_item_detail | The template bound to that view in the active theme, else raytha_html_content_item_list |
| Not published | 404, unless you preview a draft | 404 |
Either one can be the home page. Pick it in the admin: a content item, a list view or a site page.
Detail view
Target is one content item:
| Member | Type | Notes |
|---|---|---|
Target.Id | string | The item id. |
Target.PrimaryField | string | The value of the content type's primary field. Usually the title. |
Target.RoutePath | string | Path without a leading slash, for example blog/hello. Prefix with {{ PathBase }}/. |
Target.PublishedContent | object | Your custom fields, keyed by developer name. Each is a field value object (see below). |
Target.CreationTime | date (UTC) | Format with organization_time. |
Target.LastModificationTime | date (UTC) or nothing | Nothing when the item was never modified. |
Target.CreatorUser, Target.LastModifierUser | object or nothing | Id, FirstName, LastName, FullName, EmailAddress. |
Target.Template | string | Developer name of the template that rendered the item. |
Target.ContentType | object | Same as the top-level ContentType. |
Read a custom field as Target.PublishedContent.<developer_name>, then pick the part you need. For a field named summary:
{% if Target.PublishedContent.summary.HasValue %}
<p class="lead">{{ Target.PublishedContent.summary.Value | escape }}</p>
{% endif %}
The field object itself is always truthy once the field exists, even when it is empty. Test .HasValue. The full list of .Value types is in Template variables.
Previewing a draft
Open the item's route with ?previewDraft=true. If you are signed in and may edit that content type, Raytha renders the draft: Target.PublishedContent then holds the draft fields, despite its name. Anyone else gets the 404 template.
List view
The view decides what is listed. Its settings (in the admin, open the content type, then Views) are the route path, whether it is published, the stored filter and sort, the columns that search looks at, the default and maximum page size, and the template. A list view only ever returns published items.
| Member | Type | Notes |
|---|---|---|
Target.Items | array | Items for the current page. Each has the members listed under Detail view. |
Target.TotalCount | number | Items matching across all pages. |
Target.PageNumber | number | 1-based. Values below 1 become 1. |
Target.PageSize | number | The size in effect after the view's limits. |
Target.TotalPages | number | ceil(TotalCount / PageSize). |
Target.PreviousDisabledCss, Target.NextDisabledCss | boolean | Previous is true on the first page, next is true on the last page, and both are true when there are no pages. The names say CSS, but the values are plain booleans. |
Target.FirstVisiblePageNumber, Target.LastVisiblePageNumber | number | A window of at most four page numbers for a pager. |
Target.Search, Target.Filter, Target.OrderBy | string | The query parameters the visitor sent, or empty. |
Target.RoutePath | string | The view's route path. |
Target.Label, Target.DeveloperName, Target.Description | string | Properties of the view, not of the content type. |
Query parameters
A list view reads these from the URL, and QueryParams also exposes them to the template:
| Parameter | Effect |
|---|---|
pageNumber | Page to show. Default 1. |
pageSize | Items per page. When missing or 0, the view's default (25 unless you changed it). Capped at the view's maximum (1000 by default). |
search | Case-insensitive "contains" match on the view's search columns. With no columns set, only the primary field is searched. If the search text is a number, a number column is compared for equality instead; the same applies to a checkbox column and true/false. |
filter | A filter expression that is combined with the view's own filter using AND. See Filtering and sorting. |
orderBy | For example PrimaryField asc. Replaces the view's sort. |
If you tick Ignore client filter and sort query params in the view settings, filter and orderBy from the URL are dropped and only the view's own filter and sort apply. search, pageNumber and pageSize still work. Turn it on for any view where visitors should not be able to slice the data themselves.
A complete list template
<div class="container py-5">
<h1>{{ Target.Label | escape }}</h1>
<form method="get" action="{{ PathBase }}/{{ Target.RoutePath }}" class="mb-4">
<input type="search" name="search" value="{{ Target.Search | escape }}" placeholder="Search">
<button type="submit">Search</button>
</form>
{% if Target.Items.size == 0 %}
<p>Nothing found.</p>
{% else %}
<p>{{ Target.TotalCount }} result{% if Target.TotalCount != 1 %}s{% endif %}</p>
{% for item in Target.Items %}
<article class="mb-4">
<h2 class="h4"><a href="{{ PathBase }}/{{ item.RoutePath }}">{{ item.PrimaryField | escape }}</a></h2>
<small>{{ item.CreationTime | organization_time: "%b %e, %Y" }}</small>
{% if item.PublishedContent.content.HasValue %}
<p>{{ item.PublishedContent.content.Text | strip_html | truncate: 200 }}</p>
{% endif %}
</article>
{% endfor %}
{% endif %}
{% if Target.TotalPages > 1 %}
<nav aria-label="Pages">
{% unless Target.PreviousDisabledCss %}
<a href="{{ PathBase }}/{{ Target.RoutePath }}?pageNumber={{ Target.PageNumber | minus: 1 }}&search={{ Target.Search | url_encode }}">Previous</a>
{% endunless %}
{% for i in (Target.FirstVisiblePageNumber..Target.LastVisiblePageNumber) %}
{% if i == Target.PageNumber %}
<strong>{{ i }}</strong>
{% else %}
<a href="{{ PathBase }}/{{ Target.RoutePath }}?pageNumber={{ i }}&search={{ Target.Search | url_encode }}">{{ i }}</a>
{% endif %}
{% endfor %}
{% unless Target.NextDisabledCss %}
<a href="{{ PathBase }}/{{ Target.RoutePath }}?pageNumber={{ Target.PageNumber | plus: 1 }}&search={{ Target.Search | url_encode }}">Next</a>
{% endunless %}
</nav>
{% endif %}
</div>
The built-in raytha_html_content_item_list template is a Bootstrap version of the same thing. Pull the default theme and read it as a starting point (see Themes and the command line tool).
Choosing which template a view or item uses
Bindings are per theme. A theme holds its own set of templates, and each view and item is bound to one template of each theme. A web template only appears in the choices for a content type if that content type has access to it; new templates can be set to apply to all new content types. If an item or view has no binding in the active theme, Raytha uses the built-in detail or list template. Duplicating a theme copies the bindings, which is the safe way to start a redesign.
Gotchas
- List views and
get_content_itemsare separate. The view uses its stored filter, sort and search columns.get_content_itemstakes its ownFilterandOrderByand cannot search. Target.Itemscan be empty on a page above the last one.?pageNumber=99renders the template with no items, not a 404.- The same name means different things:
Target.Labelin a list view is the view's label. UseContentType.LabelPluralfor the content type's name. - An item with no template in the active theme is rendered with the built-in detail template. After switching themes, check that bindings carried over.
- An unpublished related item is still returned through a relationship field. Check
IsPublishedbefore you link to it.
Next steps
- Template variables for field value types and the other top-level variables
- Filtering and sorting
- Template recipes for related items, grouping and search forms
- Create and publish a list view (user guide)