2.2.1 The Export Process

This subsection outlines the generic Org Export process with an eye toward customizing it for our purposes. While we defer the fully-customized implementation to See Customizing the Publication Process, it is here that we introduce indie-org.sh, a live example of an Org-generated static site built on top of indie-org.

The Org Export publication process, in broad terms, looks like this:

generic-org-pub-flow

The main entrypoint to the Org Export facility is See org-publish-all. org-publish-all refers to the variable See org-publish-project-alist, which describes our publication “project” to Org Mode. For each project (the root project can have sub-projects), Org Export will iterate over each file, copying it to its configured destination and, in general, transforming the contents in some way.

Of particular note is the info, or plist argument which is initialized at the beginning of the process of publishing each project (in org-publish-file) and is passed down through the entire call stack. It begins as the project plist (i.e. the project entry in org-publish-project-alist) and is augmented at each step. It is a property list that the different pieces of the publication pipeline use to communicate, and indie-org will use it as well.

The process of transforming the Org Mode document to another format is governed by the :publishing-function attribute for each project. It is invoked with the input filename, the publication directory, and the project plist.

indie-org.sh has two sub-projects salient to this discussion: “pages” and “posts”. The former contains a few top-level pages (home, about & so forth) whereas the latter contains all the site posts. Each employs a lambda as its publishing-function; the lambdas simply provide one more argument to the true publishing implementation, iosh/publish-page. The additional argument is the Org Export See Back-end in Adding Export Back-ends to use.

iosh/publish-page passes that back-end on org-publish-org-to and thence to org-export-to-file and org-export-as, which is where the real work begins. The function has a lot of functionality packed into its 171 lines; of note to us, it will:

  1. Parse the buffer being exported into Org elements (see See org in Org Syntax)
  2. Give the export backend the opportunity to filter the resulting parse tree; we’re not doing that so far in this example, but will take advantage of this below.
  3. Transcodes the resulting parse tree to HTML
  4. Extract the template from the backend & ask it to produce an HTML document from that HTML
  5. Offers the backend the opportunity to “finalize” the resulting page; that is, to run arbitrary code after the HTML document has been produced.

We introduce an Emacs Lisp file, indie-org.sh.el to the project where we can setup this boilerplate & invoke org-publish-all:

(defun iosh/publish (prod)
  "Publish indie-org.sh to production if PROD is non-nil, locally else."
  ;; Define a derived backend to insert our template:
  (org-export-define-derived-backend
      'iosh/page-html
      'html
      :translate-alist '((template . iosh/page-html)))
  (org-export-define-derived-backend
      'iosh/post-html
      'html
      :translate-alist '((template . iosh/post-html)))
  ;; ...
  (let* ((publishing-root (concat (file-name-as-directory project-dir) "www"))
         (org-publish-project-alist
          `(("indie-org.sh" :components ("pages"))
            ("pages"
             :base-directory             ,(concat project-dir "pages")
             :publishing-directory       ,(concat project-dir "www")
             :publishing-function        ,(list
                                           (lambda (plist filename pub-dir)
                                             (iosh/publish-page plist filename pub-dir 'iosh/page-html)))
             :html-doctype               "html4-strict"
             ...
             )
            ("posts"
             :base-directory             ,(concat project-dir "posts")
             :publishing-directory       ,(concat project-dir "www/posts")
             :publishing-function        ,(list
                                           (lambda (plist filename pub-dir)
                                             (iosh/publish-page plist filename pub-dir 'iosh/post-html)))
             :html-doctype               "html4-strict"
             ...
             ))))
      (org-publish-all t)
      ;; ...
      ))