Writing Rendering Documents

Advanced

The full vocabulary: values from the current element, blocks, related-element queries, tables and shortening filters.

A rendering document is Markdown with two additions: interpolation for values from the current element, and blocks for content Metapad assembles for you.

Throughout, the element a page is about is called the subject.

Values from the subject

Use {{ ... }} anywhere in your text:

  • {{ subject.label }} — the element's name
  • {{ subject.description }} — its description
  • {{ subject.properties.owner }} — any property, by name
  • {{ subject.auto_id }} — its short id, such as SRV-12

A reference that cannot be resolved renders as nothing rather than an error, so check your spelling in the preview.

Blocks

A block is a line starting with :::

BlockWhat it does
:::prose{ source=subject.description }Renders a text property as Markdown
:::propertiesThe subject's properties as a table
:::view{ source=... }A list or table of related elements
:::metric{ source=... label="..." }A single number
:::diagram{ source=... }A diagram, drawn into the page

Pulling in related elements

:::view needs to know which elements. You define that once at the top of the document in a query_spec block, then refer to it by name.

To show, on every Process page, the Roles involved in that process:

{"sections":[{"name":"roles","selection":{"Relative":{"hops":[{"rel":{"relationship_type_ids":["involves"],"direction":"Outgoing"}}]}},"shape":{"Collect":{"include":{"node_properties":"All","edge_properties":"All"}}}}],"locale":"en"}

and then, anywhere below:

:::view{ source=roles }

Use the exact relationship type name from your model — a name that does not exist matches nothing, silently. direction is Outgoing, Incoming or Both; incoming is how a page shows "what points at me".

Two ways to present a view

A table, with the columns you choose:

:::view{ source=roles columns="label, description | summary: 160, properties.owner" }

A list, or any other shape, with a per-item template:

:::view{ source=roles template="- [{{ label }}](node:{{ id }}) — {{ via.involvement }}" }

Inside a template, {{ label }}, {{ id }}, {{ description }} and {{ properties.x }} refer to each item, not to the subject. {{ via.x }} reads a property of the relationship that connects them — which is where an involvement description or a RACI letter usually lives.

A template renders each item on its own, so a template shaped like a table row will not assemble into a table. That is what columns= is for.

Keep long text short

A full description in a table cell wrecks the layout. Pipe it through a filter:

  • | summary: 160 — the lead paragraph, flattened and cut to 160 characters (reach for this one)
  • | first_paragraph — just the lead paragraph
  • | truncate: 200 — cut to length

Linking between pages

Writing [{{ label }}](node:{{ id }}) links to another element's page. In the published site it becomes a real link; if that element is not part of the publication it degrades to plain text rather than a dead link.

Watch out for empty sections

Your prose is printed exactly as written — including headings — even when the block below it finds nothing. A page for an element with no related roles will show a bare Roles involved heading with nothing under it.

Until blocks can carry their own heading, the reliable fix is to put the label inside the template, so nothing at all prints when there is nothing to show:

:::view{ source=roles template="**Involves:** [{{ label }}](node:{{ id }})" }

Check both formats

Heading levels differ between the website and the PDF: a # heading is the page title on the site, but nests under the chapter heading in the PDF. If a document matters in both, preview it in both.