Using org-publish

Table of Contents

Excerpt from config file

I use org-publish for my websites. This block has a lot going on:

  1. I set some default options for publishing projects.
  2. I use a custom function to generate postamble.
  3. Include my three sites in org-publish-project-alist.
(use-package ox-publish
  :defer t
  :config
  (use-package ox-jamzattack
    :demand
    :straight
    (ox-jamzattack :type git
                   :repo "git@jamzattack.xyz:ox-jamzattack.git"))
  <<my-org-html-postamble-format>>
  (defvar my-org-publish-default-options
    '(
      <<my-org-publish-default-options>>
      )
    "Default options for `org-publish-project-alist'.

This variable must be spliced into `org-publish-project-alist'
when set, i.e.
    (setq org-publish-project-alist
            `((\"project\"
               ,@my-org-publish-default-options)))")
  (setq
   org-html-postamble t ; needed to use custom format
   org-export-headline-levels 6
   org-html-postamble-format
   (my-org-html-postamble-format
    "Author: %A")
   org-publish-timestamp-directory "~/.cache/org/timestamps/"
   org-html-head "<link rel=\"stylesheet\" type=\"text/css\" href=\"/style.css\"/>"
   org-publish-project-alist
   `(("blog"
      ,@my-org-publish-default-options
      :base-directory "~/jamzattack.xyz/blog"
      :with-toc t
      :publishing-directory "~/jamzattack.xyz/out/blog"
      :html-postamble-format ,(my-org-html-postamble-format
                               "Author: %A"
                               "Date: %d (modified %M)"
                               "Top: <a href=\"/index.html\">The Yeet Log</a>")
      :sitemap-filename "index.org"
      :sitemap-title "The Yeet Log"
      :sitemap-format-entry
      (lambda (entry style project)
        (cond ((not (directory-name-p entry))
               (format "%s [[file:%s][%s]]"
                       (format-time-string
                        "%Y-%m-%d"
                        (org-publish-find-date entry project))
                       entry
                       (org-publish-find-title entry project)))
              ((eq style 'tree)
               ;; Return only last subdir.
               (file-name-nondirectory (directory-file-name entry)))
              (t entry)))
      :sitemap-sort-files anti-chronologically)
     ("music"
      ,@my-org-publish-default-options
      :base-directory "~/jamzattack.xyz/music"
      :recursive t
      :html-postamble-format ,(my-org-html-postamble-format
                               "Author: %A"
                               "Top: <a href=\"/sitemap.html\">All projects</a>")
      :publishing-directory "~/jamzattack.xyz/out/music"
      :sitemap-title "My Music Projects")
     ("html"
      ,@my-org-publish-default-options
      :base-directory "~/jamzattack.xyz/html"
      :publishing-directory "~/jamzattack.xyz/out/html"))))

Generate postamble

A little function to generate postamble.

(defun my-org-html-postamble-format (&rest args)
  "Generate an html postamble using ARGS.

This generates a paragraph for each item in ARGS.  For format
strings, see the docstring of `org-html-postamble-format'."
  (unless args
    (setq args '("Author: %a <%e>")))
  (list (list "en"
              (mapconcat (lambda (str)
                           (format "<p>%s</p>" str))
                         args
                         "\n"))))

Default export options

A list of default export options.

:auto-sitemap t
:publishing-function org-html-publish-to-html
:html-metadata-timestamp-format "%Y-%m-%d"
:with-toc nil
:with-email t
:with-drawers nil
:section-numbers nil
:with-todo-keywords nil

ox-jamzattack

I wrote the library ox-jamzattack in a vain attempt to make this section less dense, but it still has a lot going on.

In ox-jamzattack, I define a formatting function to replace org-html-format-spec. This allows me to extract the date that a file was last edited using git (as seen at the bottom of this page).

Publishing locally or via TRAMP?

I used to use TRAMP directories as the publishing directory for my website(s). This is actually really simple, and can just be done as though they were local directories:

(setq org-publish-project-alist
      '(("blog"
         :base-directory "~/jamzattack.xyz/blog"
         :publishing-directory "/ssh:jamzattack.xyz:/var/www/blog")
        ("music"
         :base-directory "~/jamzattack.xyz/music"
         :publishing-directory "/ssh:jamzattack.xyz:/var/www/music")))

This worked fine for a while, but I found it kind of awkward if I needed to make additional edits.

Now, I publish to a local directory and use rsync to send the files to my server:

(setq org-publish-project-alist
      '(("blog"
         :base-directory "~/jamzattack.xyz/blog"
         :publishing-directory "~/jamzattack.xyz/out/blog")
        ("music"
         :base-directory "~/jamzattack.xyz/music"
         :publishing-directory "~/jamzattack.xyz/out/music")))
rsync -rLv --exclude '*~' ~/jamzattack.xyz/out/* jamzattack.xyz:/var/www

This has a few benefits:

  1. I can check that everything works fine (links, images, etc.) before pushing to my server.
  2. I don't need to resort to any hackery to publish non-org files.
  3. I can use symlinks and have the server's directory mimic the local one. This is really useful for publishing my sheet music.
  4. I have offline access to all the exported html files.

Author: Jamie Beardslee

Date: 2020-06-20 (modified 2020-08-21)

Top: The Yeet Log