Site, page and nav variables
When a markdown file (or other supported content) is rendered, the Mako template
receives a number of context variables as partly described above. A few of these
variables, such as MDTEMPLATES
and DATADIR
set directly by wmk
(see
above). Others are user-configured either (1) in wmk_config.yaml
(the contents
of the site
object and potentially additional "global" variables in
template_context
); or (2) the cascade of index.yaml
files in the content
directory and its subdirectories along with the YAML frontmatter of the markdown
file itself, the result of which is placed in the page
object.
When gathering the content of the page
variable, wmk
will
start by looking for index.yaml
files in each parent directory of the markdown
file in question, starting at the root of the content
directory and moving
upwards, at each step extending and potentially overriding the data gathered at
previous stages. Only then will the YAML in the frontmatter of the file itself
be parsed and added to the page
data.
The file-specific frontmatter may be in the content file itself, or it may be in
a separate YAML file with the same name as the content file but with an extra
.yaml
extension. For instance, if the content filename is important.md
, then
the YAML file would be named important.md.yaml
. If both in-file and external
frontmatter is present, the two will be merged, with the in-file values
"winning" in case of conflict.
At any point, a data source in this cascade may specify an extra YAML file using
the special LOAD
variable. This file will then be loaded as well and
subsequently treated as if the data in it had been specified directly at the
start of the file containing the LOAD
directive.
Which variables are defined and used by templates is very much up the user,
although a few of them have a predefined meaning to wmk
itself. For making it
easier to switch between different themes it is however suggested to stick to
the following meaning of some of the variables:
The variables site
and page
are dicts with a thin convenience layer on top
which makes it possible to reference subkeys belonging to them in templates
using dot notation rather than subscripts. For instance, if page
has a dict
variable named foo
, then a template could contain a fragment such as
${ page.foo.bar or 'splat' }
-- even if the foo
dict does not contain a key
named bar
. Without this syntactic sugar you would have to write something much
more defensive and long-winded such as ${ page.foo.bar if page.foo and 'bar'
in page.foo else 'splat' }
.
The nav
variable
The nav
variable is an easy way of configuring a navigation tree
for websites with content that has a hierarchical structure, such as a typical
documentation site. It is set via the nav
key in the wmk_config.yaml
file
and is represented in templates as a tree-like Nav
object.
A Nav
instance is a list-like object with two types of entries: links and
sections. A link is just a title and a URL. A section has a title and a list of
links or sections (possibly nested).
Each item has a parent
(with the nav
itself as the top level parent) and a
level
(starting from 0 for the immediate children of the nav
).
The nav
has a homepage
attribute which by default is the first local link in
the nav. Each local link has previous
and next
attributes. Each section has
children
. There are other attributes but these are the basics.
Manually configured
A typical explicit nav setting looks something like this:
nav:
- Home: /
- User Guide:
- Lorem:
- Ipsum: /guide/ipsum/
- Eu fuit: /guide/mageisse/
- Dolor sit amet: /guide/concupescit/
- Resources:
- Community: 'https://example.com/'
- Source code: 'https://github.com/example/com/'
- About:
- License: /about/license/
- History: /about/history/
A manually configured nav
setting of this kind is necessary if you want to
have more than one level of nesting or if you need to link to something outside
of the site from the nav. Both of these characteristics are present in the
above example. However, if you need neither of them, an automatically generated
nav may be more convenient.
Automatically generated
A simple nav
object with a single level of nesting can also be generated by
wmk
from the frontmatter of the content files. In order for this to happen two
conditions must be met:
-
The value of
nav
inwmk_config.yaml
is set toauto
. -
Each item in the config that is to appear in the navigation tree must have at least the key
nav_section
in the frontmatter. To determine ordering,nav_order
or (equivalently)weight
may also be specified; and if necessary the pagetitle
may be overridden in the nav by setting thenav_title
attribute.
The nav_section
value Root
is special. Pages assigned to that section are
placed directly at the front of the nav
structure as link items.
Other sections are simply grouped by their nav_section
values. Please note
that these values are case-sensitive.
Within each section the link items are ordered by the their nav_order
/weight
value, which should be an integer. If two or more items have the same ordering
number, they are ordered by nav_title
/title
.
The sections themselves are ordered within the nav by the lowest
nav_order
/weight
value of the pages assigned to them. Sections with the same
ordering number are sorted alphabetically.
The TOC
variable
When a page is rendered, the generated HTML is examined and a simple table of
contents object constructed, which will be available to templates as TOC
. It
contains a list of the top-level headings (i.e. H1 headings, or H2 headings if
no H1 headings are present, etc.), with lower-level headings hierarchically
arranged in its children
. Other attributes are url
and title
.
TOC.item_count
contains the heading count (regardless of nesting).
The TOC
variable can e.g. be used by the page template to show a table of
contents elsewhere on the page.
The table of contents object is not constructed unless each heading has an id
attribute. When using the default python-markdown, this means that the toc
extension must be active.
System variables
The following frontmatter variables affect the operation of wmk
itself, rather
than being exclusively used by templates.
Templates
Note that a variable called something like page.foo
below is referenced as
such in templates but specified in YAML frontmatter simply as foo: somevalue
.
-
page.template
specifies the template which will render the content. -
page.layout
is used by several other static site generators. For compatibility with them, this variable is supported as a fallback synonym withtemplate
. It has no effect unlesstemplate
has not been specified explicitly anywhere in the cascade of frontmatter data sources.
For both template
and layout
, the .mhtml
(or .html
in the case of
Jinja2) extension of the template may be omitted. If the template
value
appears to have no extension, .mhtml
or .html
(depending on the template
engine) is assumed; but if the intended template file has a different extension,
then it must of course be specified.
Likewise, a leading base/
directory may be omitted when specifying template
or layout
. For instance, a layout
value of post
would find the template
file base/post.mhtml
unless a post.mhtml
file exists in the template root
somewhere in the template search path.
If neither template
nor layout
has been specified and no default_template
setting is found in wmk_config.yaml
, the default template name for markdown
files is md_base.mhtml
(or md_base.html
if Jinja2 templates have been
selected).
The special template
/layout
value __empty__
(case-insensitive) indicates
that no base template should be applied to the given content file.
Taxonomy handling
A taxonomy is a classification of pieces of content for the purpose of grouping
them together. Common taxonomy types are tags, categories, sections and article
authors. However, the taxonomy that is appropriate to a particular website
mainly depends on the content. On a site with book reviews you would have
genres, book authors and publishers, on a movie site you would have genres and
actors, and so on. Each set of frontmatter classifiers (e.g. the single
classifier tag
or the list ['tag', 'tags']
) used in a taxonomy may be called
a term. Each term may have several values, and each value represents a list
of content items associated with it.
Up to version 1.13 of wmk, taxonomies had to be handled by templates, and this is still the best way to do it if you want a form of presentation which is tailored to a particular term. However, as a consequence, themes had to be designed around specific taxonomies, typically tags, categories, or sections. In other words, the presentation of taxonomies was not primarily content-driven.
From version 1.13 it is therefore possible to specify the taxonomy criteria
directly in the front matter of the main content page for the corresponding
term. Here is an example based on a movie site, for the term director. The
content file might be named directors/index.md
:
---
title: Directors
date: 2024-11-01
template: base/taxonomy/list.mhtml
TAXONOMY:
taxon: ['director', 'directors']
order: name
detail_template: base/taxonomy/detail.mhtml
list_settings:
pagination: true
per_page: 24
detail_settings:
biographies: directors.yaml
item_template: lib/movie_teaser.mc
---
Below is a list of the directors of the movies
that have been covered on this website.
Click on the name of a director to see a short biography
and an overview of their movies.
The frontmatter variable page.TAXONOMY
triggers the special processing of the
page, provided that it contains at least the subkeys taxon
and
detail_template
. This special processing consists in the following:
-
wmk fetches a list of values for the term specified in
taxon
using thetaxonomy_info()
method ofMDCONTENT
. This will be added to the template context asTAXONS
. -
For each value in the list, wmk renders the template
detail_template
with the same context, except that the two keysTAXON
(the value) andTAXON_INDEX
(the 0-based index of the value in the list) are added. EachTAXON
hasitems
which represent the pages tagged with that director, and the main job of thet detail page is to show a list of them to the user. The result is written to a destination file the name of which is based on the destination of the rendered Markdown content plus the slug of the string identifying the value (e.g.directors/orson-welles/index.html
in this example). The target url will be available asTAXON['url']
(and thus also under the key'url'
for each item inTAXONS
). -
wmk resumes normal operation by calling the main template with the modified template context as well as the content from the markdown file, and writes the result to the target file.
Please note that the settings in list_settings
and detail_settings
in the
example above are merely for the purposes of illustration. Whether any of them
are actually supported is entirely up to the template or theme author. The only
subvariables used by wmk itself are taxon
, order
(if present), and
detail_template
.
Variables affecting rendering
-
page.slug
: If the value ofslug
is nonempty and consists exclusively of lowercase alphanumeric characters, underscores and hyphens (i.e. matches the regular expression^[a-z0-9_-]+$
), then this will be used instead of the basename of the markdown file to determine where to write the output. If aslug
variable is missing, one will be automatically added bywmk
based on the basename of the current markdown file. Templates should therefore be able to depend upon slugs always being present. Note that slugs are not guaranteed to be unique, although that is good practice. -
page.pretty_path
: If this is true, the basename of the markdown filename (or the slug) will become a directory name and the HTML output will be written toindex.html
inside that directory. By default it is false for files namedindex.md
orindex.html
and true for all other files. If the filename contains symbols that do not match the character class[\w.,=-]
, then it will be "slugified" before final processing (although this only works for languages using the Latin alphabet). -
page.do_not_render
: Tellswmk
not to write the output of this template to a file inhtdocs
. All other processing will be done, so the gathered information can be used by templates for various purposes. (This is similar to theheadless
setting in Hugo). -
page.draft
: If this is true, it prevents further processing of the markdown file unlessrender_drafts
has been set to true in the config file. -
page.no_cache
: If this is true, the rendering cache will not be used for this file. (See also theuse_cache
setting in the configuration file). -
page.markdown_extensions
,page.markdown_extension_configs
,page.pandoc
,page.pandoc_filters
,page.pandoc_options
,page.pandoc_input_format
,page.pandoc_output_format
: See the description of these options in the section on the configuration file, above. -
page.POSTPROCESS
: This contains a list of processing instructions which are called on the rendered HTML just before writing it to the output directory. Each instruction is either a function (placed intoPOSTPROCESS
by a shortcode) or a string (possibly specified in the frontmatter). If the latter, it points to a function entry in theautoload
dict imported from either the project'spy/wmk_autoload.py
file or the theme'spy/wmk_theme_autoload.py
file. In either case, the function receives the html as the first argument while the rest of the arguments constitute the template context. It should return the processed html. -
page.PREPROCESS
: This is analogous topage.POSTPROCESS
, except that the instructions in the list are applied to the markdown (or other content document) just before converting it to HTML. The function receives two arguments: the document text and thepage
object. It should return the altered document source. Note that this happens before shortcodes have been expanded, so (unlikepage.POSTPROCESS
) such actions cannot be added via shortcode.
Note that if two files in the same directory have the same slug, they may both
be rendered to the same output file; it is unpredictable which of them will go
last (and thus "win the race"). The same kind of conflict may arise between a
slug and a filename or even between two filenames containing non-ascii
characters. It is up to the content author to take care to avoid this; wmk
does nothing to prevent it.
Standard variables and their recommended meaning
The following variables are not used directly by wmk
but affect templates in
different ways. It is a list of recommendations rather than something which
must be necessarily followed.
Typical site variables
Site variables are the keys-value pairs under site:
in wmk_config.yaml
.
-
site.title
: Name or title of the site. -
site.lang
: Language code, e.g. 'en' or 'en-us'. Used e.g. for translations by some themes. -
site.locale
: Locale code, e.g. 'en_US.utf8'. Used when sortingMDCONTENT
by name or title. -
site.tagline
: Subtitle or slogan. -
site.description
: Site description. -
site.author
: Main author/proprietor of the site. Depending on the site templates (or the theme), may be a string or a dict with keys such as "name", "email", etc. -
site.base_url
: The protocol and hostname of the site (perhaps followed by a directory path ifsite.leading_path
is not being used). Normally without a trailing slash. -
site.leading_path
: If the web pages built bywmk
are not at the root of the website but in a subdirectory, this is the appropriate prefix path. Normally without a trailing slash. -
site.build_time
: This is automatically added to the site variable bywmk
. It is a datetime object indicating when the rendering phase of the current run started. -
site.lunr_search
: A boolean automatically added to the site variable. It is true whenlunr_index
is true in the configuration file.
Templates or themes may be configurable through various site variables, e.g.
site.paginate
for number of items per page in listings or site.mainfont
for
configuring the font family.
Classic meta tags
These variables mostly relate to the text content and affect the metadata
section of the <head>
of the HTML page.
-
page.title
: The title of the page, typically placed in the<title>
tag in the<head>
and used as a heading on the page. Normally the title should not be repeated as a header in the body of the markdown file. Most markdown documents should have a title. If it is not explicitly specified, the title will be generated automatically from the filename. -
page.slug
: See above. If it is missing, the slug is created from the title. -
page.id
: This is guaranteed to be unique at rendering time. If it is present but not unique, then "-1", "-2", etc., will be appended as necessary. If it is not explicitly specified, then it is generated by slugifying the full path to the source markdown file (relative to the content directory). For instance,blog/2022/09/The letter Þ in Old English.md
will become the IDblog-2022-09-the-letter-th-in-old-english
. -
page.description
: Affects the<meta name="description" ...>
tag in the<head>
of the page. The variablesummary
(see later) may also be used as fallback here. -
page.keywords
: Affects the<meta name="keywords" ...>
tag in the<head>
of the page. This may be either a list or a string (where items are separated with commas). -
page.robots
: Instructions for Google and other search engines relating to this content (e.g.noindex, nofollow
) should be placed in this variable. -
page.author
: The name of the author (if there is only one). May lead to<meta name="keywords" ...>
tag in the<head>
as well as appear in the body of the rendered HTML file. Some themes may expect this to be a dict with keys such asname
,email
,image
, etc. -
page.authors
: If there are many authors they may be specified here as a list. It is up to the template how to handle it if bothauthor
andauthors
are specified, but one way is to add theauthor
to theauthors
unless already present in the list. -
page.summary
: This may affect the<meta name="description" ...>
tag as a fallback if nodescription
is provided, but its main purpose is for list pages with article teasers and similar content. If it is initially not present butpage.generate_summary
is True, then it will be generated from the body of the page, as follows: (1) if the HTML comment<!--more-->
is present in the body, then any non-heading content before that will be used as the summary; (2) otherwise the first paragraph of the body will be used. In either case, if the autogenerated summary is longer than 300 characters, then it is truncated so as to be shorter than that (this maximum length is configurable withpage.summary_max_length
). Autogenerated summaries will contain neither HTML tags nor Markdown markup; if this is desired, the summary must be explicitly added to the frontmatter.
Note that this is by no means an exhaustive list of variables likely to affect
the <head>
part of the generated HTML. For instance, several other variables
may affect meta tags used for sharing on social media. One of the more common
ones is probably page.image
(described below). In any case, the list of
supported frontmatter attributes and how they are interpreted is for the most
part up to the theme or template author.
Dates
Dates and datetimes should normally be in a format conformant with or similar to
ISO 8601, e.g. 2021-09-19
and 2021-09-19T09:19:21+00:00
. The T
may be
replaced with a space and the time zone may be omitted (localtime is assumed).
If the datetime string contains hours it should also contain minutes, but
seconds may be omitted. If these rules are followed, the following variables
are converted to date or datetime objects (depending on the length of the
string) before they are passed on to templates.
-
page.date
: A generic date or datetime associated with the document. -
page.pubdate
: The date/datetime when first published. Currentlywmk b
does not omit rendering files withdate
orpubdate
in the future, but it may do so in a later version. -
page.modified_date
: The last-modified date/datetime. Note thatwmk
will also add the variableMTIME
, which is the modification time of the file containing the markdown source, so this information can be inferred from that if this variable is not explicitly specified. -
page.created_date
: The date the document was first created. -
page.expire_date
: The date from which the document should no longer be published. Similarly topubdate
, this currently has no direct effect on howwmk
builds and renders the site but may do so in a later version. -
page.auto_date
: If this is True and nopage.date
is present (or rather the field specified inpage.auto_date_field
, which deafults todate
), thenwmk
tries to look for an ISO date in the source filename or its directory path. In this context, that means a group of 4+2+2 digits with a separator which may be either-
,_
, or/
: e.g.posts/2024-05-13-find-the-fish.md
ordiary/2024/02/19/spam.org
. If a date is found, thenpage.date
is set accordingly. (Obviously you would normally setauto_date
in anindex.yaml
file so as to affect all content files in that directory and its subdirectories.)
See also the description of the DATE
and MTIME
context variables above.
Media content
-
page.image
: The main image associated with the document. Affects theog:image
meta tag in HTML output and may be used for both teasers and content rendering. -
page.images
: A list of images associated with the document. Ifimage
is not specified, the main image will be taken to be the first in the list. -
page.audio
: A list of audio files/urls associated with this document. -
page.videos
: A list of video files/urls associated with this document. -
page.attachments
: A list of attachments (e.g. PDF files) associated with this document.
Taxonomy
See also the description of page.TAXONOMY
above. The following are terms
commonly used for taxonomy purposes:
-
page.section
: One of a quite small number of sections on the site, often corresponding to the leading subdirectory incontent
. E.g. "blog", "docs", "products". -
page.categories
: A list of broad categories the page belongs to. E.g. "Art", "Science", "Food". The first-named category may be regarded as the primary one. -
page.tags
: A list of tags relevant to the content of the page. E.g. "quantum physics", "knitting", "Italian food". -
page.weight
: A measure of importance attached to a page and used as an ordering key for a list of pages. This should be a positive integer. The list is normally ascending, i.e. with the lower numbers at the top. (Pages may of course be ordered by other criteria, e.g. bypubdate
).