Collecting my attempts to improve at tech, art, and life

Blog Writing in Org Mode

Tags: emacs orgmode jekyll tools

Introduction

Much of what I’ve read about Org has focused on its utility as a task management tool. That’s great. I wouldn’t mind spending some time on that aspect. Mostly I’ve been focused on its usefulness for note-taking and writing.

Org mode includes features which make it attractive for blogging and journaling. It has a relatively simple set of markup rules for common constructs such as paragraphs, lists, source code, and tables. The mode itself provides an editing interface which simplifies creating and managing those constructs. Most importantly for the blogger, org files can be exported to a range of formats including Markdown and HTML.

Why not use that functionality for my own site? Random Geekery is built with Jekyll, and there are already instructions available for using the two together. I can use those as a starting point.

Organize Directories

When I’m using Org mode to write the blog pages, Jekyll becomes an implementation detail specific to publishing the blog. One folder contains all of the Jekyll project files, and an org folder mirrors the content-specific structure of the jekyll tree.

+jekyll
+- css
+- _data
+- _drafts
+- img
+- _includes
+- _layouts
+- pages
+- _plugins
+- _posts
+- _sass
+- _scripts
+- _site
+org
    +- _drafts
    +- _posts
    +- pages

I use _drafts because I don’t always know when I will be publishing a post, and pages because I have legacy content that will get rewritten in Org format as it gets updated.

Front Matter

The front matter used by Jekyll and other engines to determine content metadata requires some special handling to get exported correctly by Org mode. The most straightforward thing is to use the suggestion from the instructions mentioned earlier. Put your front matter in a HTML block right at the top of the file.

#+BEGIN_HTML
---
title: Blog Writing in Org Mode
layout: post
category: Emacs
tags: org jekyll
---
#+END_HTML

Okay, it’s not HTML. But Org mode doesn’t really care. It will get passed through untouched when you export.

Configure HTML Export

HTML and other output needs to be placed correctly within the Jekyll layout conventions. A proper org-publish-project-alist will take care of this.

(setq org-publish-project-alist
      '(
        ("org-randomgeekery"
         ;; Location of org files
         :base-directory "~/Projects/randomgeekery.org/org/"
         :base-extension "org"

         ;; Location of Jekyll files
         :publishing-directory "~/Projects/randomgeekery.org/jekyll/"
         :recursive t
         :publishing-function org-publish-org-to-html
         :headline-levels 4
         :html-extension "html"

         ;; Only export section between <body></body>
         :body-only t)

        ("org-static-randomgeekery"
         :base-directory "~/Projects/randomgeekery.org/org/"
         :base-extension "css\\|js\\|png\\|jpg\\|gif\\|pdf\\|mp3\\|ogg"
         :publishing-directory "~/Projects/randomgeekery.org/"
         :recursive t
         :publishing-function org-publish-attachment)

        ("rg" :components ("org-randomgeekery" "org-static-randomgeekery"))
        ))

Now when I export the project with org-mode-export (C-c C-e X) rg, all of my org content for the project gets put in the correct spot. I even get a table of contents, which is not such a bad thing.

Publishing A Post

So when you’ve been editing a draft long enough and you’re ready to make it a real live post, you need to move the file from _drafts to _posts, with the publish date prefixing the filename.

I could do that manually, but it’s tedious to do that for every blog post.

I experiment with my rudimentary Emacs Lisp skills to create a new filename that looks about right.

(defun post-it ()
  "Write current draft file as a Jekyll post file"
  (interactive)
  (if
      (string-match "_drafts" buffer-file-name)
      (let ((draft-copy buffer-file-name)
            (post-copy
             ;; _drafts/<stub>.org
             ;; becomes
             ;; _posts/yyyy-mm-dd-<stub>.org
             (concat
              (replace-regexp-in-string "_drafts" "_posts"
                                        (file-name-directory buffer-file-name))
              (format-time-string "%Y-%m-%d")
              "-"
              (file-name-nondirectory buffer-file-name)
              )
             ))
        (write-file post-copy)
        )
    (message "%s is not in _drafts!" (file-name-nondirectory buffer-file-name))
      )
  )

Awkward, but it works. It worked at least once, anyways. Should manually remove the original _draft file until I know what I’m doing a little more.

WARNING

See that Lisp I wrote? It’s probably wrong in some horrible way. It’s the most complex Elisp I’ve ever managed. Look at it for interesting ideas, but please don’t just copy and paste.

Followup

I wonder if maybe this isn’t the best approach, since it seems to confuse the heck out of Org mode. My lone org file just would not republish until I found this post for a similar situation. If it’s just not rebuilding, force it with a numeric argument: C-u 0 C-c e.

This works well enough to get one post published, anyways. I’m sure to revisit this topic as I continue to learn more about Org mode and Emacs.


Added to vault 2024-01-15. Updated on 2024-02-01