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