Developing ox-jekyll

In a previous post, I surveyed existing org and jekyll integration workflows. This survey found two common approaches, one that is Jekyll-centric and one that uses Org-publish (Emacs-centric). Unfortunately, neither fit with my workflow and I decided to develop my own Org exporter.

I finally have some functioning code, so I figured I should share details about the project and the development process. You can find the project on GitHub.

Starting Point

In my survey I found some useful resources:

Great artists steal.

I want everything that org-octopress is doing with it’s jekyll exporter, I just want it built on markdown instead of HTML.

So, I’ve copied ox-jekyll.el and replaced “html” with “md”. After fixing a few function names, it works!

Most importantly, the front matter is in the right spot (with and without a table of contents). The next step is to make this work with the particulars of my publishing workflow.

My Publishing Workflow Details

There are a number of things I want my exporter to accomplish. Many of which are particular to my workflow.

  • I use a single org file per post.
  • Upon export, the date (YYYY-MM-DD) should get added to the file name.
  • Subtree level matches export heading level (this is just how I design my site’s CSS)
  • Code snippets should be easy to export with appropriate syntax. This is where many markdown converters differ, but jekyll currently wraps code blocks with { % highlight LANG %} / { % endhighlight %}. [Ignore the extra space before the %]
  • Jekyll front matter should be added above org-inserted table of contents. The manual HTML source block is just hideous.
  • It should be easy to move the generated file to a separate location (I think this addressed in the org-publish workflow).
  • Org-y way to add tags to the post.
  • Safe export of title (colon character mucks things up for Jekyll).
  • Fix up links and export connected images. This one is really a nice to have, not necessary.
  • TOC should be an ordered list (with the option to make it unordered) WTF is the HTML exporter doing making it an unordered list with numbers in the text.

Many of these are solved with code from org-octopress, particularly the yaml front matter.

Implementing Features

Here are some notes on my implementation.

Thinking about the Table of Contents

I had been including a table of contents at the top of each of my posts. I didn’t actually label it with “table of contents” and I prefer an un-numbered list. This seems to be very contrary to what the org-exporter likes to do. It pretty much does not allow for any fine-grained control of how the table of contents appears.

While I was able to get the code to do what I wanted, it ended up being way too much of a hack. In the end, I’ve decided that I don’t want a table of contents at all. Really, it will be up to the markdown / jekyll / liquid parser to create a TOC if necessary. This makes it easy to apply separate HTML styles to the TOC (to put it in a sidebar or something).

Preserving the Headline Level

I would like :headline-offset (as described here) to work on a file level. This allows me to make sure the contents of my post match up the CSS on the web site (the content’s final destination). This is definitely a more markdown-y way to do things rather than the org way.

Unfortunately, the :headline-offset option is only supported per subtree. I can hack it with a simple function that adds an “offset by 0” property to each subtree:

(defun org-jekyll-headline-offset (headline contents info)
  "proper headline offset"
  (let* ((info (plist-put info :headline-offset 0)))
    (org-md-headline headline contents info)))

I add it to the derived backend :translate-alist like so:

(org-export-define-derived-backend 'jekyll 'md
  ;; ...
  :translate-alist
  '((headline . org-jekyll-headline-offset)
  ;; ...

Now, this function is called each time a headline is translated by the export engine and my headline level is directly translated to markdown.

Setting the Date

I have a strange workflow where I want the #+DATE: tag to be the day I started working on a post and the date in the filename to be the day I hit publish. For my exporter, I can use the option date: to trigger this behavior. The date: option takes precedence over the variable org-export-with-date.

While I would like my code to support putting the #+DATE: property into the filename, this seems impossible with the export engine. The date property is stored in the info plist which I don’t have access to at file naming time.

Instead, I’ve implemented this functionality:

  • The date: option controls if the value of the #+DATE property is put into the Jekyll front matter.
  • I’ve added a new option to the exporter: org-jekyll-use-today-date. If t, the exporter will prepend the filename with today’s date.

Results

I’m quite happy with my exporter, I even used it to export this post! I still need to figure out how to use the org-publish workflow, but for now I can successfully export my blog posts.

As with most of my projects, you can find it on GitHub. Please feel free to file an issue and share any feed back you have.