YC blog

How to set up org mode for blogging

This blog is on how I set up my blog pulishing process in emacs org mode.

Setting up essentials

Org mode

I started to use org mode to document my work several years ago. Before that I am using markdown for this purpose. After know how powerful org mode is, I can't help but want to do everything in org mode.

Org mode is not only a text mode. You can use it as your calendar, to-do list, and work report. You can insert code snippet and even run in it to get the return results of your snippet. You can even play games in it. But as a text mode, it gives you the power to output you org file into different formats, including pdf, latex, markdow, MS doc, html etc.

If that sounds a ton of funs to you, please try org mode out!

ox-pandoc & pandoc

I have been searching for a good package to convert org to markdown. And I discover this beautiful package ox-pandoc that use pandoc as the backend to convert your org file into other format. Pandoc is one of my old friends, and I used to write my PhD thesis in markdown and use it to convert into pdf with a latex template. It is very versitile. If you have even been driven crazy on converting file to different formats, you should definitely check pandoc out.

Set up publishing directory

Directory structure

This is the structure that I used to organize my blog.

myProject
├───org
└───myBlog
    ├───assets
    ├───_data
    ├───_includes
    ├───_layouts
    ├───_posts
    ├───_sass
    └───_site

I write and put all my org files under org directory, and then I publish all org into markdown under myBlog/_posts/.

Convert org to markdown

In org mode, you can export the current org file into markdown using C-c C-e p and choose from the options that you want. If you have ox-pandoc ready, you can see a list of pandoc output options.

If you did not see the markdown option, you need to go to ox-pandoc.el and uncomment the following lines as you needed:

;;(?k "to markdown." org-pandoc-export-to-markdown)
;;(?k "to markdown and open." org-pandoc-export-to-markdown-and-open)
;;(?K "as markdown." org-pandoc-export-as-markdown)

After that, you need to recompile the ox-pandoc.el by M-x emacs-lisp-byte-compile. Now you get your markdown option under pandoc.

Publish all of your organize

It would be tedious to hit the export everytime you want to convert you org to markdown. One option org mode offers you is to publish a project. This means that you can publish all org files under your project in one command (you can read more on publishing).

First, you need to set up a project. Simply define the source org files and destination of the markdown files in your init.el:

(setq org-publish-project-alist
  '(("my-blog"
     :base-directory "/path/to/myProject/org/"
     :base-extension "org"
     :publishing-directory "/path/to/myProject/myBlog/_posts/"
     :publishing-function (org-pandoc-publish-to-markdown))
    ("all" :components ("my-blog"))))

The publish command is C-c C-e P x and then select my-blog. Then all the org files would be executed in the publishing function and get converted into markdown.

Some extrac works

Publish using ox-pandoc backend

In the previous section, I use a user-defined function org-pandoc-publish-to-markdown for the conversion. The reason is that the ox-pandoc conversion function is not compatible with the org mode publish function. If I simply supply a ox-pandoc function org-pandoc-export-to-markdown to the publishing-function, there will be an error:

Publishing file /path/to/pubtest.org using `org-pandoc-export-to-markdown'
Initializing asynchronous export process
Publishing file /path/to/pubtest.org using `org-pandoc-export-to-markdown'
Process `org-export-process' exited abnormally

The reason being that the org-pandoc-export-to-markdown does not take arguments used during org mode export (see this answer). Therefore, you need to construct a function to take such arguments and also run pandoc conversion. Luckily, pgorczak has come up with a solution for this function in this issue (thank you so much!). You only need to put these in your init.el:

(defun org-pandoc-publish-to (format plist filename pub-dir)
  (setq org-pandoc-format format)
  (let ((tempfile
   (org-publish-org-to
    'pandoc filename (concat (make-temp-name ".tmp") ".org") plist pub-dir))
  (outfile (format "%s.%s"
           (concat
            pub-dir
            (file-name-sans-extension (file-name-nondirectory filename)))
           (assoc-default format org-pandoc-extensions))))
    (let ((process
     (org-pandoc-run tempfile outfile format 'org-pandoc-sentinel
             org-pandoc-option-table))
    (local-hook-symbol
     (intern (format "org-pandoc-after-processing-%s-hook" format))))
      (process-put process 'files (list tempfile))
      (process-put process 'output-file filename)
      (process-put process 'local-hook-symbol local-hook-symbol))))

(defun org-pandoc-publish-to-markdown (p f pd)
  (org-pandoc-publish-to 'markdown p f pd))

Pass front matter to markdown

In order to function normally, the markdown file needs a front matter block to specify layout, title, time etc.

We can pass such header by adding a structure template block at the start of the org file using C-c C-, E, and change the block attribute to markdown.

#+begin_export markdown
---
layout: post
title: "How to set up org mode for blogging"
date:   2021-11-23 18:00:00 +0800
categories: blog
---
#+end_export

However, the ox-pandoc by default enable --standalone for all format. This would automaticall create a empty front matter in the final markdown. This will cause the header of the output markdown to look like this:

---
---

---
layout: post
title: "How to set up org mode for blogging"
date:   2021-11-23 18:00:00 +0800
categories: blog
---

In order to fix this, we can simply turn off --standalone for markdown mode only and we pass our own front matter to pandoc. Add this to your init.el:

;; ox-pandoc default options for all output formats
(setq org-pandoc-options '((standalone . t)))
;; cancel above standalone 'markdown' format so that we can pass front matter in org mode.
(setq org-pandoc-options-for-markdown '((standalone . nil)))

Now you are all good to go. Go ahead and publish your blogs in one go!