Blogging with Emacs and org-publish

Table of Contents

Why?

If you already use Emacs and org-mode, there are plenty of reasons to manage your website from within Emacs.

  • You already use org-mode to manage your information. Using it to manage your website is a natural extension to your workflow.
  • Org-mode syntax is arguably much easier to use and edit than markdown syntax.
  • You can easily publish other information you are managing in org-mode. If you publish your notes for example, you can view them across any device.
  • If you are considering this, I probably don't need to mention how much more productive you are in Emacs.
  • Like most things Emacs, it is infinitely customizable by writing some elisp (although this isn't a requirement to use it).

I'm going to assume that you already use org-mode. If you don't, you should look into it because it's one of Emacs' killer features.

How?

Org-mode comes with a great tool, org-publish, for publishing a project of interlinked org files as a website of interlinked html files. Although I'm only using it to publish a website, it is capable of much more. Using org-publish requires a bit of configuration, but it's pretty straight forward. It can be distilled to just a few steps:

  1. Specify the source directory of your project. This directory will contain the org files you want to publish.
  2. Specify the destination directory for your website. This directory will contain the exported html files created from the source org files.
    • You can specify the distination using TRAMP syntax to have these files automatically copied to remote locations via SSH, etc.
  3. Decide what publishing options you need for your project.

You will probably end up creating several projects. For example, I have one for my posts, one for static pages, and another for static assets like CSS and JavaScript. You can group all of these "sub projects" into a single "meta project" that can publish them all at once (this sounds confusing but is pretty simple as you will see).

Configuration

The majority of configuration is done using the variable org-publish-project-alist, which is an association list that maps projects to their publishing options. Here's a simple example taken from the documentation:

(setq org-publish-project-alist
  '(("org"
     :base-directory "~/org/"
     :publishing-directory "~/public_html"
     :section-numbers nil
     :with-toc nil
     :html-head "<link rel=\"stylesheet\"
                href=\"../other/mystyle.css\"
                type=\"text/css\"/>")))

This example configuration specifies the source directory, destination directory, and uses some publishing options to turn off the generation of table of contents and section numbers.

Tips

  • If you are setting the same option across all the projects you set up, set it as a variable so that it is picked up automatically by all your projects. For example, if you look at the publishing options, it says that the "html-head" option can be set by the "org-html-head" variable.
(setq org-html-head "<link rel=\"stylesheet\" type=\"text/css\" href=\"../assets/style.css\">")
  • Start with a very basic configuration, and customize it as you go.
  • Use the "auto-sitemap" option to generate a landing page listing all your posts for a given project. You may decide that the default function that generates the sitemap, "org-publish-org-sitemap", doesn't do exactly what you want. In that case, you can specify another function that your write yourself. Start by looking up the source code for "org-publish-org-sitemap", use it as a start point, and edit it for your needs.

Conclusion

This should hopefully give you a good starting point. Below is my configuration in case it is helpful. The last line contains an example of a meta-project containing multiple sub-projects. Now all I have to do to publish my entire website is run "M-x org-publish <ret> website"

(setq org-html-postamble-format '(("en" "<p class=\"author\">Author: %a</p><p class=\"date\">Last Modified: %C</p>")))
(setq org-html-head-include-default-style nil)
(setq org-html-head "<link rel=\"stylesheet\" type=\"text/css\" href=\"../assets/style.css\">")
(setq org-publish-project-alist
      '(("assets"
         :base-directory "~/org/website/assets"
         :base-extension "css\\|js\\|png\\|jpg\\|gif\\|pdf\\|mp3\\|ogg\\|swf"
         :publishing-directory "~/www/assets"
         :recursive t
         :publishing-function org-publish-attachment)
        ("static-pages"
         :base-directory "~/org/website"
         :base-extention "org"
         :section-numbers nil
         :with-toc nil
         :html-postamble t
         :publishing-directory "~/www"
         :publishing-function org-html-publish-to-html)
        ("posts"
         :base-directory "~/org/website/posts"
         :base-extention "org"
         :publishing-directory "~/www/posts"
         :publishing-function org-html-publish-to-html
         :section-numbers nil
         :auto-sitemap t
         :html-postamble t
         :sitemap-title "Latest Posts"
         :sitemap-function my-org-publish-org-sitemap
         :sitemap-filename "index.org"
         :sitemap-date-format "%b %d '%y")
        ("website"
         :components ("assets" "static-pages" "posts"))))

Author: Caleb Gossler

Last Modified: 2016-04-16 Sat 00:29