2013-11-15

Blog using OrgMode and Pelican

First I was using drupal, then tinkerer, then I discovered OrgMode

Since I started using OrgMode for my notes, I figured out, that would be cool to be able to just move notes from one file to another and have a blog post ready.

I kind of figured out something, using Pelican.

1 What about Hyde, Jekyll, Tinkerer, O-blog?

Everything seems nice, but I could not make them work easily the way I wanted.

1.1 O-blog

O-blog seems to have everything included but I could not make anything else than the demo work, and I did not want to have everything in one file. Also it is in elisp, which makes me fear of not beeing able to touch it.

1.2 Jekyll

Jekyll is in ruby …

1.3 Hyde

I don't remember, I found this tutorial but I could not make it work, also, I wanted to keep the normal org-mode keywords like #+title #+keywords #+date

1.4 Tinkerer

It's simple and does everything I wanted, exept I could not find a way to import already rendered html files

1.5 Pelican

Works like Tinkerer, uses templates in jinja2, is in python and allows to import html files, which org-mode can produce using M-x org-publish

2 Setting things up

2.1 Pelican

2.1.1 Install

I installed Pelican using pip from the git repo. Why? because it has a patch that allows <meta charset=..> tags that org-publish adds in the exported files

pip install -e git+https://github.com/getpelican/pelican.git#egg=pelican

2.1.2 Configure

I used the theme Strongly Typed from html5up.net and got helped by Pierre Paul to make it usable by pelican now it is available in a github repo

2.1.2.1 Initialize the pelican website
pelican-quickstart

then answer the questions

2.1.2.2 Install the theme

Just put the selected theme in some folder, then in pelicanconf.py using the variable THEME. Put the relative or absolute path.

THEME="themes/strongly"
2.1.2.3 Posts and pages

I wanted to have articles in a subfolder and pages in the main folder. Here is how I configured pelicanconf.py

PATH = 'public_html' #where org-mode will export the html files
PAGE_DIR = ('') # Directory to look at for pages, relative to PATH.
PAGE_EXCLUDES = (('posts',)) # A list of directories to exclude when looking for pages.
ARTICLE_DIR = ('posts')   # Directory to look at for articles, relative to PATH.
ARTICLE_EXCLUDES = (())
2.1.2.4 Org specific settings

I exported org-mode's style for code highlighting using M-x org-html-htmlize-generate-css to a file called org-style.css which I then had to include in the theme. I prefered to make it optional, so the theme accepts an ORGMODE variable. If set to True it will include it.

2.1.2.5 Other settings

See the nice documentation from Pelican

2.2 Org-mode

Org-mode is really awesome, but I'm new to it, so you might want to read http://orgmode.org/ for more details

2.2.1 Install

I used M-x package-install org in order to get the latest version. It had a patch for generating <meta name="keywords"…> based on the #+keywords: in the org file

2.2.2 Configure

This took me a bit of tests to be able to get this the way I'd want. For now I have that in my ~/.emacs. I know I could put it somewhere else but seeing the full size of my config, helps me make sure I'm not adding crazy long unneeded configs just because it's easy

(require 'org-publish)
(setq org-publish-project-alist
      '(
        ("base-orgs" ;; an identifier
         :base-directory "~/org-files/blog" ;; path where I put the articles and pages
         :base-extension "org" ;; export org files
         :publishing-function org-html-publish-to-html ;; use the html publishing method
         :auto-sitemap nil ;; don't generate a sitemap (kind of an index per folder)
         :publishing-directory "~/pelican-site/public_html" ;; where to publish those files
         :recursive t ;; recursively publish the files
         :headline-levels 4 ;; Just the default for this project.
         :auto-preamble nil ;; Don't add any kind of html before the content
         :export-with-tags t
         :todo-keywords nil
         ;;:author nil
         :html-doctype "html5" ;; set doctype to html5
         :html-html5-fancy t 
         :creator-info nil ;; don't insert creator's info
         :auto-postamble nil ;; Don't add any kind of html after the content
         :html-postamble nil ;; same thing
         :timestamp nil ;; 
         :exclude-tags ("noexport" "todo")) ;; just in case we don't want to publish some part of the files
        ("blog-static" ;; identifier for static files
         :base-directory "~/org-files/blog" ;; path where I put the articles and pages
         :publishing-directory "~/pelican-site/public_html" ;; where to publish those files
         :base-extension "css\\|js\\|png\\|jpg\\|gif\\|pdf\\|mp3\\|ogg\\|swf"
         :recursive t
         :publishing-function org-publish-attachment ;; method to use for publishing those files
         )
        ("blog" :components ("base-orgs" "blog-static")) ;; meta identifier to publish everything at once

        ))

(require 'org-macro) ;; enable org-macro
;; this is a custom macro until I find out how to use defadvice
;; in order to put the <meta name="date"...> in the exported file
;; in the org file we would put {{{dt(2010-12-31 23:59)}}}
(defun apply-my-macros (backend)
  (org-macro-replace-all
   (list (cons "dt" "#+HTML_HEAD: <meta name=\"date\" content=\"$1\" />"))))
(add-hook 'org-export-before-processing-hook 'apply-my-macros)

3 Publishing

3.1 Create an org file

You can create a template for that but I did not do it yet so I don't know how :) Here is what a basic article would look like

#+title: What a nice article
#+keywords: some,tags,or,keywords
{{{dt(2012-12-31 23:59)}}}

* here is something interesting
  Yep!
  #+BEGIN_SRC python
  def blah():
     print("blah")
  #+END_SRC

3.2 Publish to html

from emacs run M-x org-publish (using IDO, you can do M-x o-pub) then enter what to publish, here blog

3.3 Publish in a nice pelican blog

from the folder you have initialized your pelican website run

make html
make serve

3.4 Try it

open http://127.0.0.1:8000 and see how pretty

3.5 Send it somewhere on the web

Configure your Makefile or your fabric.py and run the corresponding command. For the Makefile using rsync, you can run make rsync_upload

4 Notes, tips, tweaks

4.1 Force org-mode to re-publish

to force org-mode to re-publish articles it already published, I touch all the files, ie:

#+BEGIN_SRC sh touch ~/org-files/blog/* touch ~/org-files/blog/*/*/*

#+END_SRC\

4.2 Ensure moved posts are removed from published site

to make sure there are not posts in double, for example org files moved or renamed, I delete the public_html

4.3 To get images in posts from org

I created a files folder in the org-file/blog folder and then link to it (ln -s) from subfolders. That way from orgmode, I can see the files, and when published they have the right src attribute (ie: ./files/pic.jpg)

5 Finally

There are still a few things to fix, like use #+date: and other details, but that does the job.