Fork me on GitHub


An article by Gaspard Bucher

Skins are used to define the layout of your websites. A skin contains assets (css, images, javascripts) and zafu templates. Read Understanding Templates, and see the tutorials to create a new skin.

Skins can be created from scratch, imported and exported (dev mode) as archives, or loaded from files (fs-skins brick).

html rendering

When rendering a page, zena uses the best match out of the zafu templates that the configured skin provides. This decision is made based on the current node’s class, the rendering mode and the format (html, png, jpg, rss, js, csv, ical, ...).


The template naming scheme is: class-mode-format.zafu


Template selection examples, based on the templates in the image above:

url node class mode format template used
project12.html Project html Project.zafu
docproject21.html DocProject html Project.zafu
document3.html Document html Node.zafu
document3.png Image png send document data
image3_pv.png Image pv png send image data with ‘pv’ mode (size/format)
project12_changes.html Project changes html Project-changes.zafu
project12_changes.rss Project changes rss Project-changes-rss.zafu
project12_foo.html Project foo html 404 error (no template for ‘foo’ mode) Project bar 404 error (no template for ‘bar’ format)

Note that DocProject is a specialization (sub-class) of Project. This is why it can be rendered using the “Project.zafu” template.


When creating an url, the mode and format are encoded in a similar way:

Link with “rss” format and “changes” mode: "link title":14_changes.rss

Special “modes”

special mode

Internally, Zena uses some special modes to render the homepage, the “page not found” and some other things. You create these special templates by creating a master template with the given mode (image above).

All special modes start with a ”+” sign (and cannot therefore be set in the url for security reasons).

Here are all the special modes:

Used to render the home page

Renders the 404 page.

Renders the login page. Make sure this template is visible by the anonymous user.

The layout of the popup window. See the default layout to have an idea on how this template should look like.

This is used as the “contact” form part when creating a new user. It can be used to change the link between the user and he/her contact node by setting this template to <r:input type='id' name='id'/>. Setting node[id] on the user changes the visitor’s node.

Used to render the ”++” tab on the edit popup. Use class scoping for different elements (“Contact-+edit”, “Page-+edit”, etc).

edit tab

js/css rendering

If you want to generate dynamic “css” or “js” content, you need to take special care because the server adds a “1 year cache” header on this kind of data. The simplest solution is to replace “js” and “css” extensions by “jsx” and “cssx”.

[Advanced stuff] The other solution if you want the cache to work and be able to update the content when changing the template is to somehow insert the template’s cachestamp in the url:

Let’s say the template id is 1432. We want some dynamic JS for the project:

This would cache any generated JS in the browser with the project’s cachestamp only:

<script src='#{path(project, :format =&gt; "js")}'></script>

This is better (also uses the template’s cachestamp):

<script src='#{path(project, :format =&gt; "js", :tsamp =&gt; find(1432).updated_at.to_i)}'></script>

other formats

You can also have special rendering tools that produce other (even binary) formats, if you write a simple rendering engine

Have a look at the pdf brick for an example.