The Hidden Gem: Structr's new Template Engine

The recent release 1.0 has a hidden gem: A brand-new template engine. The reason why it's hidden is that we simply didn't find enough time to document all new components before the launch 1.0, but it's already in use on structr.org and some customer sites. We'll update the docs and provide a how-to screencast soon.

We use the opportunity to explain the existing and new functionality, and how to get the best out of both.

Structr Pages

Existing Templating Mechanisms in Structr

To understand the changes we made, it is good to know the existing functionality for content reuse in Structr: Widgets and Shared Components.

Widgets

Widgets are static content nodes, containing code which is transformed into a part of a page, a blueprint if you like. There are local and remote widgets, the latter are served from a central Widget server, the former are only available on your local instance.

Widgets

When applying a Widget to a page, a new set of DOM elements is created as child nodes of the node the Widget was dropped onto, including all metadata like data binding and queries. The textual information contained in the Widget is transformed into database elements (nodes, relationships and properties). Once created, the new DOM elements have no connection to the Widget they originated from. Later changes made to the Widget code don't have any effect on the page's elements. Widgets in Structr are more or less containers to exchange reusable code between Structr instances, so maybe the name does not fit very well.

Shared Components

Shared Components

The second element, Shared Components, are reusable branches of a DOM tree, locally managed as database objects. The only difference between a Shared Component and a regular DOM branch is that the latter is connected to exactly one page while the former has no direct connection to a page but is connected to and synchronized with placeholder DOM elements in the page.

Page Graph

These two mechanisms are what Structr has to offer related to templating, and they differ somewhat from what you find in most classic Content Management Systems.

Difference to Classic CMS Templating

Most classic CMS have 'outer' templates: Static HTML code blocks with 'holes' or placeholders to be filled with or replaced by the inner, typically dynamic content, generated at runtime. The benefits are that you can edit the template code with any text editor, or even upload/import it from external sources or synchronize it with a code repository.

The downside is that classic templates are just static text blocks with no inner structure controllable by the CMS. When a site gets more and more complex, you find yourself breaking up large templates into smaller ones, introducing lots of 'includes' and using a programming or scripting language to add dynamic behaviour. This is what makes feature-rich, dynamic web pages slow, and this is even more true for web applications. You can mitigate this by adding caching (possible for public content only) or move content rendering to the client, but both means adding complexity, in one way or the other.

In Structr, all DOM elements are nodes in a graph database, and pages are rendered by traversing a page's graph, starting at a Page node and just following the relationships down to the Content nodes, typically containing plain text only. The benefit here is that you can define rules and filter criteria for each node, like f.e. visibility, access rights, or language settings, allowing for a fine-grained control over the content generation while still being fast.

But there was a limitation of Structr's pure approach of only allowing structure to exist as a server-side DOM tree and content in leaf nodes: As a web developer, you didn't have the choice of making your blocks bigger or finer as needed, because there was only one level of granularity: maximum. The new template engine removes this limitation.

New Node Type: Template

With the latest release of Structr, we introduce a Template node type. A Template node is derived from the existing Content node with the only difference that a Template node can also have child nodes. Together with the Template node type come two new built-in function called render() and include(). The following example is the content of a Template node with three child nodes:

    <div class="row">
    	<div class="col">${render(first(element.children))}</div>
    	<div class="col">${render(nth(element.children, 1))}</div>
    	<div class="col">${render(nth(element.children, 2))}</div>
    </div>

You can even mix the new static, outer templates with the existing fine-grained, database-controlled DOM nodes, giving you full flexibility, combining the benefits of both approaches.

And you can of course reuse Template elements within one instance by just making them a Shared Component, so they can be managed in a central location and changes made to the Template content will be also effective in each page they're contained in. Or you can apply a query and a data key to repeat Template nodes, dynamically filled with data from your database.

This new functionality in Structr is a big step towards a Semantic CMS, and we think it was worth the additional effort to include it in the 1.0 release. We have some plans to create a new, much simpler CMS user interface, together with a module system for resusable elements which will make use of the template engine, so stay tuned! Don't forget to follow us on Twitter (@structr) to be kept updated, or subscribe to the newsletter.

Share this post

Comments