content overhaul for first post
[kengrimes.com/content.git] / content / ox-hugo-tutorial.md
diff --git a/content/ox-hugo-tutorial.md b/content/ox-hugo-tutorial.md
new file mode 100644 (file)
index 0000000..464212a
--- /dev/null
@@ -0,0 +1,656 @@
+---
+title: "Using ox-hugo To Build Websites with Emacs"
+author: ["Ken Grimes"]
+date: 2018-04-11T21:56:00-07:00
+tags: ["org", "emacs", "hugo"]
+categories: ["tutorial"]
+draft: false
+caption: "Exporting to Hugo's Blackfriday Markdown from Orgmode"
+header: "/img/org.png"
+---
+
+This article explains in detail the process of setting up a bare-bones website
+using Hugo and org-mode. My goal in writing this is to provide readers with a
+superior understanding of the fundamentals of this workflow. It is by no means
+an exhaustive explanation of org-mode or Emacs, but should give readers of any
+skill level a strong foundation to apply their own knowledge and techniques to
+the Emacs-Hugo toolchain.
+
+I assume only beginner-level knowledge of Emacs.
+
+
+# Intro & Setup {#intro-and-setup}
+
+[Kaushal Modi](https://github.com/kaushalmodi) made ox-hugo by extending org's ox-blackfriday package, providing
+an impressive amount of features for organizing blog text and linked data with
+Hugo. He maintains [great documentation](https://ox-hugo.scripter.co/) and ample [examples](https://github.com/kaushalmodi/ox-hugo/tree/master/test/site/content-org) for using the
+package. I will explain my own workflow here, but for an exhaustive (though
+terse) reference, I highly recommend Modi's [test site](https://ox-hugo.scripter.co/test/) and [post source](https://raw.githubusercontent.com/kaushalmodi/ox-hugo/master/test/site/content-org/all-posts.org) org file,
+which contain demonstrations and tests for all of ox-hugo's features.
+
+After issuing the Emacs command `M-x package-install RET ox-hugo RET`, you'll
+need to `require` it. You can do this by running `M-: (require 'ox-hugo)`, but
+you'll want to add it to your configuration as explained [here](https://ox-hugo.scripter.co/doc/usage/). Once this is
+done, using ox-hugo is just a matter of making an org file and writing
+content. Org's format is very straightforward, and is designed to make sense to
+the reader even if they're unfamiliar with the formal syntax. For instance,
+
+```org
+* My food
+| Where's My Food? | Fridge | Counter | Mouth | Total          |
+| Oranges          |      1 |       3 |     0 | :=vsum($2..$4) |
+| Marshmallows     |      0 |     100 |    20 | :=vsum($2..$4) |
+| Brussel Sprouts  |     32 |       4 |     0 | :=vsum($2..$4) |
+```
+
+Produces a dynamic spreadsheet table in org-mode that exports to HTML like this:
+
+
+## My food {#my-food}
+
+| Where's My Food? | Fridge | Counter | Mouth | Total |
+|------------------|--------|---------|-------|-------|
+| Oranges          | 1      | 3       | 0     | 4     |
+| Marshmallows     | 0      | 100     | 20    | 120   |
+| Brussel Sprouts  | 32     | 4       | 0     | 36    |
+
+If you're already familiar with org-mode, the benefits are obvious and creating
+content is fairly trivial. Org-mode is, however, a complex and expansive program
+with many features, and its learning curve can appear daunting at first glance.
+Using ox-hugo is a great way to learn the format, since it gives the author a
+command-center view of their entire content hierarchy, much like a traditional
+database, but in a flat format that's much easier to read and understand. Org
+features present themselves naturally, and the author can easily visualize the
+correspondence between the org format and the output on their webpage.
+
+Just take a look at the [org file](https://www.kengrimes.com/gitweb/?p=kengrimes.com/content.git;a=blob_plain;f=content.org;hb=HEAD) for this webpage. Search for "ox-hugo is super
+cool!" and you should find this very paragraph.
+
+Eventually you'll want to [read the manual](https://orgmode.org/manual/), though. You may access it in Emacs
+with `M-x org-info`.
+
+
+# Making a New Blog {#making-a-new-blog}
+
+Compared to a generic org file, the only important "extra" data that ox-hugo
+needs to properly export data is a `:PROPERTIES: ... :END:` block with
+definitions used for Hugo's [front matter](https://gohugo.io/content-management/front-matter/) (used for associating a title, header,
+or other custom data with the page it generates). `:PROPERTIES:` blocks are
+common in org for defining arbitrary metadata about sections, and can be used in
+many such ways. Providing an `:EXPORT_FILE_NAME:` definition signals to ox-hugo
+that this heading is available for export, and that it should be exported to a
+markdown file with the name provided.  For example, the `:PROPERTIES:` block of
+the page you're currently reading looks like this:
+
+```org
+:PROPERTIES:
+:EXPORT_FILE_NAME: ox-hugo
+:EXPORT_HUGO_CUSTOM_FRONT_MATTER: :caption "Exporting to Hugo's Blackfriday Markdown from Orgmode"
+:EXPORT_HUGO_CUSTOM_FRONT_MATTER+: :header /img/org.png
+:END:
+```
+
+The `:caption` and `:header` variables are optional definitions allowed by the
+Speedy theme of this website, but the filename is the only required property for
+ox-hugo. So, as a minimal example, here's what a new blog might look like in its
+entirety:
+
+{{< highlight org "linenos=table, linenostart=1" >}}
+#+hugo_base_dir: .
+* Home
+:PROPERTIES:
+:EXPORT_HUGO_SECTION:
+:EXPORT_FILE_NAME: _index
+:END:
+This is the home of my blog!
+** I have herpes
+:PROPERTIES:
+:EXPORT_FILE_NAME: herpes
+:END:
+Someone gave me herpes! Oh no!
+{{< /highlight >}}
+
+The org file can be placed in any directory so long as `HUGO_BASE_DIR` correctly
+identifies the Hugo project's root directory. This path definition is required
+for any valid ox-hugo file, and in the example above uses `.` as the base
+directory, which assumes that the file will be placed in the hugo project's base
+directory. If you saved this file as hugotest.org, exported it with org's
+exporter `C-c C-e` and selected the Hugo output `H` and the All Subtrees To
+Files option `A`, you'd wind up with the following files in your directory:
+
+```nil
+.
+├── content
+│   ├── _index.md
+│   └── herpes.md
+└── hugotest.org
+```
+
+Most sites will be more than a blog, though, and will want multiple sections. In
+fact, many sites are made up of nothing but a slew of sections that users
+navigate between with some built-in menu. So a more functional minimal example
+would be the following:
+
+{{< highlight org "linenos=table, linenostart=1" >}}
+#+hugo_base_dir: .
+* My Homepage
+:PROPERTIES:
+:EXPORT_HUGO_SECTION:
+:EXPORT_FILE_NAME: _index
+:EXPORT_HUGO_MENU: :menu "main"
+:END:
+This is the home of my blog!
+* My Blog
+:PROPERTIES:
+:EXPORT_HUGO_SECTION: posts
+:END:
+** My Blog Homepage
+:PROPERTIES:
+:EXPORT_HUGO_MENU: :menu "main"
+:EXPORT_FILE_NAME: _index
+:END:
+Man, look at all my blog posts.
+** I have herpes
+:PROPERTIES:
+:EXPORT_FILE_NAME: herpes
+:END:
+Someone gave me herpes! Oh no!
+{{< /highlight >}}
+
+Which yields the following:
+
+```nil
+.
+├── content
+│   ├── _index.md
+│   └── posts
+│       ├── herpes.md
+│       └── _index.md
+└── hugotest.org
+```
+
+As you might expect, this structure adheres to the Hugo [content management](https://gohugo.io/content-management/organization/)
+scheme. Additionally, the index files have been marked with menu metadata, which
+allows Hugo themes to automatically generate navigation menus from the markdown
+files. Hereafter, making new blog posts is as simple as adding new sub-headings
+under the "My Blog" heading, and exporting. As you can see, this is suitable for
+defining the hierarchical structure of any general website, not just
+blogs. Org-mode and Hugo just make creating new pages so simple and
+well-structured that providing content is all that's required for a new page,
+blog entry, or entirely new site section. If you can blog with ox-hugo, you can
+deftly deploy any manner of web content, or even develop entire websites as
+naturally as you make blog posts. Any tool that can turn blogging and web
+development into the same task is quite an achievement!
+
+Of course, themes to style this content are another can of worms entirely, but
+it is sufficient for now to mention that Hugo makes [using themes](https://gohugo.io/themes/installing-and-using-themes/) as easy as
+downloading one and specifying it in Hugo's config file.
+
+One question you may ask is why the blog's homepage is not defined in the **My
+Blog** heading. This is a fair question! Property blocks are inherited by
+sub-headings, and as of the current version of ox-hugo even `:EXPORT_HUGO_MENU:`
+properties are inherited. This might be intended by the content creator, but
+most likely you don't want every single post you make to be in the main menu. So
+it makes sense to define all your pages, including the index, as a sub-heading
+of the section definition (which specifies which sub-directory content will
+output to).
+
+To illustrate, let's assume you want to extend the previous site definition with
+a section about fishsticks.
+
+{{< highlight org "linenos=table, linenostart=24" >}}
+* Fishsticks
+:PROPERTIES:
+:EXPORT_HUGO_MENU: :menu "main"
+:EXPORT_HUGO_SECTION: fishsticks
+:EXPORT_FILE_NAME: _index
+:END:
+This section devoted to Orson Wells, R.I.P.
+** Van De Camps
+:PROPERTIES:
+:EXPORT_FILE_NAME: van-de-camps
+:END:
+If this is fish, I'll be a monkey's uncle.
+** Gortons
+:PROPERTIES:
+:EXPORT_FILE_NAME: gortons
+:END:
+I think these gave me the herpes.
+{{< /highlight >}}
+
+In this example, we've defined the main homepage of the section inside the
+tier-1 heading for Fishsticks. This is valid, and produces the expected file output:
+
+```nil
+.
+├── content
+│   ├── fishsticks
+│   │   ├── gortons.md
+│   │   ├── _index.md
+│   │   └── van-de-camps.md
+│   ├── _index.md
+│   └── posts
+│       ├── herpes.md
+│       └── _index.md
+└── hugotest.org
+```
+
+But on inspection of the gortons.md file, we find the anomoly mentioned above:
+
+{{< highlight markdown "linenos=table, linenostart=1" >}}
+---
+title: "Gortons"
+author: ["Ken Grimes"]
+draft: false
+menu:
+  main:
+    weight: 2002
+    identifier: "gortons"
+---
+
+I think these gave me the herpes.
+{{< /highlight >}}
+
+Uh oh! Not only did these fishsticks give us herpes, they are now part of the
+main menu. Tisk tisk. So if you use this workflow, be sure to put your index
+pages in subheadings so that the tier-1 heading can be used for "global"
+definitions that affect all of the pages.
+
+Another question might be why the index pages are named **\_index**. You can use
+**index** instead of **\_index**, the only difference is whether Hugo treats the
+index page as a leaf, or a branch, when [bundling resources](https://gohugo.io/content-management/page-bundles/) for Hugo to query
+during site generation. This is a relatively new addition to Hugo as of version
+0.39, and isn't fully functional or integrated well into ox-hugo, so I simply
+don't use it at the moment. I define all indexes as **\_index** to make them
+branches because, in future versions, packaging files within bundles like this
+will provide a more stable way for Hugo themes to reference page- and
+section-specific files that accompany the content. Currently, I store all such
+files in the static folder, which is copied verbatim to the output directory by
+Hugo when the site is built.
+
+
+# Hugo Setup {#hugo-setup}
+
+At this point, setting up Hugo and publishing is simple. [Installing](https://gohugo.io/getting-started/installing/) Hugo is
+pretty straightforward on any Unix-like system with a package manager; it is
+available on most distributions at this point. Windows installation is a bigger
+pain in the ass, but you should be used to that if you're still in the
+stone-age.
+
+Using `hugo new site .` on the command-line will create a new hugo site in the
+current directory, but `hugo` expects to be creating a new directory with this
+command and will complain if it already exists. It also provides the `--force`
+option to allow creating a new site in an extant directory, but this too will
+fail if the **content** subdirectory already exists (which ox-hugo will create
+when you export).
+
+So you have three choices:
+
+1.  run `hugo new site /path/to/some-new-dir` and move your org file to it
+2.  simply `rm -Rf content/` to remove the content directory ox-hugo created,
+    then run `hugo new site --force .`
+3.  don't even bother with the `hugo new site` command, and make a **config.toml**
+    file manually.
+
+It's convenient to do this through the `hugo` command because it will create
+Hugo-specific subdirectories like archetypes, layouts, themes, etcetera, in
+addition to populating a basic **config.toml** file. The subdirectories it creates
+aren't necessary, but help illustrate Hugo's structure. In any case, you'll want
+to wind up with a directory structure something like this (created with option 2
+above, extending from previous examples):
+
+```nil
+.
+├── archetypes
+│   └── default.md
+├── config.toml
+├── content
+├── data
+├── hugotest.org
+├── layouts
+├── static
+└── themes
+```
+
+Exporting with ox-hugo using `C-c C-e H A` again will, as expected, fill the
+content directory with our content.
+
+```nil
+.
+├── archetypes
+│   └── default.md
+├── config.toml
+├── content
+│   ├── fishsticks
+│   │   ├── gortons.md
+│   │   ├── _index.md
+│   │   └── van-de-camps.md
+│   ├── _index.md
+│   └── posts
+│       ├── herpes.md
+│       └── _index.md
+├── data
+├── hugotest.org
+├── layouts
+├── static
+└── themes
+```
+
+Now, running the command `hugo` with no subcommands will invoke the Hugo
+generator on the current directory, and output finalized content in the
+**public/** directory.
+
+```nil
+.
+├── archetypes
+│   └── default.md
+├── config.toml
+├── content
+│   ├── fishsticks
+│   │   ├── gortons.md
+│   │   ├── _index.md
+│   │   └── van-de-camps.md
+│   ├── _index.md
+│   └── posts
+│       ├── herpes.md
+│       └── _index.md
+├── data
+├── hugotest.org
+├── layouts
+├── public
+│   ├── categories
+│   │   └── index.xml
+│   ├── fishsticks
+│   │   └── index.xml
+│   ├── index.xml
+│   ├── posts
+│   │   └── index.xml
+│   ├── sitemap.xml
+│   └── tags
+│       └── index.xml
+├── static
+└── themes
+```
+
+Hugo, by default, generates xml files that are suitable for RSS feeds. With a
+theme installed, Hugo will produce more suitable web content (usually
+HTML). You'll notice from this default output however that Hugo creates a
+sitemap, and two directories for [taxonomies](https://gohugo.io/content-management/taxonomies/) that let you "tag" and "categorize"
+content. The taxonomy index pages allow users to browse content by category or
+tag. These taxonomies correspond to org-mode tags, and ox-hugo will
+automatically associated tagged headings with the tags taxonomy, or the
+categories taxonomy if prefixed with an @ symbol. You are free to define your
+own taxonomies, and even disable the default "tags" and "categories" taxonomies,
+but since org-mode tags directly translate to the default Hugo taxonomies, it
+makes sense to just use the default taxonomies for now.
+
+
+# Example Hugo Site {#example-hugo-site}
+
+As an example, let's add some tags and categories to our **hugotest.org** file:
+
+{{< highlight org "linenos=table, linenostart=1" >}}
+#+hugo_base_dir: .
+* My Homepage
+:PROPERTIES:
+:EXPORT_HUGO_SECTION:
+:EXPORT_FILE_NAME: _index
+:EXPORT_HUGO_MENU: :menu "main"
+:END:
+This is the home of my blog!
+* My Blog
+:PROPERTIES:
+:EXPORT_HUGO_SECTION: posts
+:END:
+** My Blog Homepage
+:PROPERTIES:
+:EXPORT_HUGO_MENU: :menu "main"
+:EXPORT_FILE_NAME: _index
+:END:
+Man, look at all my blog posts.
+** I have herpes   :@inanity:herpes:fear:
+:PROPERTIES:
+:EXPORT_FILE_NAME: herpes
+:END:
+Someone gave me herpes! Oh no!
+* Fishsticks
+:PROPERTIES:
+:EXPORT_HUGO_MENU: :menu "main"
+:EXPORT_HUGO_SECTION: fishsticks
+:EXPORT_FILE_NAME: _index
+:END:
+This section devoted to Orson Wells, R.I.P.
+** Van De Camps   :@inanity:
+:PROPERTIES:
+:EXPORT_FILE_NAME: van-de-camps
+:END:
+If this is fish, I'll be a monkey's uncle.
+** Gortons        :@inanity:herpes:
+:PROPERTIES:
+:EXPORT_FILE_NAME: gortons
+:END:
+I think these gave me the herpes.
+{{< /highlight >}}
+
+Exporting **hugotest.org** with `C-c C-e H A` and generate with `hugo` will yield
+the same file structure as before, but this time we'll see that the categories
+and tags directories have sections for our newly added tags.
+
+```nil
+.
+├── archetypes
+│   └── default.md
+├── config.toml
+├── content
+│   ├── fishsticks
+│   │   ├── gortons.md
+│   │   ├── _index.md
+│   │   └── van-de-camps.md
+│   └── posts
+│       └── herpes.md
+├── data
+├── hugotest.org
+├── layouts
+├── public
+│   ├── categories
+│   │   ├── inanity
+│   │   │   └── index.xml
+│   │   └── index.xml
+│   ├── fishsticks
+│   │   └── index.xml
+│   ├── index.xml
+│   ├── posts
+│   │   └── index.xml
+│   ├── sitemap.xml
+│   └── tags
+│       ├── fear
+│       │   └── index.xml
+│       ├── herpes
+│       │   └── index.xml
+│       └── index.xml
+├── static
+└── themes
+```
+
+The index pages of taxonomies provide a list of all available taxonomies of that
+type, with links to lists that show content associated with that taxonomy. For
+instance, public/tags/index.xml looks like this:
+
+{{< highlight xml "linenos=table, linenostart=1" >}}
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
+  <channel>
+    <title>Tags on My New Hugo Site</title>
+    <link>http://example.org/tags/</link>
+    <description>Recent content in Tags on My New Hugo Site</description>
+    <generator>Hugo -- gohugo.io</generator>
+    <language>en-us</language>
+
+       <atom:link href="http://example.org/tags/index.xml" rel="self" type="application/rss+xml" />
+
+
+    <item>
+      <title>Fear</title>
+      <link>http://example.org/tags/fear/</link>
+      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
+
+      <guid>http://example.org/tags/fear/</guid>
+      <description></description>
+    </item>
+
+    <item>
+      <title>Herpes</title>
+      <link>http://example.org/tags/herpes/</link>
+      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
+
+      <guid>http://example.org/tags/herpes/</guid>
+      <description></description>
+    </item>
+
+  </channel>
+</rss>
+{{< /highlight >}}
+
+And public/tags/fear/index.xml looks like this:
+
+{{< highlight xml "linenos=table, linenostart=1" >}}
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
+  <channel>
+    <title>Fear on My New Hugo Site</title>
+    <link>http://example.org/tags/fear/</link>
+    <description>Recent content in Fear on My New Hugo Site</description>
+    <generator>Hugo -- gohugo.io</generator>
+    <language>en-us</language>
+
+       <atom:link href="http://example.org/tags/fear/index.xml" rel="self" type="application/rss+xml" />
+
+
+    <item>
+      <title>I have herpes</title>
+      <link>http://example.org/posts/herpes/</link>
+      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
+
+      <guid>http://example.org/posts/herpes/</guid>
+      <description>Someone gave me herpes! Oh no!</description>
+    </item>
+
+    <item>
+      <title>Van De Camps</title>
+      <link>http://example.org/fishsticks/van-de-camps/</link>
+      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
+
+      <guid>http://example.org/fishsticks/van-de-camps/</guid>
+      <description>If this is fish, I&amp;rsquo;ll be a monkey&amp;rsquo;s uncle.</description>
+    </item>
+
+  </channel>
+</rss>
+{{< /highlight >}}
+
+This allows themes to easily build navigation pages for browsing or querying
+taxonomies. Files like these are often useful to output as JSON (done by the
+theme) to allow Javascript-driven dynamic search features, but a simpler scheme
+can output HTML pages to browse taxonomies just as you would posts in a section
+(i.e. org-mode heading).
+
+
+## Theming {#theming}
+
+The last thing to do here is to download or create a theme for Hugo. As
+mentioned before, installing a theme is very simple. This blog uses a custom
+theme named Speedy that I have been developing to help myself learn Hugo's
+internals, but for this example I'll be using Kaushal Modi's [bare-min theme](https://github.com/kaushalmodi/hugo-bare-min-theme). The
+bare-min theme is the best starting place out there for making new themes, and
+outputs basic HTML pages without any need to mess with CSS or JS. It also
+provides easy debugging facilities and search features.
+
+We'll just install it and generate the site again. You can download the theme
+from its github page and extract it to the themes folder, or much more easily
+use git to clone it to your themes directory.
+`git clone https://github.com/kaushalmodi/hugo-bare-min-theme.git themes/bare-min`
+Then open up your **config.toml** file, and add the theme.
+
+{{< highlight toml "linenos=table, linenostart=1" >}}
+baseURL = "http://example.org/"
+languageCode = "en-us"
+title = "My New Hugo Site"
+# Adding a theme:
+theme = "bare-min"
+{{< /highlight >}}
+
+Be sure that the theme's name matches the theme directory's name in the themes/
+directory of your project base directory. (e.g. themes/bare-min here).
+
+That's it for installing the theme. Just run `hugo` again, and behold your output:
+
+```nil
+.
+└── public
+    ├── categories
+    │   ├── inanity
+    │   │   ├── index.html
+    │   │   └── index.xml
+    │   ├── index.html
+    │   └── index.xml
+    ├── css
+    │   └── github_chroma.css
+    ├── fishsticks
+    │   ├── gortons
+    │   │   └── index.html
+    │   ├── index.html
+    │   ├── index.xml
+    │   └── van-de-camps
+    │       └── index.html
+    ├── index.html
+    ├── index.xml
+    ├── js
+    │   └── search.js
+    ├── page
+    │   └── 1
+    │       └── index.html
+    ├── posts
+    │   ├── herpes
+    │   │   └── index.html
+    │   ├── index.html
+    │   └── index.xml
+    ├── sitemap.xml
+    └── tags
+        ├── fear
+        │   ├── index.html
+        │   └── index.xml
+        ├── herpes
+        │   ├── index.html
+        │   └── index.xml
+        ├── index.html
+        └── index.xml
+```
+
+The bare-min theme outputs HTML, provides CSS for doing chroma-based syntax
+highlighting (in case you include code blocks), and inline styles for basic
+page formatting. Generated pages also have a lot of useful debugging information.
+
+You can now serve the **public/** directory over an HTTP server. Hugo is packaged
+with an internal [HTTP server](https://gohugo.io/commands/hugo_server/) to help with testing, which is quite convenient
+because it can automatically refresh whenever content in its content directory
+is updated (so when you export from ox-hugo, you don't have to run `hugo`
+again). To use it, simply run `hugo server` and point your browser at
+<http://localhost:1313> (1313 is the default `--port` argument for `hugo server`).
+
+Eventually you'll want to move on to other themes, or develop your own, but at
+this point you've got a fully functional blog publishing workflow from start to
+finish.
+
+
+# Attaching Files, Capturing Information & Automation {#attaching-files-capturing-information-and-automation}
+
+Once you have a basic site structured in your org file, you're ready to start
+throwing information in it. It is of course sufficient to open the org file and
+edit it, but most org-mode users prefer to automate _everything_, and being able
+to use org's capture feature to instantly populate new blog posts is extremely
+convenient.
+
+The [ox-hugo documentation](https://ox-hugo.scripter.co/) provides succinct explanations on how to do this,
+including elisp snippets for [capture setup](https://ox-hugo.scripter.co/doc/org-capture-setup/), [image linking](https://ox-hugo.scripter.co/doc/images-in-content/), and [automating
+exports](https://ox-hugo.scripter.co/doc/auto-export-on-saving/) when you save your org file (so no more need to `C-c C-e H A` every
+time, just save the file as usual with `C-x C-s`).