Background
I've been telling myself to setup blogging in org mode for years, but I
was worried about getting it to work with my existing org publish
pipeline, but it turned out to actually be quite easy. Most of this has
been shamelessly stolen from this
post.
What it looks like
My directory structure looks something like this:
.
|-- archive.org
|-- build.sh
|-- hackathons.org
|-- index.org
|-- org.css
|-- posts
| |-- blogging-in-org-mode.org
| `-- test.org
|-- public
| |-- archive.html
| |-- hackathons.html
| |-- index.html
| |-- posts
| | |-- blogging-in-org-mode.html
| | |-- test.html
| | `-- test2.html
| |-- resume.html
| |-- settings.html
| `-- statics
| `-- cv-no-phone.pdf
|-- publish.el
|-- resume.org
|-- settings.org
`-- statics
`-- cv-no-phone.pdf
The posts directory contains files that I want org-publish to consider
blog posts.
How It Works
Styles
I use the awesome OrgCSS
stylesheet to style this site.
Automated Publishing
I use a simple bash script to automate publishing and pushing to my
webserver. I am aware that org-publish can automatically push to a web
server, but I chose to rsync for convince.
#!/bin/bash
emacs --batch --eval "(progn (package-initialize) (package-refresh-contents) (package-install 'org))"
emacs --batch --no-init-file --load publish.el --funcall org-publish-all
rsync -avh --stats public/ nmccarty@10.0.5.4:/var/www/html/
My publish.el
First, require some packages and configure some org mode settings
``` {.commonlisp org-language=”emacs-lisp”}
(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 ‘org-plus-contrib)
(package-install ‘htmlize)
(require ‘org)
(require ‘htmlize)
(require ‘ox-publish)
(require ‘ox-html)
(require ‘org-element)
(require ‘ox-rss)
(require ‘s)
(setq org-html-htmlize-output-type ‘css)
;; setting to nil, avoids “Author: x” at the bottom
(setq user-full-name “Nathan McCarty”)
(setq org-export-with-section-numbers nil
org-export-with-smart-quotes t
org-export-with-toc nil)
(setq org-html-divs ‘((preamble “header” “top”)
(content “main” “content”)
(postamble “footer” “postamble”))
org-html-container-element “section”
org-html-metadata-timestamp-format “%Y-%m-%d”
org-html-checkbox-type ‘html
org-html-html5-fancy t
org-html-validation-link nil
org-html-doctype “html5”)
Next set a (admittedly ugly) header for all the .org files, and pull in
the CSS
``` {.commonlisp org-language="emacs-lisp"}
(defvar org-blog-head
"<link rel=\"stylesheet\" type=\"text/css\" href=\"https://mccarty.io/org.css\"/>")
(defun org-blog-preamble (_plist)
"Pre-amble for whole blog."
"
<center>
<div class=\"banner\">
Nathan's Adventures in Programming
</div>
</center>
<center>
<ul class=\"banner-links\">
<a href=\"/\"> Home </a> </li>
   
<a href=\"/archive.html\"> Posts </a>
</ul>
</center>
<hr>")
Setup some functions for generating the sitemap. I chose to do this as a
simple org mode list of dates and links, because it makes pulling the
recent posts into the index easier later.
``` {.commonlisp org-language=”emacs-lisp”}
(defun org-blog-sitemap-format-entry (entry _style project)
“Return string for each ENTRY in PROJECT.”
(when (s-starts-with-p “posts/” entry)
(format “ + %s [[file:%s][%s]]”
(format-time-string “%h %d, %Y”
(org-publish-find-date entry project))
entry
(org-publish-find-title entry project))))
(defun org-blog-sitemap-function (title list)
“Return sitemap using TITLE and LIST returned by `org-blog-sitemap-format-entry’.”
(concat
“#+TITLE: Blog Posts \n”
(mapconcat (lambda (li)
(format “%s” (car li)))
(seq-filter #’car (cdr list))
“\n”)
“\n”))
Then set the list of attachment file types for the statics
``` {.commonlisp org-language="emacs-lisp"}
(defvar site-attachments
(regexp-opt '("jpg" "jpeg" "gif" "png" "svg"
"ico" "cur" "css" "js" "woff" "html" "pdf"))
"File types that are published as static files.")
Setup the org-publish-project-alist I have it set to only generate the
site map for org files in the posts directory, which corresponds to blog
posts, and it lives at archive.org/archive.html
``` {.commonlisp org-language=”emacs-lisp”}
(setq org-publish-project-alist
(list
(list “site-org”
:base-directory “.”
:base-extension “org”
:recursive t
:publishing-function ‘(org-html-publish-to-html)
:publishing-directory “./public”
:exclude (regexp-opt ‘(“README” “draft”))
:auto-sitemap t
:sitemap-filename “archive.org”
:sitemap-title “Blog Posts”
:sitemap-style ‘list
:html-head-extra org-blog-head
:html-preamble #’org-blog-preamble
:html-infojs-options “home:https://mccarty.io”
:sitemap-sort-files ‘anti-chronologically
:sitemap-format-entry #’org-blog-sitemap-format-entry
:sitemap-function #’org-blog-sitemap-function)
(list “site-static”
:base-directory “.”
:exclude “public/”
:base-extension site-attachments
:publishing-directory “./public”
:publishing-function ‘org-publish-attachment
:recursive t)
(list “site” :components ‘(“site-org”))))
(provide ‘publish)
## Pulling the most recent blog posts into index.org
I wanted to have the 10 or so most recent blog posts in a section in the
index file, and the rest in a separate archive.org. This turned out to
actually be quite easy to do. Org publish generates a full list of the
blog posts in archive.org, and since I used a simple list format, I can
just use an include statement in the index file to include only the top
so many lines:
``` org
* Recent Blog Posts
#+INCLUDE: "./archive.org" -16