Update "How Worg publishes itself as HTML?".
[Worg.git] / org-tutorials / org-jekyll.org
blob46643bc0fd3fc337f778a917ee3eefa12556ad04
1 #+TITLE: Using org to Blog with Jekyll
2 #+AUTHOR: Ian Barton.
3 #+EMAIL: ian@manor-farm.org
4 #+LANGUAGE: en
5 #+OPTIONS:    H:3 num:nil toc:t \n:nil @:t ::t |:t ^:t -:t f:t *:t TeX:t LaTeX:t skip:nil d:(HIDE) tags:not-in-toc
6 #+STARTUP:    hidestars 
9 * Introduction.
10 [[http://wiki.github.com/mojombo/jekyll][Jekyll]] is a static web site generator written in Ruby. It can
11 transform various text markups, using a templating language, into
12 static html. The resulting site can be served by almost any web server
13 without requiring additional components such as php. Jekyll is the
14 tool used to produce Github's pages.
16 This article discusses how to produce both a static site and a blog
17 using Jekyll and org. Rather than writing a markup processor for org
18 files, I have relied on org's html export features to generate files
19 that can be processed by Jekyll.
21 Org already has an excellent html export engine. However, it lacks
22 built in support for blogging. Using Jekyll also gives more control
23 over the final appearance of your site.
25 Publishing your site with org and Jekyll involves three steps:
27 - write your page content using org.
29 - use org to export your pages to html in the Jekyll project directory.
31 - run Jekyll to convert your html pages exported from org into your
32   final site.
34 By default Jekyll produces its output in the _site directory of
35 Jekyll's working directory. This is a self contained version of your
36 site, which can be deployed to your web server. The files in _site are
37 completely self contained, so all you need to do is to copy them to
38 your web server. Methods include using ftp, rsync or a git post commit
39 hook. You can configure where Jekyll puts its published files in
40 _config.yml.
42 Essentially, I am using org to produce everything between the <body>
43 tags on the page and Jekyll to produce the rest. Note that you can
44 easily embed html content in your org pages using the +BEGIN_HTML tag.
46 * Install Jekyll.
48 Installation is described at the [[http://github.com/mojombo/jekyll][Jekyll]] web site. 
50 * Project Directory Structure.
51 Jekyll expects a certain directory structure. In the example below my
52 Jekyll project is in a directory called "jekyll". Blog posts are in
53 "_posts" and the layout templates in "_layouts". The "_includes"
54 directory is for files containing code you want to include in other
55 pages e.g. a header or sidebar.
57 The file _config.yml is a YAML file that contains Jekyll's
58 configuration for the site.
60 In addition to the "_posts" directory you can create other directories
61 to hold different non blog parts of your site.
63 #+BEGIN_EXAMPLE
64 '|myproject
65 '|   |org
66 '|      |_posts
67 '|      |-- 2009-11-26-my-first-post.org
68 '|   |index.org
69 '|   |jekyll
70 '|   -- _config.yml
71 '|   -- _layouts
72 '|      |-- default.html
73 '|      `-- post.html
74 '|   -- _posts
75 '|      |-- 2009-11-26-my-first-post.html
76 '|      
77 '|   -- |_site
78 '|   -- |_includes
79 `    -- index.html
80 #+END_EXAMPLE
83 You should setup the directory structure of your org files to mirror
84 that of the Jekyll project. Then when you export your org files as
85 html the files will end up in the correct place in your Jekyll
86 project. I usually place the directory containing my org files in the
87 directory about the Jekyll project directory to make sure that Jekyll
88 doesn't consider .org files to be part of its project.
90 * Configuring org html Export.
91 The fundamentals of publishing html are described on [[http://orgmode.org/worg/org-tutorials/org-publish-html-tutorial.php][worg]]. I am
92 assuming that you have a basic working org publishing setup. By
93 default org produces complete web pages. However, as I am using Jekyll
94 I am only really interested in the section of the page between the
95 <body> tags, as Jekyll produces the rest. Most things in org are
96 configurable and it's possible to tell org to export only the bits of
97 the page between the <body> tags. Here is the relevant section of my .emacs:
99 #+BEGIN_SRC emacs-lisp
100 (setq org-publish-project-alist
101       '(
103   ("org-ianbarton"
104           ;; Path to your org files.
105           :base-directory "~/devel/ianbarton/org/"
106           :base-extension "org"
108           ;; Path to your Jekyll project.
109           :publishing-directory "~/devel/ianbarton/jekyll/"
110           :recursive t
111           :publishing-function org-publish-org-to-html
112           :headline-levels 4 
113           :html-extension "html"
114           :body-only t ;; Only export section between <body> </body>
115     )
118     ("org-static-ian"
119           :base-directory "~/devel/ianbarton/org/"
120           :base-extension "css\\|js\\|png\\|jpg\\|gif\\|pdf\\|mp3\\|ogg\\|swf\\|php"
121           :publishing-directory "~/devel/ianbarton/"
122           :recursive t
123           :publishing-function org-publish-attachment)
125     ("ian" :components ("org-ianbarton" "org-static-ian"))
128 #+END_SRC
130 To export my site I just run "C-c e X ian".
132 You need to set the destination of your exported files to your Jekyll
133 project directory. Assuming you have set up your org directory
134 structure to mirror that of your Jekyll project everything should end
135 up in the correct place.
137 * Creating an org File to be Published with Jekyll.
138 When you run Jekyll it processes the source files for your site and
139 any files with YAML Front Matter are subject to special processing. The
140 Front Matter is used to tell Jekyll how to format your page.
142 Bear in mind that Jekyll doesn't process your .org files, but the
143 .html files produced by exporting. So when writing an org file it
144 should be formatted in such a way that when exported it produces html
145 suitable for processing by Jekyll.
147 YAML Front Matter must be the first thing in the file, with
148 no blank lines above the Front Matter Section. A typical Front Matter
149 Section would look like:
152 layout: default
153 title: My Page Title.
156 So you should ensure that any Front Matter directives come first in
157 your org file.
159 Note that the three hyphens "---" are part of the markup and are
160 required. The layout tag tells Jekyll which layout from its _layouts
161 directory should be used to format your page. You can include any
162 other keys in the Front Matter section (e.g. title:), which you can use
163 in your page. See the Jekyll [[http://wiki.github.com/mojombo/jekyll/yaml-front-matter][wiki]] for more details on Front Matter.
165 Below is a short extract from one of my org files showing my setup:
167 #+BEGIN_EXAMPLE
168 #+STARTUP: showall indent
169 #+STARTUP: hidestars
170 #+BEGIN_HTML
172 layout: default
173 title: Benighted on the Ben.
174 excerpt: An unplanned bivouac on Ben Nevis.
176 #+END_HTML
177 It was early January when six of us travelled up to ....
178 #+END_EXAMPLE
180 The Front Matter section is wrapped in #+BEGIN_HTML so it is exported
181 literally to the final html file. You may need to upgrade your org
182 version as older versions produced two blank lines before the Front
183 Matter section when exported. You can define your own Front Matter keys and use
184 them within your generated page. In the above example I use the
185 "excerpt" key to display "teasers" for a blog post.
187 Note that the current git version of org removes the first "---" if the
188 directory containing the file start with an underscore. The workaround
189 is to start your file with "---" in both the first two lines.
191 Carsten has also provided two hooks that are run after exporting is
192 complete, which can also be used to tidy up the output:
194 #+BEGIN_SRC emacs-lisp
195 org-export-html-final-hook      (always)
196 org-publish-after-export-hook   (when going through org-publish)
197 #+END_SRC
199 Once you have exported your org project to html it's simply a matter
200 of running jekyll to produce the final output. By default Jekyll puts
201 its output in the _site directory of your project, but you can
202 customize this in your _config.yml file.
204 * Blogging with Jekyll and Org.
206 Jekyll has built in support for blogging. Anything you place in the
207 _posts directory of your Jekyll project is considered as a blog
208 post. However, the file names of your posts must adhere to the
209 following format:
211 #+BEGIN_EXAMPLE
212 yyyy-mm-dd-post_name.html
213 #+END_EXAMPLE
215 To write a post just create a new file with the correct filename in
216 your org/_posts directory. You may find that Yasnippet is useful for
217 inserting Front Matter and other directives in your org file. When you
218 have finished just run C-c e X project_name to export your org project
219 as html and then run jekyll to generate your site.
221 You can use Jekyll's [[http://wiki.github.com/mojombo/jekyll/template-data][template]] markup to decide how your blog posts are
222 displayed. On the Jekyll [[http://wiki.github.com/mojombo/jekyll/sites][sites]] page there are many sites with source
223 listed, so you can study how other people use the markup to create
224 their blog. You can also view my site http://www.ian-barton.com and
225 see a snapshot of the source at
226 http://github.com/geekinthesticks/ianbarton .
228 You can assign categories to your posts either by placing posts inside
229 folders like:
231 #+BEGIN_EXAMPLE
232 _posts/org/jekyll/howto.html
234 #+END_EXAMPLE
236 This would assign your post to the "org" and "jekyll" categories.
238 or by using YAML markup in your org file:
240 #+BEGIN_EXAMPLE
241 categories:
242     - org
243     - linux
244 #+END_EXAMPLE
246 ** Showing Blog Posts on the Front Page.
247 Most blogs show the latest posts on their front page. The example
248 below shows the title and an excerpt for the five latest posts:
250 #+BEGIN_EXAMPLE
251 <ul class="posts">
252 {% for post in site.posts limit: 5 %}
253   <div class="post_info">
254     <li><a href="{{ post.url }}">{{ post.title }}</a> <span>({{ post.date | date:"%Y-%m-%d" }})</span></li>
255     </br> <em>{{ post.excerpt }} </em>
256     </div>
257   {% endfor %}
258 </ul>
259 #+END_EXAMPLE
262 ** Creating Archive Pages.
263 You will probably only want to display a limited number of blog posts
264 on your front page. However, you will also want to make older pages
265 available. You can create a simple list of all blog posts using the
266 following markup:
268 #+BEGIN-EXAMPLE
269         <ul>
270           {% for post in site.posts %}
271             <li>
272               <a href="{{ post.url }}" title="{{ post.title }}">
273                 <span class="date">
274                   <span class="day">{{ post.date | date: '%d' }}</span> 
275                   <span class="month"><abbr>{{ post.date | date: '%b' }}</abbr></span>
276                   <span class="year">{{ post.date | date: '%Y' }}</span>
277                 </span>
278                 <span class="title">{{ post.title }}</span>
279               </a>
280             </li>
281           {% endfor %}
282         </ul>
283 +END_EXAMPLE
285 * Inserting Images.
286 You will probably want to insert some images into your blog posts. I
287 use the following method:
289 #+BEGIN_EXAMPLE
290 <img src ="/images/skiddaw.jpg"
291 "alt"="John and Ella on Skiddaw" align ="left" width="300"
292 height="250" title="John and Ella on Skiddaw" class="img"</img>
293 #+END_EXAMPLE
295 Note that the class attribute refers to the class used to style the
296 image tag in your css. My css contains:
298 #+BEGIN_EXAMPLE
299 img {
300     margin: 15px;
301     border: 1px solid blue;
304 #+END_EXAMPLE
306 Note that if you wish to have some space between your image and the
307 text, using padding in your css doesn't seem to work. I use margin,
308 which gives the same effect.
310 Whilst this works, it won't display captions for your
311 images. Unfortunately, after years of development xhtml doesn't seem
312 to provide an easy way to display image captions. I decided to use the
313 method described [[http://www.w3.org/Style/Examples/007/figures][here]]. An example from of floating a picture to the
314 right of the text is shown below.
316 In your .org file use the following html to embed the picture:
318 #+BEGIN_EXAMPLE
319 <div class="photofloatr">
320   <p><img src="myphoto.jpg" width="300"
321     height="150" alt="My Mug Shot"></p>
322   <p>A photo of me</p>
323 </div>
324 #+END_EXAMPLE
326 Now you need to add some information to your style sheet:
328 #+BEGIN_EXAMPLE
329 div.photofloatr {
330     float: right;
331     border: thin silver solid;
332     margin: 0.5em;
333     padding: 0.5em;
336 div.photofloatr p {
337   text-align: center;
338   font-style: italic;
339   font-size: smaller;
340   text-indent: 0;
342 #+END_EXAMPLE
344 A third method, which I haven't tried myself, is to use the jQuery EXIF
345 plugin to extract the caption from the image EXIF data and use
346 Javascript to display it. See [[http://www.nihilogic.dk/labs/exif/][here]] for  more details.
348 * Using Text Markup in Front Matter.
349 By default text in the Front Matter part of your file isn't processed
350 by Jekyll's markup engine. However, you can use the Textilize filter
351 to convert your Front Matter string into HTML, formatted using textile
352 markup.
354 I use this to format my page excerpts, which I include in my org files
355 Front Matter markup. So in my sites index.html I have:
357 #+BEGIN-EXAMPLE
358     <li><a href="{{ post.url }}">{{ post.title }}</a> <span>({{ post.date | date:"%Y-%m-%d" }})</span></li>
359     </br> <em>{{ post.excerpt | textilize}} </em>
361 #+END-EXAMPLE
363 This lets me use textile markup in my page excerpts, which are defined
364 in my page's YAML Front Matter section.
366 * Version Control with Jekyll.
367 Jekyll is amenable to using version control systems. If you follow my
368 suggested directory structure you can create a git repo to your top
369 level directory. You can then create a post-commit script that runs
370 the org html export and then runs Jekyll to generate your site.
372 * HappyBlogger's Jekyll Modifications.
373 Bjørn Arild Mæland has created some modifications to Jekyll to
374 provide some pre-processing to org files to allow for better
375 integration with Jekyll. You can find his code on [[http://github.com/bmaland/happyblogger][github]].
376 * Another example of Org-mode/Jekyll usage
377 The on-line documentation for [[file:../org-contrib/babel/index.org][Org-babel]] development is published on
378 [[http://github.com][github]] which uses jekyll.  The following code is used to publish one
379 blog post for every subheading of the first to top-level headings of a
380 org file which tracks Org-babel development.  The results can be seen
381 [[http://eschulte.github.com/babel-dev/][here]], and the code used to create this site is available [[http://github.com/eschulte/babel-dev/][here]].
382 #+begin_src emacs-lisp
383   (save-excursion
384     ;; map over all tasks entries
385     (let ((dev-file (expand-file-name
386                      "development.org"
387                      (file-name-directory (buffer-file-name))))
388           (posts-dir (expand-file-name
389                       "_posts"
390                       (file-name-directory (buffer-file-name))))
391           (yaml-front-matter '(("layout" . "default"))))
392       ;; go through both the tasks and bugs
393       (mapc
394        (lambda (top-level)
395          (find-file dev-file)
396          (goto-char (point-min))
397          (outline-next-visible-heading 1)
398          (org-map-tree
399           (lambda ()
400             (let* ((props (org-entry-properties))
401                    (todo (cdr (assoc "TODO" props)))
402                    (time (cdr (assoc "TIMESTAMP_IA" props))))
403               ;; each task with a state and timestamp can be exported as a
404               ;; jekyll blog post
405               (when (and todo time)
406                 (message "time=%s" time)
407                 (let* ((heading (org-get-heading))
408                        (title (replace-regexp-in-string
409                                "[:=\(\)\?]" ""
410                                (replace-regexp-in-string
411                                 "[ \t]" "-" heading)))
412                        (str-time (and (string-match "\\([[:digit:]\-]+\\) " time)
413                                       (match-string 1 time)))
414                        (to-file (format "%s-%s.html" str-time title))
415                        (org-buffer (current-buffer))
416                        (yaml-front-matter (cons (cons "title" heading) yaml-front-matter))
417                        html)
418                   (org-narrow-to-subtree)
419                   (setq html (org-export-as-html nil nil nil 'string t nil))
420                   (set-buffer org-buffer) (widen)
421                   (with-temp-file (expand-file-name to-file posts-dir)
422                     (when yaml-front-matter
423                       (insert "---\n")
424                       (mapc (lambda (pair) (insert (format "%s: %s\n" (car pair) (cdr pair))))
425                             yaml-front-matter)
426                       (insert "---\n\n"))
427                     (insert html))
428                   (get-buffer org-buffer)))))))
429        '(1 2))))  
430 #+end_src
432 * Other Blog Solutions for org.
433 ** Blorgit
434 [[http://orgmode.org/worg/blorgit.php][Blorgit]] uses org mode for markup and runs on the Sinatra mini
435 framework. It is amenable to using git for posting and maintenance.
436 ** ikiwiki
437 [[http://ikiwiki.info/][ikiwiki]] is a web site compiler written in Perl. In many ways it is
438 similar to Jekyll, but has closer integration with version control
439 systems. It supports blogging and has many plugins.
441 There is an org mode plugin by [[http://www.golden-gryphon.com/blog/manoj/blog/2008/06/08/Using_org-mode_with_Ikiwiki/][Manoj]], which lets you write your posts in org
442 and converts them to html suitable for processing by ikiwiki.