Publishing Org-files to HTML

How to publish with Org Mode

This post summarizes my Org to HTML Publish setup.

DONE Package Initialization

In order to publish Org-files to HTML I have to load the org package. In addition I also download htmlize which can be used to display the org-files’ source text do be displayed in the browser, org-contrib which contains handy add-ons to Org-mode and ox-reveal an Org-mode exporter backend to Reveal.js to create good-looking HTML presentations.

;; publish.el --- Publish org-mode project on Gitlab Pages
;; Author: pekaha

;;; Commentary:
;; This script will convert the org-mode files in this directory into
;; html.

;;; Code:

(require 'package)
(package-initialize)
(add-to-list 'package-archives '("org" . "https://orgmode.org/elpa/") t)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
(package-refresh-contents)
(package-install 'htmlize)
(package-install 'org-plus-contrib)
(package-install 'ox-reveal)

(require 'org)
(require 'ox-publish)
(require 'ox-reveal)

TODO Default Export Options [1/2]

There are multiple methods to set export setting as stated in the Org Manual:

Export options can be set: globally with variables; for an individual file by making variables buffer-local with in-buffer settings (see *note In-buffer Settings); by setting individual keywords or specifying them in compact form with the OPTIONS keyword; or for a tree by setting properties (see *note Properties and Columns). Options set at a specific level override options set at a more general level.

I set some global options as “sane defaults” and manage the rest on a per file basis.

DONE Global Export Options (not specific to HTML)

I first set my user name for the case that I want to display it in some post and the my default export-language.

(setq user-full-name "pekaha"
      org-export-default-language "en")

I keep most of the default settings. In order to remove unnecessary clutter from the exported files I remove section numbers, the table of contents and all TODO-related marks like the statistics cookies etc.

(setq org-export-with-smart-quotes t ; defaults to nil
      org-export-with-author nil ; defaults to t
      org-export-with-broken-links 'mark ; defaults to nil
      org-export-headline-levels 5 ; defaults to 3
      org-export-with-section-numbers nil ; defaults to t
      org-export-with-statistics-cookies nil ; defaults to t
      org-export-with-tags 'not-in-toc ; defaults to t
      org-export-with-toc nil ; defaults to t
      org-export-with-todo-keywords nil) ; defaults to t

TODO HTML Export Options

TODO Default HTML Export Options

(defvar pekaha/default-html-head "
<link rel=\"stylesheet\" type=\"text/css\" href=\"css/base.css\" />
")

(defvar pekaha/default-html-head-extra "
<meta html-head-extra=\"default-head-extra-value\">
")

(setq org-html-link-home "index.html#home"
      org-html-link-up "index.html#up"
      org-html-head pekaha/default-html-head
      org-html-head-extra pekaha/default-html-head-extra
      org-html-validation-link nil
      org-html-preamble t
      org-html-postamble 'auto)

Set export options for HTML5.

(setq org-html-doctype "html5"
      org-html-html5-fancy t
      org-html-container-element "section")

 (setq org-html-divs '((preamble "header" "preamble")
                       (content "main" "content")
                       (postamble "footer" "postamble")))

TODO Custom Navigation Bar

We can replace the default HOME and UP links by a custom navigation bar simply by replacing the HTML snippet defined by org-html-home/up-format.

(setq org-html-home/up-format "
<nav id=\"org-div-home-and-up\">
  <div id=\"navbar\">
    <div id=\"navbar-logo\">
      <a id=\"org-link-home\" accesskey=\"h\" href=\"%2$s\">
        <img src=\"images/pekaha.svg\" alt=\"pekaha logo\"/>
      </a>
    </div>
    <div class=\"navbar-item\"><a id=\"org-link-up\" accesskey=\"h\" href=\"%1$s\">Blog</a></div>
    <div class=\"navbar-item\"><a id=\"org-link-about\" accesskey=\"a\" href=\"about.html\">About</a></div>
  </div>
</nav>
")

TODO HTML Export Options for Blog Posts

(defvar pekaha/blog-html-head "
<link rel=\"stylesheet\" type=\"text/css\" href=\"css/base.css\" />
<link rel=\"stylesheet\" type=\"text/css\" href=\"css/syntax-coloring.css\" />
")

(defvar pekaha/blog-html-head-extra "
<meta html-head-extra=\"post-head-extra-value\">
")

(defun pekaha/blog-html-preamble (plist)
  "PLIST: An entry."
  (let ((date (org-export-get-date plist)))
  (if date
      (format "<p class=\"datetitle\">%s</p>" (org-export-data date plist)))))

TODO Publish Pages with org-publish-project-alist

(defvar image-extensions
  (regexp-opt '("jpg" "jpeg" "gif" "png" "svg" "ico"))
  "File types that are published as image files.")

(defvar asset-extensions
  (regexp-opt '("cur" "js" "woff" "woff2" "html" "pdf"))
  "File types that are published as static files (beside images and stylesheets).")

(setq org-publish-project-alist
      `(("posts"
         :base-directory "posts"
         :base-extension "org"
         :recursive t
         :publishing-function org-html-publish-to-html
         :publishing-directory "./public"
         :exclude ,(regexp-opt '("README" "draft"))
         :with-todo-keywords nil
         :with-date t
         :with-toc 2
         :auto-sitemap t
         :sitemap-filename "index.org"
         :sitemap-title "Sitemap"
         :sitemap-file-entry-format "%d *%t*"
         :sitemap-style list
         :sitemap-sort-files anti-chronologically
         :html-head-include-default-style nil
         :html-preamble pekaha/blog-html-preamble
         :html-head ,pekaha/blog-html-head
         :html-head-extra ,pekaha/blog-html-head-extra)
        ("css"
         :base-directory "css"
         :base-extension "css"
         :publishing-directory "./public/css"
         :publishing-function org-publish-attachment
         :recursive t)
        ("images"
         :base-directory "images"
         :base-extension ,image-extensions
         :publishing-directory "./public/images"
         :publishing-function org-publish-attachment
         :recursive t)
        ("assets"
         :base-directory "assets"
         :base-extension ,asset-extensions
         :publishing-directory "./public/assets"
         :publishing-function org-publish-attachment
         :recursive t)
        ("all" :components ("posts" "css" "images" "assets"))))

TODO Header and Footer

TODO CSS Styling

Disable default CSS

#+OPTIONS: html-style:nil

Add custom CSS styles on a per file basis

#+HTML_HEAD: <link rel="stylesheet" type="text/css" href="/note/style.css"/>
#+HTML_HEAD_EXTRA: <script type="text/javascript" src="/note/script.js"></script>

Use separate css file for formatting code snippets

(setq org-html-htmlize-output-type 'css)

TODO Style remaining elements

  1. [ ] Images
  2. [ ] Header/Footer
  3. [ ] Lists
  4. [ ] Footnotes

TODO Custom 404 and 403 error pages

TODO Index

TODO Sitemap with Blog-Previews

TODO Setup org-info

To use the org-info script, just add this line to the Org file:

#+INFOJS_OPT: view:info toc:nil

TODO Use local copy of the script and customize options in org-html-infojs-options

;; (setq org-html-use-infojs)
;; (setq org-html-infojs-options)

TODO Setup org-reveal

See Also