Problem

The problem appeared in a recent document. I used to use pandoc in order to transform an .org file into github flavoured .md, i.e when doing

pandoc -s -t markdown file.org -o file.md

I can obtain content in markdown which includes the header that looks more or less like this:

---
author:
- cissic
date: '\<2022-11-10 Thu\>'
tags: 'org-mode export-settings'
title: 'How to tailor the output of org-mode exporter to our needs'
---

This header is important, especially the ‘tags’ part, because basing on this my template assigns tags to the post.

Everything worked fine until I decided to use a more sophisticated syntax for source parts of the text in my recent post. Namely I wrote:

#+begin_src org :tangle (concat (org-entry-get nil "PRJ-DIR" t) "main-book.org") :mkdirp yes

This is too much for pandoc converter. An org file with such lines was all messed up. I decided to use standard emacs exporter (C-c C-e m m), however when using it we need to instruct it to add special markdown header mentioned above. How can we do this?

Solution - first try

The solution can be found here. We need to add

#+OPTIONS: -:nil

to the keywords at the start of the org-file in order to disable special treatment of minus sign during the export (This is described here).

And then we could just add the following to init.el:

(defun org-export-md-format-front-matter ()
  (let* ((kv-alist (org-element-map (org-element-parse-buffer 'greater-element)
                       'keyword
                     (lambda (keyword)
                       (cons (intern (downcase (org-element-property :key keyword)))
                             (org-element-property :value keyword)))))
         (lines (mapcar (lambda (kw)
                          (let ((val (alist-get kw kv-alist)))
                            (format (pcase kw
                                      ('author "%s: %s")
                                      ((or 'tags 'title) "%s: '%s'")
                                      (_ "%s: %s"))
                                    (downcase (symbol-name kw))
                                    (pcase kw
                                      ('date (substring val 1 -1))
                                      (_ val)))))
                        '(author date tags title))))
    (concat "---\n" (concat (mapconcat #'identity lines "\n")) "\n---")))

(defun my/org-export-markdown-hook-function (backend)
    (if (eq backend 'md)
        (insert (org-export-md-format-front-matter) "\n")))

(add-hook 'org-export-before-processing-hook #'my/org-export-markdown-hook-function)

Now, the file generated when exporting from .org to .md contains desired data.

Solution - a better try

However the above mentioned approach has a drawback that it changes the way how the default Emacs to markdown exporter works.

So the desired behaviour would be to have this edited way of exporting org files working only for specific files. In particular, it would be convenient to change the exporter behaviour from within the file. In order to do this we need to make use of Emacs’ local variables.

So what we need to do is to comment out the last line of the code above from the init.el to avoid loading hook globally. So init.el should be supplemented only with:

(defun org-export-md-format-front-matter ()
  (let* ((kv-alist (org-element-map (org-element-parse-buffer 'greater-element)
                       'keyword
                     (lambda (keyword)
                       (cons (intern (downcase (org-element-property :key keyword)))
                             (org-element-property :value keyword)))))
         (lines (mapcar (lambda (kw)
                          (let ((val (alist-get kw kv-alist)))
                            (format (pcase kw
                                      ('author "%s: %s")
                                      ((or 'tags 'title) "%s: '%s'")
                                      (_ "%s: %s"))
                                    (downcase (symbol-name kw))
                                    (pcase kw
                                      ('date (substring val 1 -1))
                                      (_ val)))))
                        '(author date tags title))))
    (concat "---\n" (concat (mapconcat #'identity lines "\n")) "\n---")))

(defun my/org-export-markdown-hook-function (backend)
    (if (eq backend 'md)
        (insert (org-export-md-format-front-matter) "\n")))

The specific .org file should contain the following line at the beginning:

#+OPTIONS: -:nil

and the following code at the bottom of the file:

# Local Variables:
# eval: (add-hook 'org-export-before-processing-hook #'my/org-export-markdown-hook-function nil t)
# End:

Now have it working one needs to

save, close and open the file again

after adding the above content (or just reload the file with commands M-x revert buffer or C-x C-v RET).

Helpful Links:


org-mode export-settings