The Weary Travelers

A blog for computer scientists


Date: 2023-08-27
Author: Suhail
Suhail.png

How to generate a website with org-mode

In a previous blog-post, we looked at how a single org-mode file can be converted into HTML using the ox-html exporter.

However, when generating an entire website one needs to generate multiple inter-linked pages, sitemaps etc. Additionally, one may want to generate output that is different than what is generated by ox-html. How do we accomplish these things? Let’s find out!

Exporter back-ends

Org files can be exported into multiple formats with the help of exporter back-ends.

Org can convert and export documents to a variety of other formats while retaining as much structure (see Document Structure) and markup (see Markup for Rich Contents) as possible.

The libraries responsible for translating Org files to other formats are called back-ends.

ox-html is one such exporter back-end that exports an org-file to the HTML format. ox-latex, meanwhile, is an exporter back-end that exports to either .tex or .pdf formats.

Customizing the output of exporter back-ends

Sometimes, however, the stock output generated by an exporter back-end may not be sufficient for one’s needs. One way to modify the output of an exporter back-end is by defining filter functions that are chained together.

Filters are lists of functions to be applied to certain parts for a given back-end. The output from the first function in the filter is passed on to the next function in the filter.1The first filter function operates on the output of the exporter back-end. The final output is the output from the final function in the filter.

However, sometimes the changes one wishes to make are larger in scope than those that may be feasible using filter functions alone. In such situations, it might make sense to define a derived exporter back-end.

In addition to standalone exporter back-ends, some back-ends are instead derived from others.2Where the derived back-end has the same behaviour as the base back-end, except in some specific situations where the behaviour differs. A notable example of this is ox-beamer which derives from ox-latex and can be used to create Beamer presentations. Another is ox-tufte which derives from ox-html and produces HTML output in the style of tufte-css.3Such as the sidenotes which are used in the present blog.

Adding a custom exporter back-end, while relatively straightforward, still has a number of details that need to be understood. The Orgmode manual has some details to get started, but perhaps the best way is to review the code of an existing derived back-end.4A future blog post will review the ox-tufte derived back-end in depth.

So given an exporter back-end, one can convert an org-file into various generic or specific output formats.5Specific in the sense that the output contains additional structure. Each exporter back-end may also define some back-end specific export properties or keywords which can be used to customize the generated output. Thus, a naive way of exporting multiple files to a desired format would be to invoke the specific exporter back-end on each file.6In a manner similar to what was presented in the blog-post on ox-html.

Sharing configuration options via SETUPFILE​s

Configuration options that are the same across multiple files7For instance, the value of HTML_HEAD, HTML_HEAD_EXTRA, HTML_LINK_HOME etc. can be shared and specified once with the help of SETUPFILE​s.

A SETUPFILE is an org-mode file that specifies various in-buffer settings such as the value of various export keywords. It can be included in other org-mode files using the following syntax:

#+SETUPFILE: <filename or URL>

Exporting multiple files via ox-publish8Using ox-publish requires knowledge of Emacs Lisp. This reference sheet may be a good starting point.

While SETUPFILE​s can be used to great effect, they have a limitation in that the settings can only be specified in a defunctionalized form.9Unless, the setting in question allows one to specify the name of a function. I.e., they allow one to specify the value, but not describe computations that will yield the value of interest. A way to address this is to use ox-publish. ox-publish also allows one to generate sitemaps and indexes. Additionally, linking to other org-mode files within the project automatically inserts the link to the corresponding published target.

At the heart of ox-publish is the org-publish-project-alist variable that describes the project specification.10Since the variable is specified using Emacs Lisp (as opposed to plain text), one can, if so desired, describe a computation that yields its value instead. Among other things, it allows one to specify the specific exporter back-end to use (by specifying the publishing action)11Via the :publishing-function key. as well as the destination directory.12Via the :publishing-directory key.

When generating a website13Or publishing a book. a number of aspects may need to be configured. ox-publish allows one to do just that. As one might expect the devil is in the details, and for a first-timer it might help to consult some sample configurations first.14A future blog post will go into the specifics of how the present blog is published.

Comments

Comments can be left on twitter, mastodon, as well as below, so have at it.

To view the Giscus comment thread, enable Giscus and GitHub’s JavaScript or navigate to the specific discussion on Github.

Footnotes:

1

The first filter function operates on the output of the exporter back-end.

2

Where the derived back-end has the same behaviour as the base back-end, except in some specific situations where the behaviour differs.

3

Such as the sidenotes which are used in the present blog.

4

A future blog post will review the ox-tufte derived back-end in depth.

5

Specific in the sense that the output contains additional structure.

6

In a manner similar to what was presented in the blog-post on ox-html.

7

For instance, the value of HTML_HEAD, HTML_HEAD_EXTRA, HTML_LINK_HOME etc.

8

Using ox-publish requires knowledge of Emacs Lisp. This reference sheet may be a good starting point.

9

Unless, the setting in question allows one to specify the name of a function.

10

Since the variable is specified using Emacs Lisp (as opposed to plain text), one can, if so desired, describe a computation that yields its value instead.

11

Via the :publishing-function key.

12

Via the :publishing-directory key.

13

Or publishing a book.

14

A future blog post will go into the specifics of how the present blog is published.