Yi Tang Data Science and Emacs

Jekyll in Emacs - Align URL with Headline

Table of Contents

  1. Problem
  2. Solution
  3. Implementation

Problem

While I was working on improving the URL in my last post, I noticed the URLs are not readable, for example,

http://yitang.uk/2023/12/18/jekyll-in-emacs-update-blog-post-title-and-date/#org0238b9f

The URL links to the section called Code, so a much better URL should be

http://yitang.uk/2023/12/18/jekyll-in-emacs-update-blog-post-title-and-date/#Code

My notes show I have had this issue since 9 months ago. I made another attempt, but still could not find a solution!

Solution

I then switched to tidy up my Emacs configuration, and the variable org-html-prefer-user-labels caught my eye.

its documentation says

By default, Org generates its own internal ID values during HTML
export.

When non-nil use user-defined names and ID over internal ones.

So “#org0238b9f” is generated by org-mode. They are randomly generated; they change if I update the export file. It means every time I update a blog post, it breaks the URLs. This was a problem I wasn’t aware of.

Anyway, what’s important is that, in the end, it says

Independently of this variable, however, CUSTOM_ID are always
used as a reference.

That’s it, I just need to set CUSTOM_ID. That’s the solution to my problem. It is hidden in the documentation of some variables…

Implementation

So I need a function to loop through each node, and set the CUSTOM_ID property to its headline. The org-mode API provides three helpful functions for working with org files:

  • org-entry-get: to get a textual property of a node. the headline title is referenced as “ITEM”,
  • org-entry-put: to set a property of a node,
  • org-map-entries: to apply a function to each node.

I changed the final function a bit so it is used as an export hook (org-export-before-processing-functions) as an experiment. With this setup, it runs automatically whenever I export a blog post in org-mode to Markdown. Also, it works on the exported file so it leaves the original org file unchanged.

The code is listed below. It can also be found at my .emacs.d git repo which includes many other useful Emacs configurations for Jekyll.

 
 (defun yt/jekyll--create-or-update-custom_id-field ()
  "so that the CUSTOM_ID property is the same as the headline and 
the URL reflects the headline.

by default, the URL to a section will be a random number."
  (org-entry-put nil "CUSTOM_ID" (org-entry-get nil "ITEM"))
  )

(defun yt/jekyll--create-or-update-custom_id-field-buffer (backend)
  (when (eq backend 'jekyll-md)
    (org-map-entries 'yt/jekyll--create-or-update-custom_id-field)
    ))

(add-hook 'org-export-before-processing-functions 'yt/jekyll--create-or-update-custom_id-field-buffer)
 
If you have any questions or comments, please post them below. If you liked this post, you can share it with your followers or follow me on Twitter!
comments powered by Disqus