Blog with Emacs and Pelican - even better !

Fixing some stuff, I decided to look again at how to get a better and easier process to post on my site.

I was already using Org mode with Pelican as seen in Part 1.

But I had to type a few weird things like `{{{dt(….)}}`, which would call a macro, manually (oh no!) enter the date, the properties and then go in the shell `make html` etc …

In the end it was pretty easy to get better … once I found out the org_reader Pelican plugin

1 Install the plugin

Easy ! Go in the folder where I run Pelican from and run :

git clone --recursive https://github.com/getpelican/pelican-plugins

2 Then configure Pelican

Which is quite simple too

PLUGIN_PATHS = ['pelican-plugins']
PLUGINS = ['org_reader']

3 A bit more delicate: configure Emacs

It was working with my current Emacs setup, but it was also doing a bunch of things adding time to the pages rendering.

The parts I struggled with were having colors in the source blocks and not using inline CSS.

3.1 Source blocks colors

I wanted to keep solarized dark but it wasn't coloring. After looking around it seems it was because it was running from the terminal so not using all the colors.

The fix would be to install Emacs solarized theme and set it to work in the terminal. To do that, clone it and add it to the config, it looks like this:

;; Theme stuff
(add-to-list 'custom-theme-load-path (expand-file-name "~/.emacs.d/emacs-color-theme-solarized"))
(set-frame-parameter nil 'background-mode 'dark)
(set-terminal-parameter nil 'background-mode 'dark)
(load-theme 'solarized t)

3.2 Don't inline the CSS

Then it kept trying to set it's own style inline, overriding all the beautifullness `M-x org-html-htmlize-generate-css` puts in a css, used in the pelican theme. It is just a variable to set, for safety I set two since I'm not sure what is used when:

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

3.3 The rest and the full config

Here is the file blog-export.el I use.

The "Org stuff" came mostly from my previous config when I exported HTML from Emacs.

The "Random Stuff" part, I'm not sure it's needed, but since it works, I didn't look too much into it.

;; -*- MODE: emacs-lisp -*-
(add-to-list 'load-path (expand-file-name "~/.emacs.d/addons"))
(add-to-list 'load-path (expand-file-name "~/.emacs.d/markdown-mode"))

;; Theme stuff
(add-to-list 'custom-theme-load-path (expand-file-name "~/.emacs.d/emacs-color-theme-solarized"))
(set-frame-parameter nil 'background-mode 'dark)
(set-terminal-parameter nil 'background-mode 'dark)
(load-theme 'solarized t)

(require 'htmlize)    
(require 'ox)
(require 'highlight-indentation)

;; Org stuff
(setq org-html-htmlize-output-type 'css)
(setq htmlize-output-type 'css)

         org-export-headline-levels 4
         org-html-preamble nil
         org-export-with-tags t
         org-export-with-todo-keywords nil
         org-html-doctype "html5"
         org-html-html5-fancy t
         org-export-creator-string nil
         org-html-postamble nil
         org-export-with-timestamp nil)

(setq org-src-fontify-natively t)
(setq org-use-sub-superscripts nil)
(setq org-export-with-sub-superscripts nil)
(add-to-list 'org-babel-load-languages '(php . t))
(org-babel-do-load-languages 'org-babel-load-languages org-babel-load-languages)

;; Random stuff, not sure if it's needed
(add-to-list 'load-path "~/.emacs.d/jade-mode")
(require 'ob-php)
(require 'web-mode)
(require 'sws-mode)
(require 'php-mode)
(require 'yaml-mode)
(require 'jade-mode)    

(autoload 'markdown-mode "markdown-mode"
   "Major mode for editing Markdown files" t)

(setq tab-always-indent t)
(setq tab-width 4)
(setq-default indent-tabs-mode nil)

4 Creating a new post

For this, I added an org-mode capture template, so I can do one of the following to move some of my notes to a new Org file ready to post:

  • `M-x org-capture`
  • `:org-capture`
  • `C-c c`

The template :

(setq org-capture-templates
      '(("b" "Blog" plain (file (capture-report-data-file "~/Sync/org/blog/posts"))
          "#+DATE: %t \n#+CATEGORY: %^G\n#+TITLE: %?\n")

I also had to add a function to generate the path and filename depending on the section I wanted to create the post.

Function capture-report-data-file based on this stack overflow question:

(defun capture-report-data-file (path)
        (completing-read "S(ysadmin)|P(rojects)|M(isc) ? " '("Sysadmin" "Projects" "Misc") nil t))
        (read-string "Title: "))
    (expand-file-name (format "%s.org" title) (concat path "/" category))))

The completing-read takes those arguments:

  • "S(ysadmin)|P(rojects)|M(isc) ?": it's the prompt
  • '("Sysadmin" "Projects" "Misc"): Those are my Pelican categories which are just sub folders in my org/blog folder.
  • nil: I don't care :)
  • t: set to true to force the choice to only what is offered (here Sysadmin Projects or Misc)

5 Rendering everything and publishing

Standard Pelican procedure:

make html
make serve # to check everything is fine
make rsync_upload # or any other favourite publishing option