Custom org-sitemap-function
post-Org 9.1
Published: December 27, 2022
I have been lugging around an old version of org-mode (9.0 to be specific) in the git repo which builds this website for a number of years now. I decided to do this because I had a custom org-sitemap-function
to generate the landing page for my blog, but org 9.1 introduced a breaking change to the org-publish API.
I have now finally come around to fixing this issue and making my website compatible with modern emacs and org-mode versions higher than 9.1. However, porting my old sitemap function was… surprisingly difficult? So just in case someone is looking up my original post these days, this post contains a sitemap-function
which will work in 2022.
In the pre-9.1 version, the org-sitemap-function
would get the project-plist
as argument. Post-9.1, the org manual states:
:sitemap-function
Plug-in function to use for generation of the sitemap. It is called with two arguments: the title of the site-map and a representation of the files and directories involved in the project as a nested list, which can further be transformed using org-list-to-generic, org-list-to-subtree and alike. Default value generates a plain list of links to all files in the project.
This makes it a little more difficult to produce the sitemap page that we want, but I was able to get it done by parsing each element of the list and extracting the path to the filename with the following function:
(defun my-blog-parse-sitemap-list (l) "Convert the sitemap list in to a list of filenames." (mapcar #'(lambda (i) (let ((link (with-temp-buffer (let ((org-inhibit-startup nil)) (insert (car i)) (org-mode) (goto-char (point-min)) (org-element-link-parser))))) (when link (plist-get (cadr link) :path)))) (cdr l)))
Finally, the new and improved sitemap function looks like this:
(defun my-blog-sort-article-list (l p) "sort the article list anti-chronologically." (sort l #'(lambda (a b) (let ((d-a (org-publish-find-date a p)) (d-b (org-publish-find-date b p))) (not (time-less-p d-a d-b)))))) (defun my-blog-sitemap (title list) "Generate the landing page for my blog." (with-temp-buffer ;; mangle the parsed list given to us into a plain lisp list of files (let* ((filenames (my-blog-parse-sitemap-list list)) (project-plist (assoc "blog-articles" org-publish-project-alist)) (articles (my-blog-sort-article-list filenames project-plist))) (dolist (file filenames) (let* ((abspath (file-name-concat my-website-blog-dir file)) (relpath (file-relative-name abspath my-website-base-dir)) (title (org-publish-find-title file project-plist)) (date (format-time-string (car org-time-stamp-formats) (org-publish-find-date file project-plist))) (preview (my-blog-get-preview abspath))) ;; insert a horizontal line before every post, kill the first one ;; before saving (insert "-----\n") (insert (concat "* [[file:" relpath "][" title "]]\n")) ;; add properties for `ox-rss.el' here (let ((rss-permalink (concat (file-name-sans-extension relpath) ".html")) (rss-pubdate date)) (org-set-property "RSS_PERMALINK" rss-permalink) (org-set-property "PUBDATE" rss-pubdate)) ;; insert the date, preview, & read more link (insert (concat "Published: " date "\n\n")) (insert preview) (insert "\n") (insert (concat "[[file:" relpath "][Read More...]]\n")))) ;; kill the first hrule to make this look OK (goto-char (point-min)) (let ((kill-whole-line t)) (kill-line)) ;; insert a title and save (insert "#+OPTIONS: title:nil\n") (insert "#+TITLE: Blog - Dennis Ogbe's Personal Website\n") (insert "#+AUTHOR: Dennis Ogbe\n") (insert "#+EMAIL: [email protected]\n") (buffer-string))))
This info can be combined with the instructions in my original post to cook up your own very special org-mode website.
Update emacs --batch
, i.e., something like:
emacs --batch -l "./project.el" --eval="(org-publish \"blog\" t)"
As part of the build process, I use CSSTidy to minify my CSS and bibtex2html to generate the list of publications.
;; [2024-12-30 Mon] ;; ;; I used to host the current version of the build script here. That made this ;; post rather large and hard to parse. Please find a more recent annotated ;; version of my build script here: https://ogbe.net//blog/emacs_org_static_site ;; ;; Also see the update note at the bottom of this post.
Update here for an explanation):
: I changed a few minor things, including that I now finally add the publish date into the actual published blog post. Also, thanks to a hint by G.M., who provided a fix for my old structure-template definition, I now have an updated structure template to generate the header for a blog post (see(require 'org-tempo) (tempo-define-template "blog-header" ; just some name for the template '("#+title: ?" n "#+AUTHOR: Dennis Ogbe" n "#+EMAIL: [email protected]" n "#+DATE:" n "#+STARTUP: showall" n "#+STARTUP: inlineimages" n "#+BEGIN_PREVIEW" n p n "#+END_PREVIEW") "<b" "Insert blog header" ; documentation 'org-tempo-tags)
Update here.
: After some updates to my generator, I now have a writeup with commentary