Blogging with just Org Mode

Why

I wanted to learn more about some of the powerful features of Org Mode that I wasn’t using or even aware of. It also a good opporunity to learn about and practice my Elisp. I also wanted a setup where I understood more what was going, and have the ability to control and tweak it to suit my needs.

My current blogging setup involved Hugo and Org Mode by using hugo and the excellent packaged ox-hugo that converts my org files to hugo compatible markdown. However one of things about org mode is being able to directly export to html. So it seems logical that you can use this export functionality to build your static website, without the need of using a tool like Hugo. From this setup I am aiming to use Org Mode for capturing and writing. I then use frontend tools/technologies for managing styling/layouts.

A lot of the following is inspired by this excellent post. I have made small changes to it that suits my needs, and expanded on some parts.

Basic HTML file

Below is a simple Org file, that could be the layout for a blog:


* My Awesome Title for My Blog

**  Coding Posts

***  Elisp yay
***  Clojure is awesome

**  Film Posts

***  Really cool movie 1
***  Movie was sad 2

Export this file as html file you can do this in spacemacs with SPC e e h h.

Once you insepct the file you can see that there is alot of extra things that you probably don’t need. Ideally all I want is from my org file to be converted to html with as minimal amount of html as possible, but still retain its structure.

At the top of your org file you can put the following:

#+OPTIONS: html-style:nil

This essentially will remove all the styling from your the html export. Export it again and inspect the html file and you see will see a little less clutter.

By setting html-style:nil makes it easier for me to add my own css styles later on and customize exactly how my site should look like. We can add a reference to our custom styles by adding the following of the org file.

#+HTML_HEAD: <link rel="stylesheet" type="text/css" href="custom_styles.css"/>
#+HTML_HEAD_EXTRA:<link rel="icon" type="image/png" href="favicon.png">

If you export the org file and inspect html file you will see the above lines.

When you view your html file, you will see that there two anchor links. One linking to HOME and the other linking to UP. We can customize where these will link to by adding the following in the top of our org file.

#+HTML_LINK_HOME: /
#+HTML_LINK_UP: /

But what about if we want to customize HOME and UP. Or have more than two links. This is where Local Variables come in. These essentially act as variables you can set for the file in the org file.

Below is how I set the format of the home/up format. In addition I can add a preamble, which is useful some sort of meta information. For example when the last time the file was modified/exported.

# local variables:
# org-html-home/up-format: "<div id=\"org-div-home-and-up-index-page\"> <a accesskey=\"h\" href=\"%s\"> UP </a> | <a accesskey=\"H\" href=\"%s\"> HOME </a> </div> <div> <a href=\"./index.xml\"> RSS </a> | <a href=\"https://github.com/dilzeem/dilzeem.github.io\"> Source </a> | <a href=\"https://creativecommons.org/licenses/by-sa/4.0/\"> License </a> </div> </div>"
# org-html-postamble-format: (("en" "<p class=\"Last Modified Time\">%T</p> <p class=\"date\">%d</p>"))
# end:

While the above looks like a mess, below you can see it

org-html-home/up-format

Below one more links have been added Source and we have removed the UP link.


<div id="org-div-home-and-up-index-page">
 <a accesskey="H" href="index.html"> HOME </a> | <a href="https://github.com/dilzeem/dilzeem.github.io\"> Source </a>
</div>

org-html-postamble-format

<p class="Last Modified Time">%T</p> <p class="date">%d</p>

Finally we just make sure that the preamble is set for our project and we set the postamble to nil. If you look at the previous exports of your html file, you will see some meta information a the bottom of the html file. By setting the post-amble to nil we remove such information.

#+OPTIONS: html-preamble:t
#+OPTIONS: html-postamble:nil

After all that your org file should something along the lines of this:

#+HTML_HEAD: <link rel="stylesheet" type="text/css" href="custom_styles.css"/>
#+HTML_HEAD_EXTRA:<link rel="icon" type="image/png" href="favicon.png">
#+OPTIONS: html-style:nil
#+OPTIONS: html-preamble:nil
#+OPTIONS: html-postamble:t

      * My Awesome Title for My Blog

      **  Coding Posts

      ***  Elisp yay
      ***  Clojure is awesome

      **  Film Posts

      ***  Really cool movie 1
      ***  Movie was sad 2

