#+TITLE: Publishing my Website with Org #+AUTHOR: Howard X. Abrams #+DATE: 2020-12-22 #+FILETAGS: :emacs: A literate programming file for publishing my website using org. #+BEGIN_SRC emacs-lisp :exports none ;;; org-publishing.el --- Publishing my website using org. -*- lexical-binding: t; -*- ;; ;; Copyright (C) 2020 Howard X. Abrams ;; ;; Author: Howard X. Abrams ;; Maintainer: Howard X. Abrams ;; Created: December 22, 2020 ;; ;; This file is not part of GNU Emacs. ;; ;; *NB:* Do not edit this file. Instead, edit the original literate file at: ;; ~/other/hamacs/org-publishing.org ;; And tangle the file to recreate this one. ;; ;;; Code: #+END_SRC * Introduction While the Emacs community have a plethora of options for generating a static website from org-formatted files, I keep my pretty simple, and just use the standard =org-publish= feature. While the following packages come with Emacs, they aren't necessarily loaded: #+BEGIN_SRC emacs-lisp :results silent (require 'ox-rss) (require 'ox-publish) #+END_SRC Variable settings: #+BEGIN_SRC emacs-lisp (setq org-export-with-broken-links t org-mode-websrc-directory "/Volumes/Personal/dropbox/website" org-mode-publishing-directory (concat (getenv "HOME") "/website-public/")) #+END_SRC * The Projects I separate my /website/ into distinct projects separately built: - =blog-content= :: The bulk of rendering my =website= org files into HTML - =blog-static= :: All of the assets, like images are easily copied in place - =blog-rss= :: Regenerate the feeder files - =org-notes= :: Optionally render a non-web site collection of notes. #+BEGIN_SRC emacs-lisp (setq org-publish-project-alist `(("all" :components ("blog-content" "blog-static" "org-notes" "blog-rss")) ("blog-content" :base-directory ,org-mode-websrc-directory :base-extension "org" :publishing-directory ,org-mode-publishing-directory :recursive t :publishing-function org-html-publish-to-html :preparation-function org-mode-blog-prepare :export-with-tags nil :headline-levels 4 :auto-preamble t :auto-postamble nil :auto-sitemap t :sitemap-title "Howardisms" :section-numbers nil :table-of-contents nil :with-toc nil :with-author nil :with-creator nil :with-tags nil :with-smart-quotes t :html-doctype "html5" :html-html5-fancy t ;; :html-preamble org-mode-blog-preamble ;; :html-postamble org-mode-blog-postamble ;; :html-postamble "
" :html-head " \n" :html-head-extra " " :html-head-include-default-style nil) ("blog-static" :base-directory ,org-mode-websrc-directory :base-extension "css\\|js\\|png\\|jpg\\|gif\\|pdf\\|mp3\\|ogg\\|swf\\|svg" :publishing-directory ,org-mode-publishing-directory :recursive t :publishing-function org-publish-attachment) ("blog-rss" :base-directory ,org-mode-websrc-directory :base-extension "org" :rss-image-url "http://howardism.org/img/dragon-head.png" :publishing-directory ,org-mode-publishing-directory :publishing-function (org-rss-publish-to-rss) :html-link-home "http://www.howardism.org/" :html-link-use-abs-url t :with-toc nil :exclude ".*" :include ("index.org")) ("org-notes" :base-directory "~/technical/" :base-extension "org" :publishing-directory ,(concat org-mode-publishing-directory "/notes/") :recursive t :publishing-function org-html-publish-to-html :headline-levels 4 ; Just the default for this project. :auto-preamble t :auto-sitemap t ; Generate sitemap.org automagically... :makeindex t :section-numbers nil :style " " :table-of-contents nil :with-author nil :with-creator nil :with-tags nil) ("org-notes-static" :base-directory "~/technical/" :base-extension "css\\|js\\|png\\|jpg\\|gif\\|pdf\\|mp3\\|ogg\\|swf" :publishing-directory ,(concat org-mode-publishing-directory "/other/") :recursive t :publishing-function org-publish-attachment))) #+END_SRC * Including Sections In the project definitions, I reference a =pre-= and =postamble= that allow me to inject some standard HTML file headers and footers: #+BEGIN_SRC emacs-lisp (defun org-mode-blog-preamble (options) "The function that creates the preamble top section for the blog. OPTIONS contains the property list from the org-mode export." (message "Preamble options: %s" (princ options)) (let ((base-directory (plist-get options :base-directory))) (org-babel-with-temp-filebuffer (expand-file-name "top-bar.html" base-directory) (buffer-string)))) (defun org-mode-blog-postamble (options) "The function that creates the postamble, or bottom section for the blog. OPTIONS contains the property list from the org-mode export." (let ((base-directory (plist-get options :base-directory))) (org-babel-with-temp-filebuffer (expand-file-name "bottom.html" base-directory) (buffer-string)))) #+END_SRC Another helper function for the content of website is to make sure to update =index.org=, so that the RSS gets generated. #+BEGIN_SRC emacs-lisp (defun org-mode-blog-prepare (&optional options) "`index.org' should always be exported so touch the file before publishing." (let* ((base-directory (plist-get options :base-directory)) (buffer (find-file-noselect (expand-file-name "index.org" base-directory) t))) (with-current-buffer buffer (set-buffer-modified-p t) (save-buffer 0)) (kill-buffer buffer))) #+END_SRC * Keybindings Make it easy to publish all or just some of my website: #+BEGIN_SRC emacs-lisp (with-eval-after-load 'ha-org (ha-org-leader "p" '(:ignore t :which-key "publishing") "p a" '("all" . org-publish-all) "p p" '("project" . org-publish-project))) #+END_SRC And let's put a /leader key/ sequence for my favorite file on my website: #+BEGIN_SRC emacs-lisp (ha-leader "f h" '(:ignore t :which-key "howards") "f h i" '("website index" . (lambda () (find-file (expand-file-name "index.org" "~/website"))))) #+END_SRC * Technical Artifacts :noexport: Let's =provide= a name so we can =require= it: #+BEGIN_SRC emacs-lisp :exports none (provide 'ha-org-publishing) ;;; ha-org-publishing.el ends here #+END_SRC Before you can build this on a new system, make sure that you put the cursor over any of these properties, and hit: ~C-c C-c~ #+DESCRIPTION: A literate programming version for publishing my website using org. #+PROPERTY: header-args:sh :tangle no #+PROPERTY: header-args:emacs-lisp :tangle yes #+PROPERTY: header-args :results none :eval no-export :comments no mkdirp yes #+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil date:nil #+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil #+INFOJS_OPT: view:nil toc:nil ltoc:t mouse:underline buttons:0 path:http://orgmode.org/org-info.js