💾 Archived View for sdf.org › rsdoiel › blog › 2020 › 11 › 09 › Pandoc-Partials.txt captured on 2023-03-20 at 19:21:40.
⬅️ Previous capture (2023-01-29)
-=-=-=-=-=-=-
Pandoc Partial Templates ======================== Most people know about [Pandoc](https://pandoc.org/) from its fantastic ability to convert various markup formats from one to another. A little less obvious is Pandoc can be a template engine for rendering static websites allowing you full control over the rendered content. The main Pandoc documentation of the template engine can be found in the [User Guide](https://pandoc.org/MANUAL.html#templates). The documentation is complete in terms of describing the template capabilities but lacks a tutorial for using as a replacement for more ambitious rendering systems like [Jekyll](https://jekyllrb.com/) or [Hugo](https://gohugo.io/). Pandoc takes a vary direct approach and can be deceptively simple to implement. Use your own template --------------------- First thing in this tutorial is to use our own template with Pandoc when rendering a single webpage. You use the `–-template` option to provide your a template name. I think of this as the page level template. This template, as I will show later, can then call other partial templates as needed. Example, render the [Pandoc-Partials.txt](Pandoc-Partials.txt) file using the template named [index1.tmpl](index1.tmpl): ~~~{.shell} pandoc --from=markdown --to=html \ --template=index1.tmpl Pandoc-Partials.txt > index1.htm ~~~ This is a simple template page level template. ~~~{.html-code} <!DOCTYPE html> <html> <head> </head> <body> ${body} </body> </html> ~~~ When we run our Pandoc command the file called [Pandoc-Partials.txt](Pandoc-Partials.txt) is passed into the template as the "body" element where it says `${body}`. See this Pandoc [User Guide](https://pandoc.org/MANUAL.html#templates) for the basics. Example 1 rendered: [index1.htm](index1.htm) Variables and metadata ---------------------- Pandoc's documentation is good at describing the ways of referencing a variable or using the built-in template functions. Where do the variables get their values? The easiest way I've found is to set the variables values in a JSON metadata file. While Pandoc can also use the metadata described in YAML front matter Pandoc doesn't support some of the other common front matter formats. If you're using another format like JSON or TOML for front matter there are tools which can split the front matter from the rest of the markdown document. For this example I have created the metadata as JSON in a file called [metadata.json](metadata.json). Example [metadata.json](metadata.json): ~~~{.json} { "title": "Pandoc Partial Examples", "nav": [ {"label": "Pandoc-Partials", "href": "Pandoc-Partials.html" }, {"label": "Version 1", "href": "index1.htm" }, {"label": "Version 2", "href": "index2.htm" }, {"label": "Version 3", "href": "index3.htm" } ] } ~~~ Let's modify our initial template to include our simple navigation and title. Example [index2.tmpl](index2.tmpl): ~~~{.html-code} <!DOCTYPE html> <html> <head> ${if(title)}<title>${title}</title>${endif} </head> <body> <nav> ${for(nav)}<a href="${it.href}">${it.label}</a>${sep}, ${endfor} </nav> <section> ${body} </section> </body> </html> ~~~ We would include our navigation metadata with a Pandoc command like ~~~{.shell} pandoc --from=markdown --to=html \ --template=index2.tmpl \ --metadata-file=metadata.json Pandoc-Partials.txt > index2.htm ~~~ When we render this we now should be able to view a web page with simple navigation driven by the JSON file as well as the body content contained in the Pandoc-Partials.txt file. Example 2 rendered: [index2.htm](index2.htm) Partials -------- Sometimes you have more complex documents. Putting this all in one template can become tedious. Web designers use a term called "partials". This usually means a template for a "part" of a page. In our initial example we can split our navigation into it's own template. Implementing partials --------------------- Pandoc will look in the current directory for partials as well as in a sub directory called "templates" of the current direct. In this example I am going to include my partial template for navigation in the current directory along side my [index3.tmpl](index3.tmpl). My navigation template is called [nav.tmpl](nav.tmpl). Here's my partial template: ~~~{.html-code} <nav> ${for(nav)}<a href="${it.href}">${it.label}</a>${sep}, ${endfor} </nav> ~~~ Here's my third iteration of our index template, [index3.tmpl](index3.tmpl). ~~~{.html-code} <!DOCTYPE html> <html> <head> ${if(title)}<title>${title}</title>${endif} </head> <body> ${if(nav)} ${nav.tmpl()} ${endif} <section> ${body} </section> </body> </html> ~~~ Pandoc only requires you to reference the partial by using its base name. Many people will name their templates with the extension ".html". I find this problematic as if you're trying to list the templates in the directory you can not easily list them separately. I use the ".tmpl" extension to identify my templates. Since I have other documents that share the base name "nav" I explicit call my navigation partial using the full filename followed by the open and closed parenthesis. I have also chosen to wrap the template in an "if" condition. That way if I don't want navigation on a page I skip defining it in my metadata file. Inside the partial template we inherit the parent metadata object. You can use all the built-in Pandoc template functions and variables provided by Pandoc in your partial templates. Putting it all together: ~~~{.shell} pandoc --from=markdown --to=html \ --template=index3.tmpl \ --metadata-file=metadata.json Pandoc-Partials.txt > index3.htm ~~~ Example 3 rendered: [index3.htm](index3.htm)