Blog setup with Emacs Org mode

Table of Contents

Target Setup

Org mode has great support for exporting org files to .html files. This is an attempt at setting up a blog using only Emacs and Org mode. The setup is really basic i.e. there is a collection of .org files under an org/ directory which shall be exported to HTML files under public_html/ folder.

The Journey

Setup an example Org file

Setup a exmpale org file with different levels of heading, inline code, code blocks as shown below and place under the org/ folder.

#+setupfile: ../org-templates/base.org
#+title: Blog setup with Emacs Org mode
#+date: <2020-05-25>

* Section Title

** Sub-Section Title
   Discussion with some inline ~code~ and an example python code block below

 #+BEGIN_SRC python
   def hello_world():
     return "Hello World"

Notice #+setupfile: ../org-templates/base.org at the beginning of the document. This is a setup file includes default configuration which will be used in all our blog org files. It might be a good idea to seperate your org templates into a seperate directory org-templates/ as you can choose to have multiple templates appended options to sepcific files.

#+options: ':nil *:t -:t ::t <:t H:2 \n:nil ^:t arch:headline author:t
#+options: broken-links:nil c:nil creator:nil d:(not "LOGBOOK") date:t e:t
#+options: email:nil f:t inline:t num:nil p:nil pri:nil prop:nil stat:t tags:t
#+options: tasks:t tex:t timestamp:t title:t toc:t todo:t |:t
#+author: Your Name
#+email: your.name@email.com
#+language: en
#+select_tags: export
#+exclude_tags: noexport
#+creator: Emacs 26.3 (Org mode 9.3.6)

The above template can be used as is or a template can be generated by invoking M-x org-export-insert-default-template and selecting default from the option list.

First Export

Before the exmaple org file can be exported to HTML using org-publish-all a publish configuration is needed,

(setq org-publish-project-alist
         :base-directory "org/"
         :base-extension "org"
         :publishing-directory "public_html/"
         :recursive t
         :publishing-function org-html-publish-to-html
         :headline-levels 2

Place the above expression in a new file publish.el in the same directory where org/ directory is placed. Evaluate the above expression by placing the cursor at the last outermost parantheses using C-x + e . Now the example org file can be published using M-x org-publish-all . This will create a corresponding HTML file under public_html/ folder from the org file. Head over to your browser and checkout the results!


The generated HTML file is not visually appeasing but this can improved rather easily with Solarised CSS. The CSS file can be modified as desired to have a personal touch, let your the creative person inside you come up with a visually appeasing look for your blog. Since the CSS should be applied to all the blog posts it desirable to not include it in every new org file. So to achieve this the CSS file can be included in base.org file which will be included in every blog file that will be created.

#+creator: Emacs 26.3 (Org mode 9.3.6)
#+HTML_HEAD: <link rel="stylesheet" type="text/css" href="css/stylesheet.css"/>

Notice the name of the CSS file is stylesheet.css. After including the CSS in base.org the publish configuration should be updated to include the same when exporting the blog i.e.

(setq org-publish-project-alist
         :base-directory "org/"
         :base-extension "org"
         :publishing-directory "public_html/"
         :recursive t
         :publishing-function org-html-publish-to-html
         :headline-levels 2

         :base-directory "static/"
         :base-extension "css"
         :publishing-directory "public_html/css"
         :recursive t
         :publishing-function org-publish-attachment

Notice that the css files should be placed in the static/ directory and on publishing they will be placed in public_html/css directory. The following is how the directory structure should look now,

├── org/
├── public_html/
├── static/
└── publish.el

Publish your changes using M-x org-publish-all. If you didn't see the changes being reflected in the published files then I would suggest to drop the org cache by evaluating (org-publish-remove-all-timestamps). This is has caused me enough trouble that I have created a small function always drop org cache before publishing as the it always gets in the way of publishing all new changes. I am not sure actually how the org publish cache works but I haven't found it helpful so far. I am sure that I missing some important details of how it actually works! Nevertheless the following is a handy workaround,

(defun publish-blog ()

I have binded the above function to C-x + C-p.

Beautify ergonomically

The base.org file can updated to have much more customizations which will be applied when the files are published. I added the following to change the preamble and postamble,

#+BIND: org-html-metadata-timestamp-format "%Y-%m-%d"
#+BIND: org-html-postamble "<p>%a  •  2020  •  %c</p>"
#+BIND: org-html-preamble "<div><h3 class='h3-preamble'>The <span class='blue'>Incomplete</span> Blog</h3><div class='published-date'> Published on %d </div></div>"

Note that (setq org-export-allow-bind-keywords t) must be set in order for #+BIND: ... to work.

HTML offers <kbd></kbd> tag to represent key bindings but there is no equivalent way to express this in org which would be expored to that tag. To make it possible I changed the default markup mappings and re-purposed verbatim to represent <kbd></kbd> tag.

(setq org-html-text-markup-alist
      '((bold . "<b>%s</b>")
        (code . "<code>%s</code>")
        (italic . "<i>%s</i>")
        (strike-through . "<del>%s</del>")
        (underline . "<span class=\"underline\">%s</span>")
        (verbatim . "<kbd>%s</kbd>")))

Future exploration

So far the process of setting up a blog with Org mode has been quite smooth and fun! During this journey I took inspiration from various other blogs out there 1 , 2 , 3 , 4 , 5 Moving forward I would explore the following topics,

  • Setup the sitemap for the blog i.e. have and index.org such that the blog can have a landing page.
  • Automating publishing setup using a Makefile. While setting up this blog I did try to explore setting up a Makefile by following steps from here but I found it particularly difficult to export the color scheme for the code blocks i.e. #+begin_src .. #+end_src . After exporting, it seems that the colors aren't exported.


Vanshdeep Singh • 2020 • Emacs 26.3 (Org mode 9.3.6)

Dividers Designed by Freepik