2021-11-12 04:59:22 +00:00
#+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
2022-03-09 18:45:37 +00:00
;;; org-publishing --- Publishing my website using org. -*- lexical-binding: t; -* -
;;
;; © 2020-2022 Howard X. Abrams
;; This work is licensed under a Creative Commons Attribution 4.0 International License.
;; See http://creativecommons.org/licenses/by/4.0/
;;
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams >
;; 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:
2021-11-12 04:59:22 +00:00
#+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 "<hr ><div id='comments' ></div >"
:html-head "<meta http-equiv=\"X-Clacks-Overhead\" content=\"GNU Terry Pratchett\" / >
<link href='http://fonts.googleapis.com/css?family=Source+Sans+Pro:400,700&subset=latin,latin-ext' rel='stylesheet' type='text/css' >
<link href='http://fonts.googleapis.com/css?family=Source+Serif+Pro:400,700&subset=latin,latin-ext' rel='stylesheet' type='text/css' >
<link href='http://fonts.googleapis.com/css?family=Source+Code+Pro:400,700' rel='stylesheet' type='text/css' >
<link rel=\"stylesheet\" href=\"/css/styles.css\" type=\"text/css\"/ >\n"
:html-head-extra "<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js\" ></script >
<script src=\"/js/magic.js\" ></script >
<link rel=\"icon\" href=\"/img/dragon.svg\" >
<link rel=\"shortcut icon\" href=\"/img/dragon-head.png\" >
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" / >"
: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 "<link rel=\"stylesheet\" href=\"../css/styles.css\" type=\"text/css\"/ > <script src=\"https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js\" type=\"text/javascript\" ></script > <link href=\"http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/themes/smoothness/jquery-ui.css\" type=\"text/css\" rel=\"stylesheet\" / > <script src=\"https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min.js\" type=\"text/javascript\" ></script > <script =\"text/javascript\" src=\"js/magic.js\" ></script >"
: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
2021-11-24 00:34:48 +00:00
(with-eval-after-load 'ha-org
(ha-org-leader
2021-11-12 04:59:22 +00:00
"p" '(:ignore t :which-key "publishing")
"p a" '("all" . org-publish-all)
2021-11-24 00:34:48 +00:00
"p p" '("project" . org-publish-project)))
2021-11-12 04:59:22 +00:00
#+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")
2021-11-24 00:34:48 +00:00
"f h i" '("website index" . (lambda ()
2021-11-12 04:59:22 +00:00
(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