Post

Converting Org-Mode to Markdown for Jekyll

Writing Jekyll posts in Org Mode.

Converting Org-Mode to Markdown for Jekyll

img

This is a guide on how to setup Emacs to convert Org-Mode to Markdown for Jekyll.

I followed the guide here to setup a Org publishing project: https://orgmode.org/worg/org-tutorials/org-jekyll.html

Basically, this is how it works.

You have a directory called ~/myproject/ for example where you put the org/ and jekyll/ directories.

In the org/ directory is your _posts directory, that contains your posts written in Org Mode. You can also have an assets directory.

In the jekyll/ directory is the Jekyll site.

؜

Tree view

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
~/myproject
├── jekyll
│   ├── assets
│   │   ├── css
│   │   ├── fonts
│   │   └── images
│   ├── _data
│   ├── _includes
│   ├── _layouts
│   ├── _posts
│   ├── _sass
│   └── _site
│       ├── 2022
│       │   └── 03
│       │       └── 02
│       ├── 2024
│       │   └── 04
│       │       ├── 02
│       │       ├── 03
│       │       ├── 04
│       │       ├── 05
│       │       ├── 07
│       │       ├── 08
│       │       └── 24
│       └── assets
│           ├── css
│           ├── fonts
│           └── images
└── org
    └── _posts

When you run C-c C-e P x and select the project, what will happen is:

  1. Posts in the org/_posts/ directory will be converted to HTML, and only the text between the <body></body> tags will be kept. If you are using ox-gfm, then posts will be converted to Markdown instead.
  2. Any directory or file under org/ will be copied recursively to jekyll/.

Using ox-gfm to export Org -> Markdown

I have now discovered the ox-gfm package which contains a function org-gfm-publish-to-gfm which I can now use the publish the posts written in Org Mode to Markdown which Jekyll understands better.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
(require 'ox-gfm)
(setq org-publish-project-alist
      '(

        ("org-yaslamblog"
         ;; Path to your org files.
         :base-directory "~/myproject/org"
         :base-extension "org"

         ;; Path to your Jekyll project.
         :publishing-directory "~/myproject/jekyll/"
         :recursive t
         :publishing-function org-gfm-publish-to-gfm
         :headline-levels 4
         )


        ("org-static-yaslam"
         :base-directory "~/myproject/org/assets/img"
         :base-extension "css\\|js\\|png\\|jpg\\|gif\\|pdf\\|mp3\\|ogg\\|swf\\|php"
         :publishing-directory "~/myproject/jekyll/assets/img"
         :recursive t
         :publishing-function org-publish-attachment)

        ("yaslamblog" :components ("org-yaslamblog" "org-static-yaslam"))

        ))

I have now replaced org-html-publish-to-html with org-gfm-publish-to-gfm, and now it is exported to Markdown.

An issue with ox-html

An issue I had with using org-html-publish-to-html was that codeblocks where not looking right because Org Mode was injecting its own classname into the codeblock. Rouge (the syntax highlighter this blog uses) needs to inject its own classes and it did not work. But, now after exporting it straight to Github-flavoured Markdown using ox-gfm it works perfectly.

Automatic publishing

Another thing I’ve done is bind F7 to (org-publish "yaslamblog") so every time I press F7 the Org Mode file will be published:

1
(keymap-set org-mode-map "<f7>" (lambda () (interactive) (org-publish "yaslamblog")))

Another useful thing to do is automatically publish the project after saving the Org Mode post, so I added this to my ~/.emacs:

1
2
3
4
5
6
7
8
(defun my-after-save-actions ()
  "Used in `after-save-hook'."
  (when (memq this-command '(save-buffer save-some-buffers))
    (if (and (eq major-mode 'org-mode) (search "/home/yaslam/myproject/org/_posts" buffer-file-name))
        (org-publish "yaslamblog")
      )))

(add-hook 'after-save-hook 'my-after-save-actions)
  1. This first checks if the command was save-buffer or save-some-buffers as I do not want this to occur when Emacs auto-saves the buffer, only when I manually run save-buffer.

  2. Then it checks if the major-mode is org-mode, if that returns t it will:

  3. Check if buffer-file-name has /home/yaslam/myproject/org/_posts in the path, this is so that (org-publish "yaslamblog") doesn’t run on ANY Org Mode file.

  4. Then once all the above conditions are met, it runs (org-publish "yaslamblog").

  5. The last thing is to add the my-after-save-actions function to after-save-hook.

Writing Org-Mode posts outside of Emacs

If you try to write Org-Mode posts outside of Emacs, you do not have the ability to convert the pages into Markdown for Jekyll automatically like above. But there is a solution for this problem.

I have written a script which I have put in ~/myproject which runs Emacs in script mode to load the ox-gfm exporter and run the export tasks without ever needing to open Emacs. This also works through SSH.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#!/usr/bin/emacs --script

(load-file "~/.config/emacs/.local/straight/repos/ox-gfm/ox-gfm.el")

(require 'ox-gfm)
(setq org-publish-project-alist
      '(

	("org-yaslamblog"
         ;; Path to your org files.
         :base-directory "~/myproject/org"
         :base-extension "org"

         ;; Path to your Jekyll project.
         :publishing-directory "~/myproject/jekyll/"
         :recursive t
         :publishing-function org-gfm-publish-to-gfm
         :headline-levels 4
	 )


	("org-static-yaslam"
         :base-directory "~/myproject/org/assets/images"
         :base-extension "css\\|js\\|png\\|jpg\\|gif\\|pdf\\|mp3\\|ogg\\|swf\\|php"
         :publishing-directory "~/myproject/jekyll/assets/images"
         :recursive t
         :publishing-function org-publish-attachment)

	("yaslamblog" :components ("org-yaslamblog" "org-static-yaslam"))

	))

(progn (org-publish-project "yaslamblog") (kill-emacs))

This allows you to write posts in Org Mode using any text editor, and have them converted into Markdown for Jekyll.

This post is licensed under CC BY 4.0 by the author.