diff --git a/content/docs/zola-cookbook/_index.md b/content/docs/zola-cookbook/_index.md
new file mode 100644
index 0000000..b4f4b68
--- /dev/null
+++ b/content/docs/zola-cookbook/_index.md
@@ -0,0 +1,67 @@
++++
+title = "Zola Cookbook"
+description = "Snippets I've developed that I want to keep"
+date = 2022-04-27T18:00:00+00:00
+updated = 2022-04-27T18:00:00+00:00
+template = "docs/section.html"
+sort_by = "weight"
+weight = 5
+draft = false
+[taxonomies]
+documentation=["Reference"]
+categories=["Web Development", "Static Site Generation", "Zola"]
++++
+
+[Zola](../zola) is the static site generator I use for most of my websites that
+don't require much dynamic functionality.
+
+## Generating Nested Lists from Data
+
+Example data:
+
+```html
+{
+ "definitions": [
+ { "dt": "undefined", "dd": " the thing is undefined." },
+ { "dt": "defined", "dd": " the thing is defined.", definitions: [
+ { "dt": "truthy", "dd": "the defined thing is truthy" },
+ { "dt": "falsy", "dd": "the defined thing is falsy" }
+ ]}
+ ]
+}
+```
+
+Tera macro to render a nested list:
+
+```
+{% macro definition_body(source) %}
+
+ {% for entry in source %}
+ - {{ entry.dt | safe }}
+ -
+ {{ entry.dd | safe }}
+ {% if entry.definitions %}
+ {{ self::definition_body(source=entry.definitions) }}
+ {% endif %}
+
+ {% endfor %}
+
+{% endmacro %}
+```
+
+Zola shortcode to import the macro template into Markdown and start the render:
+
+```
+{%- import 'macros/definition_body.html' as renderer -%}
+
+ {% set content = load_data(path=source) %}
+ {{ renderer::definition_body(source=content.definitions) }}
+
+```
+
+Invocation in Markdown file, providing the data source:
+
+```
+{ { definition_list(source="docs/zola/definitions.json") }}
+```
+
diff --git a/content/docs/zola/_index.md b/content/docs/zola/_index.md
index 393db8f..f9f4499 100644
--- a/content/docs/zola/_index.md
+++ b/content/docs/zola/_index.md
@@ -107,6 +107,8 @@ Conditional statements are managed with `if/is ... else ... endif`
The list of `is` tests that are shipped with Zola are:
+{{ definition_list(source="docs/zola/predicates.json") }}
+
- `defined`: the given variable is defined.
- `undefined`: the given variable is undefined.
- `odd`: the given variable is an odd number.
diff --git a/content/docs/zola/predicates.json b/content/docs/zola/predicates.json
new file mode 100644
index 0000000..48ef20d
--- /dev/null
+++ b/content/docs/zola/predicates.json
@@ -0,0 +1,40 @@
+{
+ "definitions": [
+ { "dt": "defined", "dd": " the given variable is defined." },
+ { "dt": "undefined", "dd": " the given variable is undefined." },
+ { "dt": "odd", "dd": " the given variable is an odd number." },
+ { "dt": "even", "dd": " the given variable is an even number." },
+ { "dt": "string", "dd": " the given variable is a string." },
+ { "dt": "number", "dd": " the given variable is a number." },
+ { "dt": "divisibleby", "dd": " the given expression is divisible by the arg given." },
+ {
+ "dt": "iterable",
+ "dd": " Returns true if the given variable can be iterated over in Tera (i.e. is an array/tuple or an object)."
+ },
+ {
+ "dt": "object",
+ "dd": " Returns true if the given variable is an object (i.e. can be iterated over key, value)."
+ },
+ {
+ "dt": "starting_with(string)",
+ "dd": " Returns true if the given variable is a string and starts with the arg given."
+ },
+ {
+ "dt": "ending_with(string)",
+ "dd": " Returns true if the given variable is a string and ends with the arg given."
+ },
+ {
+ "dt": "containing(val)",
+ "dd": " Returns true if the given variable contains the arg given.",
+ "definitions": [
+ { "dt": "strings", "dd": " is the arg a substring?" },
+ { "dt": "arrays", "dd": " is the arg one of the members of the array?" },
+ { "dt": "maps", "dd": " is the arg a key of the map?" }
+ ]
+ },
+ {
+ "dt": "matching(regexp)",
+ "dd": " Returns true if the given variable is a string and matches the regex in the argument."
+ }
+ ]
+}
diff --git a/content/docs/zola/predicates.yaml b/content/docs/zola/predicates.yaml
new file mode 100644
index 0000000..922d01d
--- /dev/null
+++ b/content/docs/zola/predicates.yaml
@@ -0,0 +1,52 @@
+---
+ definitions:
+ -
+ dt: "defined"
+ dd: " the given variable is defined."
+ -
+ dt: "undefined"
+ dd: " the given variable is undefined."
+ -
+ dt: "odd"
+ dd: " the given variable is an odd number."
+ -
+ dt: "even"
+ dd: " the given variable is an even number."
+ -
+ dt: "string"
+ dd: " the given variable is a string."
+ -
+ dt: "number"
+ dd: " the given variable is a number."
+ -
+ dt: "divisibleby"
+ dd: " the given expression is divisible by the arg given."
+ -
+ dt: "iterable"
+ dd: " Returns true if the given variable can be iterated over in Tera (i.e. is an array/tuple or an object)."
+ -
+ dt: "object"
+ dd: " Returns true if the given variable is an object (i.e. can be iterated over key, value)."
+ -
+ dt: "starting_with(string)"
+ dd: " Returns true if the given variable is a string and starts with the arg given."
+ -
+ dt: "ending_with(string)"
+ dd: " Returns true if the given variable is a string and ends with the arg given."
+ -
+ dt: "containing(val)"
+ dd: " Returns true if the given variable contains the arg given."
+ definitions:
+ -
+ dt: "strings"
+ dd: " is the arg a substring?"
+ -
+ dt: "arrays"
+ dd: " is the arg one of the members of the array?"
+ -
+ dt: "maps"
+ dd: " is the arg a key of the map?"
+ -
+ dt: "matching(regexp)"
+ dd: " Returns true if the given variable is a string and matches the regex in the argument."
+
diff --git a/templates/macros/definition_body.html b/templates/macros/definition_body.html
new file mode 100644
index 0000000..a8ef1f0
--- /dev/null
+++ b/templates/macros/definition_body.html
@@ -0,0 +1,9 @@
+{% macro definition_body(source) %}
+
+{% for entry in source %}
+- {{ entry.dt | safe }}
+- {{ entry.dd | safe }}
+{% if entry.definitions %}{{ self::definition_body(source=entry.definitions) }}{% endif %}
+{% endfor %}
+
+{% endmacro %}
diff --git a/templates/shortcodes/definition_list.html b/templates/shortcodes/definition_list.html
new file mode 100644
index 0000000..ff9b7a2
--- /dev/null
+++ b/templates/shortcodes/definition_list.html
@@ -0,0 +1,5 @@
+{%- import 'macros/definition_body.html' as renderer -%}
+
+{% set content = load_data(path=source) %}
+{{ renderer::definition_body(source=content.definitions) }}
+