Org Export Hooks

In my quest for a simplified, org-based publishing scheme, I would like to add some information to a file when I export it. Namely, I would like to add some metadata within the file, something like:

    #+property: exported: 2018-01-30

Let’s see if I can prototype this functionality through Org-mode!

Hooks and Useful Functions

I can think of some functions and/or variables I will need:

Let’s put them together into an elisp snippet.

    (add-hook 'org-export-preprocess-final-hook
      (save-excursion
        (goto-char (point-max))
        (insert "\n#+property: exported: ")
        (org-insert-time-stamp (current-time))
        (insert "\n")))

I think that does the thing that I want. Ideally the property would go near (but not at) the top of my document, but that seems overly hard for the moment. Notice that executing the block puts the #+property at the end of the document. That is the behavior we want, BUT it should not be happening when executing the block rather it should happen on export. Also, this function will keep inserting more text, rather than update an existing property.

That seems like a rather hacky way to set properties. There must be something included with org. Let’s try the org-set-property function.

    (save-excursion
      (goto-char (point-min))
      (org-set-property "exported:" (format-time-string (car org-time-stamp-formats) (current-time))))

Gross. Without going to the beginning of the file, it just adds a property drawer to the current subtree. Going to the beginning of the file just inserts the timestamp with the error: “Before first headline in position 1”.

StackExchange to the Rescue

This StackExchange Question leads me in the direction of the powerful org-element-parse-buffer. Actually, there is one solution which includes a rather elegant set of org-global-prop functions that I want to properly package up and attribute1. Let’s try them out:

    (org-global-prop-set "exported:" (format-time-string (car org-time-stamp-formats) (current-time)))

That function works! What about as a hook?

    (add-hook 'org-export-before-parsing-hook
      '(org-global-prop-set "exported:" (format-time-string (car org-time-stamp-formats) (current-time))))

Ugh, hooks are dead. Reading through the official org documenatation, it seems like each hook operates on a copy of the current buffer, not what I want.

Hooking on to Something

That’s fine, I can hack in another way. Let’s just rebind the keys that do the exporting to a new function which will do the export property update.

    ;; add exported: property with date to org files when exporting
    (defun my/org-export-dispatch ()
      "updateds the exported: property before opening the dispatch"
      (org-global-prop-set "exported:" (format-time-string (car org-time-stamp-formats) (current-time)))
      (org-export-dispatch))
    (add-hook 'org
              '(local-set-key (kbd "C-c C-e") 'my/org-export-dispatch))

Not perfect (the spaces/newlines after the property are globbed) but good enough for now. Someday I’ll have to work on integrating this functionality into the publishing process (rather than this hack), but hey, it works.

Footnotes

1 I found the author, Tobias Zawada, and put the code on GitHub.