├── .gitignore
├── README
├── org-jekyll.el
└── test
├── _posts
├── 2009-12-26-Entry-in-the-second-file.html
├── 2009-12-26-First-blog-entry.html
└── 2009-12-26-Second-blog-entry.html
├── org.el
├── test-2.org
└── test.org
/.gitignore:
--------------------------------------------------------------------------------
1 | *~
2 | *.xfasl
3 | *.pyc
4 | .emacs-bu/*
5 |
6 |
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 | Org-jekyll — export jekyll blog posts from org-mode.
2 |
3 | Juan Reyero, http://juanreyero.com
4 |
5 | Extracts subtrees from your org-publish project files that have a
6 | :blog: keyword and an :on: property with a timestamp, and exports
7 | them to a subdirectory _posts of your project's publishing
8 | directory in the year-month-day-title.html format that Jekyll
9 | expects. Properties are passed over as yaml front-matter in the
10 | exported files. The title of the entry is the title of the
11 | subtree.
12 |
13 | The full documentation is at:
14 |
15 | http://juanreyero.com/open/org-jekyll/
16 |
--------------------------------------------------------------------------------
/org-jekyll.el:
--------------------------------------------------------------------------------
1 | ;;; org-jekyll.el --- Export jekyll-ready posts form org-mode entries
2 | ;;;
3 | ;;; Author: Juan Reyero
4 | ;;; Version: 0.4
5 | ;;; Keywords: hypermedia
6 | ;;; Package-Requires: ((org "8.0"))
7 | ;;; Homepage: http://juanreyero.com/open/org-jekyll/
8 | ;;; Repository: http://github.com/juanre/org-jekyll
9 | ;;; Public clone: git://github.com/juanre/org-jekyll.git
10 | ;;;
11 | ;;; Commentary:
12 | ;;;
13 | ;;; Extract subtrees from your org-publish project files that have
14 | ;;; a :blog: keyword and an :on: property with a timestamp, and
15 | ;;; export them to a subdirectory _posts of your project's publishing
16 | ;;; directory in the year-month-day-title.html format that Jekyll
17 | ;;; expects. Properties are passed over as yaml front-matter in the
18 | ;;; exported files. The title of the subtree is the title of the
19 | ;;; entry. The title of the post is a link to the post's page.
20 | ;;;
21 | ;;; Look at http://orgmode.org/worg/org-tutorials/org-jekyll.html for
22 | ;;; more info on how to integrate org-mode with Jekyll, and for the
23 | ;;; inspiration of the main function down there.
24 | ;;;
25 | ;;; Code:
26 |
27 | ;;(require 'ox-html)
28 |
29 | (defvar org-jekyll-category nil
30 | "Specify a property which, if defined in the entry, is used as
31 | a category: the post is written to category/_posts. Ignored if
32 | nil. Use \"lang\" if you want to send posts in different
33 | languages to different directories.")
34 |
35 | (defvar org-jekyll-lang-subdirs nil
36 | "Make it an assoc list indexed by language if you want to
37 | bypass the category subdir definition and build blog subdirs per
38 | language.")
39 |
40 | (defvar org-jekyll-localize-dir nil
41 | "If non-nil and the lang property is set in the entry,
42 | org-jekyll will look for a lang.yml file in this directory and
43 | include it in the front matter of the exported entry.")
44 |
45 | (defvar org-jekyll-new-buffers nil
46 | "Buffers created to visit org-publish project files looking for blog posts.")
47 |
48 | (defun org-jekyll-publish-dir (project &optional category)
49 | "Where does the project go, by default a :blog-publishing-directory
50 | entry in the org-publish-project-alist."
51 | (princ category)
52 | (if org-jekyll-lang-subdirs
53 | (let ((pdir (plist-get (cdr project) :blog-publishing-directory))
54 | (langdir (cdr (assoc category org-jekyll-lang-subdirs))))
55 | (if langdir
56 | (concat pdir (cdr (assoc category org-jekyll-lang-subdirs))
57 | "_posts/")
58 | (let ((ppdir (plist-get (cdr project) :blog-publishing-directory)))
59 | (unless ppdir
60 | (setq ppdir (plist-get (cdr project) :publishing-directory)))
61 | (concat ppdir
62 | (if category (concat category "/") "")
63 | "_posts/"))))
64 | (let ((pdir (plist-get (cdr project) :blog-publishing-directory)))
65 | (unless pdir
66 | (setq pdir (plist-get (cdr project) :publishing-directory)))
67 | (concat pdir
68 | (if category (concat category "/") "")
69 | "_posts/"))))
70 |
71 | (defun org-jekyll-site-root (project)
72 | "Site root, like http://yoursite.com, from which blog
73 | permalinks follow. Needed to replace entry titles with
74 | permalinks that RSS agregators and google buzz know how to
75 | follow. Looks for a :site-root entry in the org-publish-project-alist."
76 | (or (plist-get (cdr project) :site-root)
77 | ""))
78 |
79 |
80 | (defun org-get-jekyll-file-buffer (file)
81 | "Get a buffer visiting FILE. If the buffer needs to be
82 | created, add it to the list of buffers which might be released
83 | later. Copied from org-get-agenda-file-buffer, and modified
84 | the list that holds buffers to release."
85 | (let ((buf (org-find-base-buffer-visiting file)))
86 | (if buf
87 | buf
88 | (progn (setq buf (find-file-noselect file))
89 | (if buf (push buf org-jekyll-new-buffers))
90 | buf))))
91 |
92 | (defun org-jekyll-slurp-yaml (fname)
93 | (remove "---" (if (file-exists-p fname)
94 | (split-string (with-temp-buffer
95 | (insert-file-contents fname)
96 | (buffer-string))
97 | "\n" t))))
98 |
99 | (defun ensure-directories-exist (fname)
100 | (let ((dir (file-name-directory fname)))
101 | (unless (file-accessible-directory-p dir)
102 | (make-directory dir t)))
103 | fname)
104 |
105 | (defun org-jekyll-sanitize-string (str project)
106 | (if (plist-get (cdr project) :jekyll-sanitize-permalinks)
107 | (progn (setq str (downcase str))
108 | (dolist (c '(("á" . "a")
109 | ("é" . "e")
110 | ("í" . "i")
111 | ("ó" . "o")
112 | ("ú" . "u")
113 | ("à" . "a")
114 | ("è" . "e")
115 | ("ì" . "i")
116 | ("ò" . "o")
117 | ("ù" . "u")
118 | ("ñ" . "n")
119 | ("ç" . "s")
120 | ("\\$" . "S")
121 | ("€" . "E")))
122 | (setq str (replace-regexp-in-string (car c) (cdr c) str)))
123 | (replace-regexp-in-string "[^abcdefghijklmnopqrstuvwxyz-]" ""
124 | (replace-regexp-in-string " +" "-" str)))
125 | str))
126 |
127 | (defun org-jekyll-export-entry (project)
128 | (let* ((props (org-entry-properties nil 'standard))
129 | (time (cdr (or (assoc "on" props)
130 | (assoc "ON" props))))
131 | (lang (cdr (or (assoc "lang" props)
132 | (assoc "LANG" props))))
133 | (category (if org-jekyll-category
134 | (cdr (assoc org-jekyll-category props))
135 | nil))
136 | (yaml-front-matter (copy-alist props)))
137 | (unless (assoc "layout" yaml-front-matter)
138 | (push '("layout" . "post") yaml-front-matter))
139 | (when time
140 | (let* ((heading (org-get-heading t))
141 | (title (replace-regexp-in-string "[:=\(\)\?]" ""
142 | (replace-regexp-in-string
143 | "[ \t]" "-" heading)))
144 | (str-time (and (string-match "\\([[:digit:]\-]+\\) " time)
145 | (match-string 1 time)))
146 | (to-file (format "%s-%s.html" str-time
147 | (org-jekyll-sanitize-string title project)))
148 | (org-buffer (current-buffer))
149 | (yaml-front-matter (cons (cons "title" heading)
150 | yaml-front-matter))
151 | html)
152 | (org-narrow-to-subtree)
153 | (let ((level (- (org-reduced-level (org-outline-level)) 1))
154 | (top-level org-html-toplevel-hlevel)
155 | (contents (buffer-substring (point-min) (point-max)))
156 | (site-root (org-jekyll-site-root project)))
157 | ;; Without the promotion the header with which the headline
158 | ;; is exported depends on the level. With the promotion it
159 | ;; fails when the entry is not visible (ie, within a folded
160 | ;; entry).
161 | (dotimes (n level nil) (org-promote-subtree))
162 | (setq html
163 | (replace-regexp-in-string
164 | (format "
Add something to it. 13 |
With some content in the first entry. 14 |
With content in the second. 14 |