# local variables:
# org-html-home/up-format: "<div id=\"org-div-home-and-up-index-page\"> <a accesskey=\"h\" href=\"%s\"> UP </a> | <a accesskey=\"H\" href=\"%s\"> HOME </a> </div> <div> <a href=\"./index.xml\"> RSS </a> | <a href=\"https://github.com/dilzeem/dilzeem.github.io\"> Source </a> | <a href=\"https://creativecommons.org/licenses/by-sa/4.0/\"> License </a> </div> </div>"
# org-html-preamble-format: (("en" "<p class=\"Last Modified Time\">%T</p> <p class=\"date\">%d</p>"))
# end:

And after you export it you should have a pretty basic html file. Now this serves as a great starting point to actually start styling your blog with CSS. Placing this file custom_styles.css, in the root of your where your file will be exported.

Blog Structure

Right now we have exported a single html file from one org file. We could easily create a new org file for each of our new blog post. However this would mean I would need to set up a template with all the meta information as described in the previous section.

To avoid this we can just use one org file with each org heading being a new post. To export we can use the function inbuilt into export function Emacs that allows us to export the subtree.

In spacemacs this would be SPC m e e and then press C-s to toggle exporting only the subtree to html. This means all the meta values we put in the org file will be used for the sub tree export.

When we export our posts it would also be nice to have some control over what the file should be called, and specify other meta information. This will can be achieved by adding a properties drawer under the heading/blog in questions.

:PROPERTIES:
:EXPORT_FILE_NAME: ./posts/2018-10-02-first-post.html
:EXPORT_DATE: <2018-10-07 Sun>
:END:

As you can see we have a specific that we have named the html file. This is useful for us later when we need sort all our posts.

So our org file is as follows:


#+begin_src text
#+HTML_HEAD: <link rel="stylesheet" type="text/css" href="custom_styles.css"/>
#+HTML_HEAD_EXTRA:<link rel="icon" type="image/png" href="favicon.png">
#+OPTIONS: html-style:nil
#+OPTIONS: html-preamble:t
#+OPTIONS: html-postamble:nil

      * My Awesome Title for My Blog

      **  Coding Posts

      ***  Elisp yay
      :PROPERTIES:
      :EXPORT_FILE_NAME: ./posts/2018-10-02-first-post.html
      :EXPORT_DATE: <2018-10-02 Sun>
      :END:

      ***  Clojure is awesome
      :PROPERTIES:
      :EXPORT_FILE_NAME: ./posts/2018-10-03-second-post.html
      :EXPORT_DATE: <2018-10-03 Sun>
      :END:

      **  Film Posts

      ***  Really cool movie 1
      ***  Movie was sad 2

# local variables:
# org-html-home/up-format: "<div id=\"org-div-home-and-up-index-page\"> <a accesskey=\"h\" href=\"%s\"> UP </a> | <a accesskey=\"H\" href=\"%s\"> HOME </a> </div> <div> <a href=\"./index.xml\"> RSS </a> | <a href=\"https://github.com/dilzeem/dilzeem.github.io\"> Source </a> | <a href=\"https://creativecommons.org/licenses/by-sa/4.0/\"> License </a> </div> </div>"
# org-html-preamble-format: (("en" "<p class=\"Last Modified Time\">%T</p> <p class=\"date\">%d</p>"))
# end:

#+end_src

Getting all the blog posts

Now that we have a way to manage our blog posts. The final piece of the puzzle is how do we list all our posts and by the order that they were created? This is where we have to learn a little bit of Elisp.

Here are some useful resources that can you get started with elips:

http://ergoemacs.org/emacs/elisp%5Fmapcar%5Floop.html https://www.gnu.org/software/emacs/manual/html%5Fnode/elisp/index.html#Top

First thing is we can run the function directory-files and see what we get. To see documentation of the function you can easily look it up in spacemacs with SPC h d f which brings up a prompt where you can type the function you want to look at.

If you run the following, you will get a list of all the files in your directory.

(directory-files ".")

What we need to do instead is get a list of all the html files in the posts directory. The nil refers to the not returning the full path of the files but the relative paths instead.

(directory-files "./posts/" nil ".html")

What we would get returned is a list of file paths. What we would like to do iterate through the list and then do some formatting. The actual thing we would like to extract is the title date of our posts.

To iterate over the list we can use dolist and let.

In the following we set x as an item from list of posts filenames from above. Then we have the value which empty initially. We uses this to store the transformed file paths.

progn will run code sequentially, and all we do here is the following blocks of code is extract the title, date and entire filepath. All this is required for when we need to write this out later as part of our list of links to all our posts that will be in our Home page of the blog.


