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