Org Static Blog: A Simple Static Site Generator
I picked up most of my computer skills from reading posts online, and
it got me thinking about having my own blog where I can share what
I've learned. But I've always been a bit hesitant about learning all
the complicated stuff in web development. Recently, I came across a
third-party emacs package called org-static-blog
while searching for
the built-in functionality org-publish
. After browsing a few blog
sites created with this package, I was impressed by its simplicity and
the ability to blog using org files. It became clear that this package
is exactly what I need at this stage.
After a few minites of survey, I observed the following facts.
- The source code is simple enough. There is only a single elisp script with less than 1000 lines. The code is well-organized, with customization variables appearing first, followed by commands. It doesn't involve any complex or cryptic syntax.
- The developer maintains this project over 8 years and he continues to use it in his blog site.
- There are a few appealing blog sites are created by org static blog, e.g., Bastian, Jose Antonio Ortega Ruiz, Justin Abrahms, Musa Al-hassy…
Finally, I decide to give it a try. I hope it can give me a way to share my thoughts on the internet.
Go through the manual
The README contains a brief introduction to the usage and a minimal working example.
First, let us review the introduction.
Static blog generators are a dime a dozen. This is one more, which focuses on being simple. All files are simple org-mode files in a directory. The only requirement is that every org file must have a
#+TITLE
and a#+DATE
, and optionally,#+FILETAGS
,#+DESCRIPTION
and#+IMAGE
.
After collecting the appropriate org files, publishing them by org
static blog needs only two steps: 1) customizing org static blog
parameters; 2) calling org-static-blog-publish
to publish all posts,
or calling org-static-blog-publish-filename
to publish only a
particular post.
The blog site generated by org static blog consists of six parts.
- Posts. Every org file in
org-static-blog-posts-directory
is one blog post. Each blog post is rendered as its own HTML page. - Index. The index page contains the last few blog posts on a single page.
The number of entries on the index page can be customized
using
org-static-blog-index-length
. - Tags. Each blog post can be tagged, and each tag links to a page
that lists all other posts of the same tag. This feature is only
enabled when
org-static-blog-enable-tags
ist
. - Archives. This page lists the publishing dates and headlines of every blog post.
- RSS Feeds. This is a machine-readable XML file that contains every blog post. It is not meant to be consumed by humans. Instead RSS readers can use the RSS feed to aggregate entries from multiple blogs.
- Drafts. They are rendered like regular blog posts, but are not included in the index, the archive, or the RSS feed.
Every HTML page in org static blog can be customized in the following aspects.
org-static-blog-page-header
. This is inserted into the<head>
of every page. Use this to include custom CSS and JavaScript for your blog.org-static-blog-page-preamble
. This is inserted just before the content of every page. This is a good place to put the header or menus for your blog.org-static-blog-page-postamble
. This is inserted after the content of every generated page: after any blog post page, after the index page, the tag pages and the archive. This is where you can include copyright notices.org-static-blog-post-preamble
andorg-static-blog-post-postamble
. The returned values are prepended and appended to every blog post. If you want to change the formatting of dates, titles, or the tag list, overwrite these functions. In particular the content oforg-static-blog-post-comments
is inserted at the end of each blog post. Use this to add a comment box.
Other features:
- Optionally show a preview of the post (instead of the full post) on
the index page setting
org-static-blog-use-preview
tot
. The region of the post used as a preview is, by default, its first paragraph, but can be fine-tuned usingorg-static-blog-preview-start
andorg-static-blog-preview-end
. Activate a few convenience key bindings by
(add-to-list 'auto-mode-alist (cons (concat org-static-blog-posts-directory ".*\\.org\\'") 'org-static-blog-mode))
These key bindings are:
C-c C-f
/C-c C-b
to open next/previous post.C-c C-p
to open the matching published HTML file of a post.C-c C-n
to create a new blog post.
Minimal Configuration
Following the example in its manual, I try to build a blog site at
./org-blog/
with a folder ./org-blog/org/
containing several org
files.
The first step is, of course, installing the package.
(package-install 'org-static-blog)
The next step is setting up variables. I want to do the following things.
- Set the site title to Hello, Org Static Blog
- Set the url of the site to
file:///home/dou/Documents/2024-01-22-TryOrgStaticBlog/org-blog/
- Set the directory that holds all html files to
./org-blog/
- Set the directory that holds all org files to be published to
./org-blog/org/
- Set the directory that holds all drafts to
./org-blog/drafts/
- Set the page header as the content of the file
./org-blog/static/header.html
- Set the page preamble as the content of the file
./org-blog/static/preamble.html
- Set the page postamble as the content of the file
./org-blog/static/postamble.html
- Enable tags
- Enable preview
(require 'org-static-blog) (setq dms/org-static-blog-root-dir "/home/dou/Documents/2024-01-22-TryOrgStaticBlog/org-blog/") (setq org-static-blog-publish-title "Hello, Org Static Blog") (setq org-static-blog-publish-url (format "file://%s" dms/org-static-blog-root-dir)) (setq org-static-blog-publish-directory (format "%s" dms/org-static-blog-root-dir)) (setq org-static-blog-posts-directory (format "%sorg" dms/org-static-blog-root-dir)) (setq org-static-blog-drafts-directory (format "%sdrafts" dms/org-static-blog-root-dir)) (setq org-static-blog-page-header (with-temp-buffer (insert-file-contents (format "%sstatic/header.html" dms/org-static-blog-root-dir)) (buffer-string))) (setq org-static-blog-page-preamble (with-temp-buffer (insert-file-contents (format "%sstatic/preamble.html" dms/org-static-blog-root-dir)) (buffer-string))) (setq org-static-blog-page-postamble (with-temp-buffer (insert-file-contents (format "%sstatic/postamble.html" dms/org-static-blog-root-dir)) (buffer-string))) (setq org-static-blog-enable-tags t) (setq org-static-blog-use-preview t)
Contents of header.html
, preamble.html
and postamble.html
are given as follows.
Assets static/style.css
and static/favicon.ico
are downloaded from Bastian.
<meta name="author" content="Dou Meishi"> <meta name="referrer" content="no-referrer"> <link href= "static/style.css" rel="stylesheet" type="text/css" /> <link href="static/favicon.ico" rel="icon" />
<div class="header"> Hello, Org Static Blog </div>
Created by <a href="https://github.com/bastibe/org-static-blog/">Org Static Blog</a>
Currently, the project layout looks like
org-blog/ ├── drafts ├── org │ └── notes.org └── static ├── favicon.ico ├── header.html ├── postamble.html ├── preamble.html └── style.css 3 directories, 6 files
Finally, call org-static-blog-publish
to generate the site. At this time, the project layout becomes
org-blog/ ├── archive.html ├── drafts ├── index.html ├── notes.html ├── org │ └── notes.org ├── rss.xml ├── static │ ├── favicon.ico │ ├── header.html │ ├── postamble.html │ ├── preamble.html │ └── style.css └── tags.html 3 directories, 11 files
Question
Does it scans all org files in
org-static-blog-posts-directory
recursively or not?Yes. For example, a folder named
2024/
in it will be published to the folder2024/
inorg-static-blog-publish-directory
.Does it support following symbolic links when checking org files?
Yes but no. I test the following based on the project layout in the Minimal Configuration section. I renamed the ordinary file
notes.org
insideorg-blog/org/
toorg-blog/../
but leave a symbolic link. So the project layout becomes.org-blog/ ├── drafts ├── org │ └── notes.org -> /home/dou/Documents/2024-01-22-TryOrgStaticBlog/notes.org └── static ├── favicon.ico ├── header.html ├── postamble.html ├── preamble.html └── style.css 3 directories, 6 files
However, calling
org-static-blog-pulish
exportsorg-blog/org/notes.org
to~/Documents/notes.html
.This issue comes function
org-static-blog-get-post-public-path
. Running either(org-static-blog-get-post-public-path "~/Documents/2024-01-22-TryOrgStaticBlog/notes.org")
or
(org-static-blog-get-post-public-path "~/Documents/2024-01-22-TryOrgStaticBlog/org-blog/org/notes.org")
gives the result
../../notes.html
.What will happen if
org-static-blog-publish-directory
is the same asorg-static-blog-posts-directory
? In this case, what will happen iforg-static-blog-drafts-directory
is a subfolder?It behaves like exporting all org files to the same directory, and posts inside the drafts directory will not be included in the index.
Build My Blog Site
It is also not hard to extend the minimal configuration to build a
real blog site. But before tweaking these scripts and assets, I need,
of course, get a public URL for hosting the site. Fortunately, GitHub
Pages allows hosting directly from a GitHub repository. What I need to
do is create a publich repo, say org-blog
, and go to Settings -> Pages
and set the deploy target to https://dou-meishi.github.io/blog/
. Now
I can replace the previous local URL to this one in the script and
assets.
Besides changing the publish URL, there are a few other things to make the site a slightly more visual appealing.
Add a top bar at each page, showing links to the homepage and the archive page.
This can be easily done by modifying the
preamble.html
<div class="header"> <div class="sitelinks"> <a href="https://dou-meishi.github.io/org-blog/index.html">Home</a> | <a href="https://dou-meishi.github.io/org-blog/archive.html">All Posts</a> </div> </div>
Render math formulae. This can also be achieved by adding appropriate javascript and stylesheets. Currently, I use KaTeX, which seems to be faster than MathJax.
<!-- Math Support by KaTeX --> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css" integrity="sha384-n8MVd4RsNIU0tAv4ct0nTaAbDJwPJzDEaqSD1odI+WdtXRGWt2kTvGFasHpSy3SV" crossorigin="anonymous"> <!-- The loading of KaTeX is deferred to speed up page rendering --> <script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.js" integrity="sha384-XjKyOOlGwcjNTAIQHIpgOno0Hl1YQqzUOEleOLALmuqehneUG+vnGctmUb0ZY0l8" crossorigin="anonymous"></script> <!-- To automatically render math in text elements, include the auto-render extension: --> <script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/contrib/auto-render.min.js" integrity="sha384-+VBxd3r6XgURycqtZ117nYw44OOcIax56Z4dCRWbxyPt0Koah1uHoK0o4+/RRE05" crossorigin="anonymous" onload="renderMathInElement(document.body);"></script>
Customize the top of the index page. This is done by setting the
org-static-blog-index-front-matter
variable in the lisp script.(setq org-static-blog-index-front-matter "<h1 class=title> Recent Posts </h1>")
Change the default ellipsis
(...)
used in preview to...
(setq org-static-blog-preview-ellipsis "...")
Use a different CSS stylesheet. I have been using this stylesheet for three years and always appreciating its clean design. It is designed for HTML exported from org files by
org-publish
. To adapt it to files exported byorg-static-blog
, I add several additional rules in a patched CSS.<link href= "https://gongzhitaao.org/orgcss/org.css" rel="stylesheet" type="text/css" /> <link href= "https://dou-meishi.github.io/org-blog/static/dou-org-blog.css" rel="stylesheet" type="text/css" />
Sync posts from my document folder. As I mentioned in the previous post, my notes resides in different event directories in the document folder, and, of course, I do not want to share the whole
~/Documents/
folder. So I list all files I want to share in~/.unison/syncpost.prf
, which looks likesource default.prf root = /home/dou/Documents root = /home/dou/Documents/2024-01-24-MyOrgBlog/ nodeletion = /home/dou/Documents path = 2023-09-19-Compactness/notes.org path = 2023-10-23-BanachSpaceExample/notes.org path = 2024-01-07-ReviewUnison/basics.org path = 2024-01-07-ReviewUnison/advanced.org path = 2024-01-11-CodeBlockinLaTeX/notes.org path = 2024-01-11-CodeBlockinLaTeX/simple-code.png path = 2024-01-11-CodeBlockinLaTeX/tcolorbox-listings.png path = 2024-01-14-TryOrgPublish/notes.org path = 2024-01-22-TryOrgStaticBlog/notes.org
Whenever I want to post something, I just check this file, run
unison-gui syncpost
, and execute all lisp script in thebuild-blog.el
.
The lisp script and static assets are all included in my git repo for this blog.
External Links refs
Below are other users' configuration on org static blog.
- a simple setup: simplicity - programming (and other) musings
- another simple setup Justin's emacs configuration - Writting - Blogging
- an extensive setup: AlBasmala: Blogging with Emacs & Org-mode (•̀ᴗ•́)و