(setq posts (let (value filepath title date)
              (dolist (x (directory-files "./posts" nil ".html")
                       value)
                (progn
                  (setq filepath x)
                  (setq title (s-titleized-words (substring x 10 nil)))
                  (setq date  (substring x 0 10))
                  (setq value (push (list filepath title date) value))))))

Our posts will be in list and look something like the following:


((2020-01-09-the-second-post.html The Second Post Html 2020-01-09)
 (2020-01-06-the-first-posts.html The First Posts Html 2020-01-08))

What we need to is to transform the list into org heading links. This is done from the following snippet of code. Note posts is from the previous section.


(string-join (mapcar (lambda (p)
                       (format "* [[./%s][%s]] %s\n\n" (nth 0 p)
                               (nth 1 p)
                               (nth 2 p)))
                     posts))

What we end up getting are org headings as follows:


'* [[./2020-01-09-the-second-post.html][The Second Post Html]] 2020-01-09

'* [[./2020-01-06-the-first-posts.html][The First Posts Html]] 2020-01-06

Now after figuring out the elisp needed to read the blog html files and outputs them as headings we can put it all in a single function.


(string-join (mapcar
              (lambda (p)
                (format "[[./%s][%s]] %s\n\n"
                        (nth 0 p) (nth 1 p) (nth 2 p)))
              (let (value filepath title date)
                (dolist (x (directory-files "./posts" nil ".html") value)
                  (progn (setq filepath x)
                         (setq title (s-titleized-words (substring x 10 nil)))
                         (setq date  (substring x 0 10))
                         (setq value (push (list filepath title date) value)))))))

The final thing to put this all together, and make it work with our org file is add special line that defines a macro that we can use within the code. Below define the macro to be called posts which is essentially what have defined above.

Now if we wish to use this macro we can add the following {{{posts()}}} anywhere in org file, and it will run the code.

#+MACRO: posts (eval (string-join (mapcar (lambda (p) (format "[[./%s][%s]] %s\n\n" (nth 0 p) (nth 1 p) (nth 2 p))) (let (value filepath title date) (dolist (x (directory-files "./posts" nil ".html") value) (progn (setq filepath x) (setq title (s-titleized-words (substring x 10 nil))) (setq date  (substring x 0 10)) (setq value (push (list filepath title date) value))))))))


{{{posts()}}}

So our final org file looks like this


#+HTML_HEAD: <link rel="stylesheet" type="text/css" href="custom_styles.css"/>
#+HTML_HEAD_EXTRA:<link rel="icon" type="image/png" href="favicon.png">
#+OPTIONS: html-style:nil
#+OPTIONS: html-preamble:nil
#+OPTIONS: html-postamble:t
#+MACRO: posts (eval (string-join (mapcar (lambda (p) (format "[[./%s][%s]] %s\n\n" (nth 0 p) (nth 1 p) (nth 2 p))) (let (value filepath title date) (dolist (x (directory-files "./posts" nil ".html") value) (progn (setq filepath x) (setq title (s-titleized-words (substring x 10 nil))) (setq date  (substring x 0 10)) (setq value (push (list filepath title date) value))))))))

      * My Awesome Title for My Blog

      ** Index

      {{{posts()}}}

      **  Coding Posts

      ***  Elisp yay
      :PROPERTIES:
      :EXPORT_FILE_NAME: ./posts/2018-10-02-first-post.html
      :EXPORT_DATE: <2018-10-02 Sun>
      :END:

            ***  Clojure is awesome
      :PROPERTIES:
      :EXPORT_FILE_NAME: ./posts/2018-10-03-second-post.html
      :EXPORT_DATE: <2018-10-03 Sun>
      :END:


      **  Film Posts

      ***  Really cool movie 1
      ***  Movie was sad 2

# local variables:
# org-html-home/up-format: "<div id=\"org-div-home-and-up-index-page\"> <a accesskey=\"h\" href=\"%s\"> UP </a> | <a accesskey=\"H\" href=\"%s\"> HOME </a> </div> <div> <a href=\"./index.xml\"> RSS </a> | <a href=\"https://github.com/casouri/casouri.github.io\"> Source </a> | <a href=\"https://creativecommons.org/licenses/by-sa/4.0/\"> License </a> </div> </div>"
# org-html-preamble-format: (("en" "<p class=\"Last Modified Time\">%T</p> <p class=\"date\">%d</p>"))
# end:

Things left to do

There a few things I would like to work on.

  • Found a way to export all the subtree with one command (similar to what ox-hugo does)
  • CSS for the site
  • Clojure/Hoplon incorporation with static pages