Inheritance
In Automad, inheritance can be used to extend a template by simply including it into another one. To be able to actually change details in the derived version of a template it is important to understand how snippets work and how they can be used to override parts on an atomic level.
Extending Templates
The basic idea is quite simple. A master template contains a snippet definition for every element that is supposed to be overridden by a derived template. Let's assume the following file structure of a theme:
packages/
name/
theme/
derived.php
master.php
For example the master template could somehow look as follows:
<# master.php #>
<!DOCTYPE html>
<html>
<head>
...
</head>
<body>
<nav>...</nav>
<@ snippet article @>
@{ +main }
<@ end @>
<@ article @>
</body>
</html>
Now as you can see, the main content field is actually encapsulated in a snippet definition called article. That snippet is called right after its definition in order to generate the actual output. This allows us to easily create a derived version of that template with a slightly different article body by overriding the snippet after including the master template:
<# derived.php #>
<# Let's include the master template first #>
<@ master.php @>
<# Now we can override the article snippet #>
<@ snippet article @>
@{ +hero }
<hr>
@{ +main }
<@ end @>
The resulting output when using the derived template for a page includes now two block editor fields — +hero
and +main
.
Example
A good example for inheritance can be found in the Automad repository. All templates that are used by the Standard theme are derived from the Post template. Now when you take a look at the Blog template you can see how inheritance is used to reduce the amount of code that has to be written.
Process Flow
In order to efficiently working with template inheritance it is essential to understand how the process flow looks like in Automad's template engine and what the limitations are. Under the hood, snippet definitions are registered before a template is actually rendered. Therefore it is possible to call a snippet before it is defined. However the snippet itself is only evaluated during rendering in a separate step. Due to that behavior, it is important to define overrides of nested snippets on the top level of a template. Let's have a look at an example to demonstrate what that actually means:
<# Here we define and evaluate "main" #>
<@ snippet main ~@>
Original content ...
<@~ end @>
<@ main @>
<# Now we override "main" #>
<@ snippet main ~@>
New content ...
<@~ end @>
<# The rendered output is "New content ..." #>
That was easy. Now let's try to nest snippets:
<@ snippet main ~@>
Original content ...
<@~ end @>
<@ main @>
<# We now override "main" and add the nested snippet "nested" #>
<@ snippet main ~@>
<@ snippet nested @>
Nested ...
<@ end @>
<@~ nested ~@>
<@~ end @>
<# The rendered output now is "Nested ..." #>
But we actually want to be able to also override nested
:
<@ snippet main ~@>
Original content ...
<@~ end @>
<@ main @>
<@ snippet main ~@>
<@ snippet nested @>
Nested ...
<@ end @>
<@~ nested ~@>
<# Trying to override "nested" #>
<@~ snippet nested ~@>
Nested override ...
<@~ end @>
<@~ end @>
The example right above fails since nested
is only evaluated during render time. To make it work we have to move the override of nested
to the top level:
<@ snippet main ~@>
Original content ...
<@~ end @>
<@ main @>
<@ snippet main ~@>
<@ snippet nested @>
Nested ...
<@ end @>
<@~ nested ~@>
<@~ end @>
<# We now try to override "nested" here ... #>
<@~ snippet nested ~@>
Nested override ...
<@~ end @>
<# The output is now "Nested override ..." #>