UP | HOME

Blogs with org-publish
searchforzero

Table of Contents

Let's say you're writing a blog post in org-mode, so far it looks like this:

#+TITLE: Interesting Things Inside
Hello friends, I'm writing an interesting blog!

How would you like to generate your site's HTML from your org files, commit your changes, push them, and have your site automatically deployed with just a few key combinations? Using org-publish, and the default Doom Emacs bindings, we can accomplish all that with SPC m P P, SPC g c c, y, p p. This will run org-publish-current-project, magit-commit-create (prompting to stage all changes if none are yet staged), accept the prompt, confirm the commit (after entering your message of course), and run magit-push. Then, if using something like GitLab and its GitLab Pages feature for hosting static websites, your most recent commit will be deployed automatically. If that sounds appealing, read on!

I used to use Hugo (with ox-hugo) + GitLab Pages to publish my site, so the underlying org files for my site remain unchanged. However the speed and simplicity of the org-publish workflow was too attractive to pass up, even compared to a static site generator like Hugo. Here I'll show you how to set up org-publish with real-world examples I use for this site.

Configure org-publish

It would be a waste of my and your time to restate the entire documentation on org-publish, so instead I'll link an official tutorial to get you started and show you what my config looks like:

(setq org-publish-project-alist
      '(("sfz-source"
         :auto-sitemap t
         :sitemap-title ""
         :base-directory "~/projects/searchforzero/src/"
         :base-extension "org"
         :publishing-directory "~/projects/searchforzero/public/"
         :recursive t
         :publishing-function org-html-publish-to-html
         :headline-levels 4
         :auto-preamble t)
        ("sfz-static"
         :base-directory "~/projects/searchforzero/src/"
         :base-extension "css\\|js\\|png\\|jpg\\|gif\\|pdf\\|mp3\\|ogg\\|swf\\|svg"
         :publishing-directory "~/projects/searchforzero/public/"
         :recursive t
         :publishing-function org-publish-attachment)
        ("sfz" :components ("sfz-source" "sfz-static"))))

With this I'm able to run the org-publish functions. What I normally do is run org-publish-current-project while I'm working on a file as mentioned in the opening paragraph, but you could just as easily run org-publish and interactively choose what project to publish. If I chose to publish the "sfz" project, it would publish its components: "sfz-source" and "sfz-static". Publishing is simply copying the matching files in base-directory to the publishing-directory and executing some transformations like converting org file to HTML (depending on the :publishing-function). So by publishing I get a nice public directory that's ready to go online, neat!

Custom HTML Exporting

org-publish leverages org's normal XHTML exporting capabilities, so you can change the way your org source gets doctored up into HTML in the normal org-export ways. You'll notice since we're just copying files, we can make CSS files and have them published too. That part is simple, just put them somewhere in your src directory, in my case src/css, and "sfz-static" will catch all the CSS files. Now we can make our exported HTML use particular CSS files by adding an #+HTML_HEAD line to the org file like so

#+HTML_HEAD: "<link rel=\"stylesheet\" type=\"text/css\" href=\"css/stylesheet.css\" />"

But adding this and other export settings to each file gets tiring, so I prefer to create setup files for each directory depth or for groups of pages that should share settings. Here's what the setup file for all my blog posts looks like:

#+SUBTITLE: searchforzero
#+OPTIONS: num:nil
#+PROPERTY: header-args :exports both :results verbatim
#+HTML_LINK_HOME: ../index.html
#+HTML_LINK_UP: ./index.html

# CSS
#+HTML_HEAD: <link rel="stylesheet" type="text/css" href="../css/stylesheet.css"/>

# Fonts
#+HTML_HEAD: <link rel="stylesheet" media="screen" href="https://fontlibrary.org//face/superia" type="text/css"/>

# Favicon
#+HTML_HEAD: <link rel="shortcut icon" type="image/svg" href="../img/sfz.svg"/>

This file lives in the setupfiles directory at my project's root. It can be anywhere you like, but where you put it will change the relative path specified in the #+SETUPFILE line. Here's the line each of my blog files need to include all the settings shown above:

#+SETUPFILE: ../../setupfiles/blog.org

Created: 2022-07-20 Wed 18:30

Validate