Skip to content

Latest commit

 

History

History
586 lines (545 loc) · 29.9 KB

ox-hugo-manual.org

File metadata and controls

586 lines (545 loc) · 29.9 KB

Ox-Hugo Manual

ox-hugo is an Emacs package to export Org files to Hugo-compatible Markdown files. At the moment it supports only the Blackfriday Markdown flavor.

Hugo specific export settings

Mandatory settings

HUGO_SECTION
The default Hugo section name for all the posts. See here for more information on Hugo sections. It is common for this property to be set to posts or blog.
HUGO_BASE_DIR
Root directory of the source for the Hugo site. If this is set to ~/hugo/, the exported Markdown files will be saved to ~/hugo/content/<HUGO_SECTION>/ directory. By default, the Markdown files reside in a hierarchy under the content/ directory in the site root directory.

Changelog

0.1.1

  • Use CLOSED log drawer info if available to set the date in front-matter {{{issue(68)}}}.
  • Code optimization: Use of org-entry-get at places instead of maintaining global variables.

0.1.2

  • Make DateTime matching better; new internal variable org-hugo--date-time-regexp. Earlier time zones ahead of UTC (with + sign) were not detected as dates in org-hugo--quote-string and thus were unnecessarily quoted.

Note to Future Contributors

NOTE TO FUTURE CONTRIBUTORS: I plan to merge this package into GNU Elpa or Org source at some point.

So you will need to assign your copyright to FSF in order to get your patches accepted.

As a bonus, once you have assigned your copyright to FSF, doors open up for your future contributions to Emacs too!

Debug

If the ox-hugo exports do not work as expected, or if you get an error backtrace,
  1. Open an Issue.
  2. Describe the problem you are seeing.
  3. Provide the debug info using org-hugo-debug-info:
    • M-x org-hugo-debug-info (that will copy the debug info in Markdown format to the kill ring)
    • Paste the Markdown contents in the GitHub issue.
      • You can still hit the Preview tab of the Issue before submitting it.

Readme

{{{GPLv3}}} {{{melpa}}}

ox-hugo is an Org exporter backend that exports Org to Hugo-compatible Markdown (Blackfriday) and also generates the front-matter (in TOML or YAML format).

This project consists of ox-blackfriday.el too. It is a derivation of =ox-gfm= with support added for Blackfriday Markdown tables and many other tweaks. ox-hugo backend extends from this.

There are 2 major blogging flows that can be used with this package:

  1. One post per Org subtree (preferred)
    • Export only the current post Org subtree, or
    • Export all valid Hugo post subtrees in a loop.
  2. One post per Org file
    • This works but you won’t be able to leverage Org-specific benefits like tag and property inheritance, use of TODO states to translate to post draft state, auto weight calculation for posts and menu items, etc.

See the Org Capture Setup Wiki page to see how to quickly create new posts.

See the Auto-export on Saving Wiki page to learn how to setup up seeing live-preview of the Hugo-rendered HTML each time you do C-x C-s in the Org file — For now, this works only with the Subtree export flow.

Before you read further, you can see below how ox-hugo translates Org to Markdown (Org on the left; exported Markdown with Hugo front-matter on the right).

One post per Org subtree –

One post per Org file –

Why ox-hugo?

Using Org just as a markup like Markdown is a miniscule part of its complete feature-set. Org also allows stuff like:
  • Easy ordering/manipulation/commenting of subtrees
  • Creating tables (with even formulas like in Excel)
  • Directly including source code snippets from external files (instead of having to copy/paste them in)
  • Running code snippets within the Org file and embedding the results (Org Babel)
  • ..

Using Org for content writing allows using in-built Org features to translate to Hugo front-matter:

  • Org uses an outline structure and can inherit meta data (tags and properties) from one subtree to children subtrees.
  • Using that feature, one can tag one tree as emacs, and everything under that tree (all posts under that) will get that tag automatically.
  • The same concept applies to inheriting any Org property meta data like menu entry, category, section name, etc.
  • A subtree can be quickly marked to be in TODO state (default binding C-c C-t). A TODO post is marked as a draft Hugo post.
  • The menu-item weights and/or post weights can be set to be auto-calculated so that the menu items or post order in the final HTML appear in the same order as the respective subtrees in Org.

    If the subtrees are re-ordered in Org, the weights get changed too.

  • One can have a subtree with section property set to “posts” and all post subtrees under that will go to that section. Similarly another parent subtree can have that property set to “articles”, and so on.
  • Images can be displayed inline in the Org buffer.
  • After save hooks can be set up in Emacs so that each time I save the file, only the current subtree in Org gets exported to Markdown. With the Hugo server running with the new switch that auto changes the preview to the last changed post (--navigateToChanged introduced in Hugo 0.25), the flow is seamless – Save the Org file and see the exact changed post in browser.
  • All posts can simply be subtrees in a single Org file. That way one can take advantage of Org subtree filtering and searching functions (org-sparse-tree bound to C-c / by default).
  • (and much more..)

Installation

This package requires emacs 24.5+ and Org 9.0+. It is available on Melpa.

Usage

Once the package is installed, you will need to require it so that the ox-hugo export options are available in the Org Export Dispatcher menu (the one you see when you hit C-c C-e to initiate any export).

You can do that by adding the below to your config:

(with-eval-after-load 'ox
  (require 'ox-hugo))

If you use use-package, you can do the below instead:

(use-package ox-hugo
  :after ox)

Before you export

Before you export check that these properties are set as you need:

HUGO_SECTION
The default Hugo section name for all the posts. See here for more information on Hugo sections. It is common for this property to be set to posts or blog. The default value is set using org-hugo-default-section-directory.
HUGO_BASE_DIR
Root directory of the source for the Hugo site. If this is set to ~/hugo/, the exported Markdown files will be saved to ~/hugo/content/<HUGO_SECTION>/ directory. By default, the Markdown files reside in a hierarchy under the content/ directory in the site root directory (ref). If you try to export without setting this property, you will get this error:
user-error: It is mandatory to set the HUGO_BASE_DIR property
    

Important: If you choose to export an Org subtree as a post, you need to set the EXPORT_FILE_NAME subtree property. That property is used by this package to figure out where the current post starts.

Export bindings

The common ox-hugo export bindings are:

BindingDescription
C-c C-e H HExport only the current valid subtree (has the EXPORT_FILE_NAME property set)
C-c C-e H AExport all valid subtrees (those that have the EXPORT_FILE_NAME property set)
C-c C-e H hExport the whole Org file to a single post

Example Hugo site to test this package

An example-site with bare-bones “theme” is used to live-test the package — you’ll know why theme is double-quoted once you try out the example-site on hugo.

Check out the example single Org file. That is created for testing various Org->Hugo content and meta-data translation features. Here are the exported Markdown files.

How to try ox-hugo on that site?

  1. Clone this repo.
  2. cd to the example-site/ directory and do:
    hugo server -D --navigateToChanged
        
    • --navigateToChanged requires Hugo 0.25+.
  3. Above command will mention the localhost where the site is served. Open that in your browser.
  4. In emacs, (require 'ox-hugo) or evaluate the ox-hugo.el from the cloned repo.
  5. Open the =all-posts.org= file.
  6. C-c C-e H A – That will export all subtrees in the file to Markdown files.
  7. In few seconds, dozens of test posts will get created, with the hugo server aided preview in the browser zapping through each new created post (needs that new feature --navigateToChanged introduced in Hugo 0.25).

How do I try ox-hugo on my site?

  1. cd to your Hugo site base directory – the one that contains the config.toml (or config.yaml or config.json).
  2. Start the hugo server in that directory:
    hugo server -D --navigateToChanged
        
    • --navigateToChanged requires Hugo 0.25+.
  3. Above command will mention the localhost where the site is served. Open that in your browser.
  4. Create a separate directory for Org content in the Hugo site base directory. You can name it anything, but I prefer to name it content-org (Example 1 – ox-hugo example site, Example 2 – My blog).
  5. Create an Org file in there and follow the Usage section in the README or Wiki to export it.

Translation of Org meta-data to Hugo front-matter

For subtree exports (C-c C-e H H or C-c C-e H A)

When organizing the posts as Org subtrees, many Hugo front-matter variables get set implicitly using the meta-data parsed from the posts in Org.

Below, where subtree is mentioned, it implies a valid Hugo-post subtree i.e. an Org subtree that has the EXPORT_FILE_NAME property set.

Hugo front-matter (TOML)OrgOrg description
title = "foo"​* fooSubtree heading
date = 2017-09-11T14:32:00-04:00CLOSED: [2017-09-11 Mon 14:32]Auto-inserted CLOSED subtree property when switch to Org DONE state
date = 2017-07-24:EXPORT_DATE: 2017-07-24Subtree property
lastmod = <current date>:EXPORT_HUGO_AUTO_SET_LASTMOD: tSubtree property
lastmod = <current date>#+HUGO_AUTO_SET_LASTMOD: tOrg keyword
tags = ["abc", "def"]* foo :abc:def:Subtree heading tags
categories = ["x", "y"]* foo :@x:@y:Subtree heading tags with @ prefix
draft = true* TODO fooSubtree heading Org Todo state set to TODO (or DRAFT)
draft = false* fooSubtree heading Org Todo state not set to TODO (or DRAFT)
weight = 123:EXPORT_HUGO_WEIGHT: autoWhen set to auto, weight is auto-calculated
weight = 123 (in [menu.foo]):EXPORT_HUGO_MENU: :menu fooMenu weight is auto-calculated unless specified

Notes

  • Precedence for date parsing: CLOSED subtree property more than EXPORT_DATE subtree property more than #+DATE: keyword.

For complete-file exports (C-c C-e H h)

Hugo front-matter (TOML)Org
title = "foo"​#+TITLE: foo
date = 2017-07-24#+DATE: 2017-07-24
lastmod = <current date>#+HUGO_AUTO_SET_LASTMOD: t
tags = ["abc", "def"]#+HUGO_TAGS: abc def
categories = ["x", "y"]#+HUGO_CATEGORIES: x y
draft = true#+HUGO_DRAFT: true
draft = false#+HUGO_DRAFT: false (default)
weight = 123#+HUGO_WEIGHT: 123
weight = 123 (in [menu.foo])#+HUGO_MENU: :menu foo :weight 123

Notes

  • The auto weight calculation for posts and menu items works only for subtree exports. For the complete-file export flow, one needs to specify the weights manually if needed.

Formatting

Below table shows the translation of Org markup to Markdown markup in the exported .md files.

See the Org source in =all-posts.org= under Formatting -> General heading and how it exports to Markdown in =general-formatting.md=.

OrgMarkdown
*bold***bold**
/italics/_italics_
==monospace==`monospace`
~key-binding~<kbd>key-binding</kbd>
- if org-hugo-use-code-for-kbd is non-nil [default]
- Requires CSS to render the <kbd> tag as something special.
~key-binding~`key-binding`
- if org-hugo-use-code-for-kbd is nil
+strike-through+~~strike-through~~
_underline_<span class = "underline">underline</span>
- Requires CSS to render this underline class as an underline.

(Note: If you see two equal signs on each side of monospace in the Org column in the table above, it is a bug with GitHub’s Org renderer.. just see those as single equal signs on each side of monospace instead.)

Do I need to re-write my whole blog in Org?

If you are considering to try out ox-hugo, and if you have already been using Hugo, it is normal for this thought to cross your mind:

I already have dozens or hundreds of posts written in Markdown. Do I need to convert them to Org if I want to start using ox-hugo?

The answer is No.

This package will export your future posts written in Org to Markdown. And those files will live along with your already written Markdown posts. So converting existing Markdown files to Org would be purely the user’s choice, your choice – but that’s by no means a necessity if you want to start using ox-hugo.

.. And if at some point, you want to stop using ox-hugo, you still have the exported Markdown files.

Changelog

Debug

Future Plans

There is a plan to create a hugo.el that would do things like:

  • New post creation using org-capture (port code from here).
  • Interactive functions to toggle draft state, add/remove/increment/decrement publishdate property.
  • Option to use template config.toml and some default hugo theme. So all a new user would need to do is to (i) have the hugo binary in PATH (ii) define their hugo blog dir in the defcustom (iii) M-x hugo.
  • Set separate faces for titles based on draft state and futureness.

Thanks

Contributing

Debug

Other Wikis

Home

This project in unique in the sense that all documentation you see in this repo is built from doc/ox-hugo-manual.org file. That includes the README.org, CONTRIBUTING.org, and these Wiki pages.

These are generated by running M-x ox-hugo-export-gh-doc defined in doc/export-gh-doc.el. Before running that, you would need to:

cd doc/
git clone https://github.com/kaushalmodi/ox-hugo.wiki.git

If changes are only to this Wiki, I believe you can push them directly using git or manually edit those here.

Screenshots

One post per Org subtree (preferred)

https://raw.githubusercontent.com/kaushalmodi/ox-hugo/master/doc/images/one-post-per-subtree.png
Files in above screenshot
Org -> Markdown

One post per Org file

https://raw.githubusercontent.com/kaushalmodi/ox-hugo/master/doc/images/one-post-per-file.png
Files in above screenshot
Org -> Markdown

Editorial

The preferred way to organize the posts is as Org subtrees (also the main reason to write this package, as nothing like that was out there) as it makes the meta-data management for Hugo front-matter pretty effortless.

If you are a one Org-file per post type of a person, that flow works too! Just note that in this flow many of those #+HUGO_ properties need to be managed manually.. just as one would manage the front-matter in Markdown files — See the Org versions in the above screenshots for comparison.

Org Capture Setup

If you do not want to manually type the EXPORT_FILE_NAME and EXPORT_DATE for each new post, here is an example org-capture setup can help:
(with-eval-after-load 'org-capture
  (defun org-hugo-new-subtree-post-capture-template ()
    "Returns `org-capture' template string for new Hugo post.
See `org-capture-templates' for more information."
    (let* (;; http://www.holgerschurig.de/en/emacs-blog-from-org-to-hugo/
           (date (format-time-string (org-time-stamp-format :long :inactive) (org-current-time)))
           (title (read-from-minibuffer "Post Title: ")) ;Prompt to enter the post title
           (fname (org-hugo-slug title)))
      (mapconcat #'identity
                 `(
                   ,(concat "* TODO " title)
                   ":PROPERTIES:"
                   ,(concat ":EXPORT_FILE_NAME: " fname)
                   ,(concat ":EXPORT_DATE: " date) ;Enter current date and time
                   ":END:"
                   "%?\n")          ;Place the cursor here finally
                 "\n")))

  (add-to-list 'org-capture-templates
               '("h"                ;`org-capture' binding + h
                 "Hugo post"
                 entry
                 ;; It is assumed that below file is present in `org-directory'
                 ;; and that it has a "Blog Ideas" heading. It can even be a
                 ;; symlink pointing to the actual location of all-posts.org!
                 (file+olp "all-posts.org" "Blog Ideas")
                 (function org-hugo-new-subtree-post-capture-template))))

Auto-export on Saving

Wouldn’t it be awesome if you can see the live-preview of your Hugo-rendered post each time you saved your post in Org?

Well.. you can do that with these steps, though, this works only with subtree-export flow at the moment.

First time setup

Step 1: Set up the after-save-hook

  1. Add below to the very-end of your posts Org file:
    * Footnotes
    * COMMENT Local Variables                                           :ARCHIVE:
    # Local Variables:
    # eval: (add-hook 'after-save-hook #'org-hugo-export-subtree-to-md-after-save :append :local)
    # End:
        

    Here I recommend adding the * Footnotes header too so that in case you add any Org footnotes, they go directly to that section you created. Otherwise, in the absence of an existing Footnotes heading, Org would create a new Footnotes heading at the end of the file – so the Local Variables heading will then no longer be at the end of the file.

  2. Then save the file, and do revert-buffer.
  3. You will be prompted to add that eval line to your Customize setup, hit ! to permanently save that setting and prevent future prompts.

Step 2: Prevent auto-export during Org Capture

You might find this step useful if you choose to write new posts using org-capture as explained in the Org Capture Setup Wiki page.

After saving the below to your emacs config and evaluating it, auto-exports will be prevented when saving a new post created using Org Capture.

(with-eval-after-load 'org-capture
  ;; Do not cause auto Org->Hugo export to happen when saving captures
  (defun modi/org-capture--remove-auto-org-to-hugo-export-maybe ()
    "Function for `org-capture-before-finalize-hook'.
Disable `org-hugo-export-subtree-to-md-after-save'."
    (setq org-hugo-allow-export-after-save nil))

  (defun modi/org-capture--add-auto-org-to-hugo-export-maybe ()
    "Function for `org-capture-after-finalize-hook'.
Enable `org-hugo-export-subtree-to-md-after-save'."
    (setq org-hugo-allow-export-after-save t))

  (add-hook 'org-capture-before-finalize-hook #'modi/org-capture--remove-auto-org-to-hugo-export-maybe)
  (add-hook 'org-capture-after-finalize-hook #'modi/org-capture--add-auto-org-to-hugo-export-maybe))

Steps that might need to be taken every time

Step 3: Start the engines (Hugo Server)

We start the hugo server so that we can see the live-preview each time the Org file is saved.

I recommend using Hugo version 0.25 at the minimum as that added support for the awesome --navigateToChanged switch!

Run below in your Hugo site root (the directory that contains the site config.toml) to start the server:

hugo server -D --navigateToChanged

Step 4: Open your browser

By default the site is served locally on port 1313 on localhost. So the above step would have printed something like below at the end:

Web Server is available at http://localhost:1313/ (bind address 127.0.0.1)

So open your favorite browser pointing to that address.

FINAL step that needs to be taken every time

If you are like me, you might not need to repeat steps 3 and 4 above, as you can leave the hugo server running in a separate terminal, and have a browser tab pinned to that localhost.

So with that, have the emacs and browser frames set up side-by-side, and edit your Org post.

Hit C-x C-s and be in awe as the browser auto-refreshes to the exact post you modified!

Contributing Guide