ox-hugo tutorial updates, theme updated with EXPORT_DESCRIPTION instead of custom...
[kengrimes.com/content.git] / content / ox-hugo-tutorial.md
1 ---
2 title: "Using ox-hugo To Build Websites with Emacs"
3 author: ["Ken Grimes"]
4 date: 2018-04-19T18:06:00-07:00
5 tags: ["org", "emacs", "hugo"]
6 categories: ["tutorial"]
7 draft: false
8 header: "/img/org.png"
9 ---
10
11 This article explains in detail the process of setting up a bare-bones website
12 using Hugo and Org mode. My goal in writing this is to provide readers with a
13 superior understanding of the fundamentals of this workflow. It is by no means
14 an exhaustive explanation of Org mode or Emacs, but should give readers of any
15 skill level a strong foundation to apply their own knowledge and techniques to
16 the Emacs-Hugo toolchain.
17
18 I assume only beginner-level knowledge of Emacs.
19
20
21 # Intro & Setup {#intro-and-setup}
22
23 [Kaushal Modi](https://github.com/kaushalmodi) created ox-hugo on top of his ox-blackfriday package, providing an
24 impressive amount of features for organizing blog text and linked data with
25 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
26 package. I will explain my own workflow here, but for an exhaustive (though
27 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,
28 which contain demonstrations and tests for all of ox-hugo's features.
29
30 After issuing the Emacs command `M-x package-install RET ox-hugo RET`, you'll
31 need to `require` it. You can do this by running `M-: (require 'ox-hugo)`, but
32 you'll want to add it to your configuration as explained [here](https://ox-hugo.scripter.co/doc/usage/). Once this is
33 done, using ox-hugo is just a matter of making an Org file and writing
34 content. Org's format is very straightforward, and is designed to make sense to
35 the reader even if they're unfamiliar with the formal syntax. For instance,
36
37 ```org
38 * My food
39 | Where's My Food? | Fridge | Counter | Mouth | Total |
40 | Oranges | 1 | 3 | 0 | :=vsum($2..$4) |
41 | Marshmallows | 0 | 100 | 20 | :=vsum($2..$4) |
42 | Brussel Sprouts | 32 | 4 | 0 | :=vsum($2..$4) |
43 ```
44
45 Produces a dynamic spreadsheet table in Org mode that exports to HTML like this:
46
47
48 ## My food {#my-food}
49
50 | Where's My Food? | Fridge | Counter | Mouth | Total |
51 |------------------|--------|---------|-------|-------|
52 | Oranges | 1 | 3 | 0 | 4 |
53 | Marshmallows | 0 | 100 | 20 | 120 |
54 | Brussel Sprouts | 32 | 4 | 0 | 36 |
55
56 If you're already familiar with Org mode, the benefits are obvious and creating
57 content is fairly trivial. Org mode is, however, a complex and expansive program
58 with many features, and its learning curve can appear daunting at first glance.
59 Using ox-hugo is a great way to learn the format, since it gives the author a
60 command-center view of their entire content hierarchy, much like a traditional
61 database, but in a flat format that's much easier to read and understand. Org
62 features present themselves naturally, and the author can easily visualize the
63 correspondence between the Org format and the output on their webpage.
64
65 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
66 cool!" and you should find this very paragraph.
67
68 Eventually you'll want to [read the manual](https://orgmode.org/manual/), though. You may access it in Emacs
69 with `M-x org-info`.
70
71
72 # Making a New Blog {#making-a-new-blog}
73
74 Compared to a generic Org file, the only necessary data that ox-hugo needs to
75 properly export to Hugo is an `:EXPORT_FILE_NAME:` property in the
76 `:PROPERTIES:` block of an Org heading. `:PROPERTIES:` blocks are common in Org
77 for defining arbitrary metadata about sections, and ox-hugo uses them to
78 generate Hugo's [front matter](https://gohugo.io/content-management/front-matter/) (used for associating a title, header, or other
79 custom data with the page it generates). Providing an `:EXPORT_FILE_NAME:`
80 definition signals to ox-hugo that a particular heading is available for export
81 to Hugo. For example, the `:PROPERTIES:` block of the page you're currently
82 reading looks like this:
83
84 ```org
85 :PROPERTIES:
86 :EXPORT_FILE_NAME: ox-hugo-tutorial
87 :EXPORT_DESCRIPTION: Exporting to Hugo's Blackfriday Markdown from Orgmode
88 :EXPORT_HUGO_IMAGES: /img/org.png
89 :END:
90 ```
91
92 The `:EXPORT_HUGO_IMAGES:` and `:EXPORT_DESCRIPTION:` variables are optional
93 definitions allowed by the Speedy theme of this website, but the filename is the
94 only required property for ox-hugo. Our goal here is to organize the structure
95 of our website as a tree using Org headers. So, as a minimal example, here's
96 what a new site might look like in its entirety:
97
98 {{< highlight org "linenos=table, linenostart=1" >}}
99 #+hugo_base_dir: .
100 * My Blog
101 :PROPERTIES:
102 :EXPORT_HUGO_SECTION:
103 :END:
104 ** Home
105 :PROPERTIES:
106 :EXPORT_FILE_NAME: _index
107 :END:
108 This is the home of my blog!
109 ** One Bad Night
110 :PROPERTIES:
111 :EXPORT_FILE_NAME: bad-night
112 :END:
113 Someone gave me herpes! Oh no!
114 {{< /highlight >}}
115
116 The Org file can be placed in any directory so long as `HUGO_BASE_DIR` correctly
117 identifies the Hugo project's root directory. This path definition is required
118 for any valid ox-hugo file, and in the example above uses `#+hugo_base_dir: .`
119 to specify that the base directory will be the same path as this Org file. If
120 you saved this file as hugotest.org, exported it with Org's exporter `C-c C-e`
121 and selected the Hugo output `H` and the All Subtrees To Files option `A`, you'd
122 wind up with the following files in your directory:
123
124 ```nil
125 .
126 ├── content
127 │   ├── bad-night.md
128 │   └── _index.md
129 └── hugotest.org
130 ```
131
132 Most sites will be more than a blog, though, and will want multiple sections. In
133 fact, many sites are made up of nothing but a slew of sections that users
134 navigate between with some built-in menu. So a more functional minimal example
135 would be the following:
136
137 {{< highlight org "linenos=table, linenostart=1" >}}
138 #+hugo_base_dir: .
139 * Homepage
140 :PROPERTIES:
141 :EXPORT_HUGO_SECTION:
142 :EXPORT_FILE_NAME: _index
143 :EXPORT_HUGO_MENU: :menu "main"
144 :END:
145 This is the home of my blog!
146 * Blog Posts
147 :PROPERTIES:
148 :EXPORT_HUGO_SECTION: posts
149 :END:
150 ** My Blog Homepage
151 :PROPERTIES:
152 :EXPORT_HUGO_MENU: :menu "main"
153 :EXPORT_FILE_NAME: _index
154 :END:
155 Man, look at all my blog posts.
156 ** One Bad Night
157 :PROPERTIES:
158 :EXPORT_FILE_NAME: bad-night
159 :END:
160 Someone gave me herpes! Oh no!
161 {{< /highlight >}}
162
163 Which yields the following files on export:
164
165 ```nil
166 .
167 ├── content
168 │   ├── _index.md
169 │   └── posts
170 │   ├── bad-night.md
171 │   └── _index.md
172 └── hugotest.org
173 ```
174
175 As you might expect if you're already familiar with Hugo, this structure adheres
176 to the Hugo [content management](https://gohugo.io/content-management/organization/) scheme. Additionally, the index files have been
177 marked with menu metadata, which allows Hugo themes to automatically generate
178 navigation menus from the markdown files. Hereafter, making new blog posts is as
179 simple as adding new sub-headings under the "Blog Posts" heading, and
180 exporting. As you can see, this is suitable for defining the hierarchical
181 structure of any general website, not just blogs. Org mode and Hugo just make
182 creating new pages so simple and well-structured that providing content is all
183 that's required for a new page, blog entry, or entirely new site section. If you
184 can blog with ox-hugo, you can deftly deploy any manner of web content, or even
185 develop entire websites as naturally as you make blog posts. Any tool that can
186 turn blogging and web development into the same task is quite an achievement!
187
188 Of course, themes to style this content are another can of worms entirely, but
189 we'll get to that soon. It is sufficient for now to mention that Hugo makes
190 [using themes](https://gohugo.io/themes/installing-and-using-themes/) as easy as downloading one and specifying it in Hugo's config file.
191
192
193 ## Heading Management {#heading-management}
194
195 One question you may ask is why the blog's homepage is not defined in the **Blog
196 Posts** heading. This is a fair question! Any heading with an
197 `:EXPORT_FILE_NAME:` property will export _all_ of that heading's content,
198 _including subheadings_ beneath it. This allows Org headings to be used as part
199 of the content of a post, where they will be exported as markdown heading
200 levels, which translate to HTML heading elements `<h1>`, `<h2>`, `<h3>`,
201 etcetera.
202
203 Furthermore, properties other than `:EXPORT_FILE_NAME:` are _inherited_ by
204 sub-headings, including the `:EXPORT_HUGO_MENU:` properties. A
205 `:EXPORT_HUGO_MENU:` property at the section root would cause all exported files
206 within that section to be added to the menu specified. This might be intended by
207 the content creator, but most likely you don't want every single post you make
208 to be in the main menu. So it makes sense to define all your pages, including
209 the index, as a sub-heading of the section definition (which merely specifies
210 which sub-directory the content will output to).
211
212 To illustrate, let's assume you want to extend the previous site definition with
213 a section about fishsticks. We'll do this the "wrong way" first to show how Org
214 handles inheritence:
215
216 {{< highlight org "linenos=table, linenostart=24" >}}
217 * Fishsticks
218 :PROPERTIES:
219 :EXPORT_HUGO_SECTION: fishsticks
220 :EXPORT_HUGO_MENU: :menu "main"
221 :EXPORT_FILE_NAME: _index
222 :END:
223 This section devoted to Orson Wells, R.I.P.
224 ** Van De Camps
225 :PROPERTIES:
226 :EXPORT_FILE_NAME: van-de-camps
227 :END:
228 If this is fish, I'll be a monkey's uncle.
229 ** Gortons
230 :PROPERTIES:
231 :EXPORT_FILE_NAME: gortons
232 :END:
233 I think these gave me the herpes.
234 {{< /highlight >}}
235
236 In this example, we've defined the main homepage of the section inside the
237 tier-1 heading for Fishsticks. This is _technically_ valid, and produces the
238 expected file output:
239
240 ```nil
241 .
242 ├── content
243 │   ├── fishsticks
244 │   │   ├── gortons.md
245 │   │   ├── _index.md
246 │   │   └── van-de-camps.md
247 │   ├── _index.md
248 │   └── posts
249 │   ├── bad-night.md
250 │   └── _index.md
251 └── hugotest.org
252 ```
253
254 But on inspection of the gortons.md file, we find the anomoly mentioned above:
255
256 {{< highlight markdown "linenos=table, linenostart=1" >}}
257 ---
258 title: "Gortons"
259 author: ["Ken Grimes"]
260 draft: false
261 menu:
262 main:
263 weight: 2002
264 identifier: "gortons"
265 ---
266
267 I think these gave me the herpes.
268 {{< /highlight >}}
269
270 Uh oh! Not only did these fishsticks give us herpes, they are now part of the
271 main menu. Worse, when the index page was exported, each of the subsequent posts
272 became part of its content:
273
274 {{< highlight markdown "linenos=table, linenostart=1" >}}
275 ---
276 title: "Fishsticks"
277 author: ["Ken Grimes"]
278 draft: false
279 menu:
280 main:
281 weight: 1001
282 identifier: "fishsticks"
283 ---
284
285 This section devoted to Orson Wells, R.I.P.
286
287
288 ## Van De Camps {#van-de-camps}
289
290 If this is fish, I'll be a monkey's uncle.
291
292
293 ## Gortons {#gortons}
294
295 I think these gave me the herpes.
296 {{< /highlight >}}
297
298 This explains the flexibility of ox-hugo's straightforward parsing
299 rules. Specifically, that any headings with an `:EXPORT_FILE_NAME:` tag will
300 export everything beneath them as content. The content organization in this
301 erroneous example duplicates data, but might still be useful if you wanted to
302 create, for instance, an "all\_content" page for the section. In general, though,
303 be sure to put your index pages in subheadings (just as you do with normal
304 pages) so that the tier-1 heading can be used for "global" definitions that
305 affect all of the pages. A _correct_ section for fishsticks should look like
306 this:
307
308 {{< highlight org "linenos=table, linenostart=24" >}}
309 * Fishsticks
310 :PROPERTIES:
311 :EXPORT_HUGO_SECTION: fishsticks
312 :END:
313 ** Fishsticks Home
314 :PROPERTIES:
315 :EXPORT_HUGO_MENU: :menu "main"
316 :EXPORT_FILE_NAME: _index
317 :END:
318 This section devoted to Orson Wells, R.I.P.
319 ** Van De Camps
320 :PROPERTIES:
321 :EXPORT_FILE_NAME: van-de-camps
322 :END:
323 If this is fish, I'll be a monkey's uncle.
324 ** Gortons
325 :PROPERTIES:
326 :EXPORT_FILE_NAME: gortons
327 :END:
328 I think these gave me the herpes.
329 {{< /highlight >}}
330
331 Now the homepage for the fishsticks section has a heading all its own, just like
332 any other page. That's better! Now our homepage will output the content only
333 from its subheading, and the other pages don't inherit the homepage's
334 properties. All pages inherit the `:EXPORT_HUGO_SECTION: fishsticks` property
335 though, which is what we want to ensure that these pages are exported to the
336 proper section.
337
338
339 # Hugo Setup {#hugo-setup}
340
341 At this point, setting up Hugo and publishing is simple. [Installing](https://gohugo.io/getting-started/installing/) Hugo is
342 pretty straightforward on any Unix-like system with a package manager; it is
343 available on most distributions at this point. Windows installation is a bigger
344 pain in the ass, but you should be used to that if you're still in the
345 stone-age.
346
347 Using `hugo new site .` on the command-line will create a new hugo site in the
348 current directory, but `hugo` expects to be creating a new directory with this
349 command and will complain if it already exists. It also provides the `--force`
350 option to allow creating a new site in an extant directory, but this too will
351 fail if the **content** subdirectory already exists (which ox-hugo will create
352 when you export).
353
354 So you have three choices:
355
356 1. run `hugo new site /path/to/some-new-dir` and move your Org file to this new
357 directory
358 2. simply `rm -Rf content/` to remove the content directory ox-hugo created,
359 then run `hugo new site --force .`
360 3. don't even bother with the `hugo new site` command, and make a **config.toml**
361 file manually (the only file really required for Hugo to run).
362
363 It's convenient to do this through the `hugo` command because it will create
364 Hugo-specific subdirectories like archetypes, layouts, themes, etcetera, in
365 addition to populating a basic **config.toml** file. The subdirectories it creates
366 aren't necessary, but help illustrate Hugo's structure. In any case, you'll want
367 to wind up with a directory structure something like this (created with option 2
368 above, extending from previous examples):
369
370 ```nil
371 .
372 ├── archetypes
373 │   └── default.md
374 ├── config.toml
375 ├── content
376 ├── data
377 ├── hugotest.org
378 ├── layouts
379 ├── static
380 └── themes
381 ```
382
383 Exporting with ox-hugo using `C-c C-e H A` again will, as expected, fill the
384 content directory with our content.
385
386 ```nil
387 .
388 ├── archetypes
389 │   └── default.md
390 ├── config.toml
391 ├── content
392 │   ├── fishsticks
393 │   │   ├── gortons.md
394 │   │   ├── _index.md
395 │   │   └── van-de-camps.md
396 │   ├── _index.md
397 │   └── posts
398 │   ├── bad-night.md
399 │   └── _index.md
400 ├── data
401 ├── hugotest.org
402 ├── layouts
403 ├── static
404 └── themes
405 ```
406
407
408 ## Theming {#theming}
409
410 The last thing to do here is to download or create a theme for Hugo. As
411 mentioned before, installing a theme is very simple. This blog uses a custom
412 theme named Speedy that I have been developing to help myself learn Hugo's
413 internals, but for this example I'll be using Kaushal Modi's [bare-min theme](https://github.com/kaushalmodi/hugo-bare-min-theme). The
414 bare-min theme is the best starting place out there for making new themes, and
415 outputs basic HTML pages without any need to mess with CSS or JS. It also
416 provides easy debugging facilities and search features.
417
418 So let's install it! You can download the theme from its github page and extract
419 it to the themes folder, or much more easily use git to clone it to your themes
420 directory. `git clone https://github.com/kaushalmodi/hugo-bare-min-theme.git
421 themes/bare-min` Then open up your **config.toml** file, and add the theme.
422
423 {{< highlight toml "linenos=table, linenostart=1" >}}
424 baseURL = "http://example.org/"
425 languageCode = "en-us"
426 title = "My New Hugo Site"
427 # Adding a theme:
428 theme = "bare-min"
429 {{< /highlight >}}
430
431 Be sure that the theme's name matches the theme directory's name in the **themes/**
432 directory of your project base directory. (e.g. **themes/bare-min** here). That's it
433 for installing the theme.
434
435 Now, running the command `hugo` with no subcommands will invoke the Hugo
436 generator on the current directory, and output finalized content in the
437 **public/** directory.
438
439 ```nil
440 .
441 ├── archetypes
442 │   └── default.md
443 ├── config.toml
444 ├── content
445 │   ├── fishsticks
446 │   │   ├── gortons.md
447 │   │   ├── _index.md
448 │   │   └── van-de-camps.md
449 │   ├── _index.md
450 │   └── posts
451 │   ├── bad-night.md
452 │   └── _index.md
453 ├── data
454 ├── hugotest.org
455 ├── layouts
456 ├── public
457 │   ├── categories
458 │   │   ├── index.html
459 │   │   └── index.xml
460 │   ├── css
461 │   │   └── github_chroma.css
462 │   ├── fishsticks
463 │   │   ├── gortons
464 │   │   │   └── index.html
465 │   │   ├── index.html
466 │   │   ├── index.xml
467 │   │   └── van-de-camps
468 │   │   └── index.html
469 │   ├── index.html
470 │   ├── index.xml
471 │   ├── js
472 │   │   └── search.js
473 │   ├── page
474 │   │   └── 1
475 │   │   └── index.html
476 │   ├── posts
477 │   │   ├── bad-night
478 │   │   │   └── index.html
479 │   │   ├── index.html
480 │   │   └── index.xml
481 │   ├── sitemap.xml
482 │   └── tags
483 │   ├── index.html
484 │   └── index.xml
485 ├── static
486 └── themes ...
487 ```
488
489 Hugo, by default, generates xml files that are suitable for RSS feeds. With a
490 theme installed, Hugo will produce more suitable web content (usually HTML) to
491 be served over HTTP. The bare-min theme outputs HTML, provides CSS for doing
492 chroma-based syntax highlighting (in case you include code blocks), and inline
493 styles for basic page formatting. Generated pages also have a lot of useful
494 debugging information. You'll also notice that Hugo has generated folders for
495 "categories" and "tags". These are default organization labels for your content
496 called [taxonomies](https://gohugo.io/content-management/taxonomies/).
497
498
499 ## Taxonomies {#taxonomies}
500
501 The taxonomy index pages allow users to browse content by category or tag. These
502 taxonomies correspond to Org mode tags, and ox-hugo will automatically
503 associated tagged headings with the tags taxonomy, or the categories taxonomy if
504 prefixed with an @ symbol. You are free to define your own taxonomies, and even
505 disable the default "tags" and "categories" taxonomies, but since Org mode tags
506 directly translate to the default Hugo taxonomies, it makes sense to just use
507 the default taxonomies for now.
508
509 As an example of taxonomies, I'll add some tags and categories to our
510 **hugotest.org** file to create a complete blog structure with tags and categories:
511
512 {{< highlight org "linenos=table, linenostart=1" >}}
513 #+hugo_base_dir: .
514 * Homepage
515 :PROPERTIES:
516 :EXPORT_HUGO_SECTION:
517 :EXPORT_FILE_NAME: _index
518 :EXPORT_HUGO_MENU: :menu "main"
519 :END:
520 This is the home of my blog!
521 * Blog Posts
522 :PROPERTIES:
523 :EXPORT_HUGO_SECTION: posts
524 :END:
525 ** My Blog Homepage
526 :PROPERTIES:
527 :EXPORT_HUGO_MENU: :menu "main"
528 :EXPORT_FILE_NAME: _index
529 :END:
530 Man, look at all my blog posts.
531 ** One Bad Night :@updates:herpes:fear:
532 :PROPERTIES:
533 :EXPORT_FILE_NAME: bad-night
534 :END:
535 Someone gave me herpes! Oh no!
536 * Fishsticks
537 :PROPERTIES:
538 :EXPORT_HUGO_SECTION: fishsticks
539 :END:
540 ** Fishsticks Home
541 :PROPERTIES:
542 :EXPORT_HUGO_MENU: :menu "main"
543 :EXPORT_FILE_NAME: _index
544 :END:
545 This section devoted to Orson Wells, R.I.P.
546 ** Van De Camps :@reviews:fear:
547 :PROPERTIES:
548 :EXPORT_FILE_NAME: van-de-camps
549 :END:
550 If this is fish, I'll be a monkey's uncle.
551 ** Gortons :@reviews:herpes:
552 :PROPERTIES:
553 :EXPORT_FILE_NAME: gortons
554 :END:
555 I think these gave me the herpes.
556 {{< /highlight >}}
557
558 Exporting **hugotest.org** with `C-c C-e H A` and generating with `hugo` will yield
559 the same file structure as before, but this time we'll see that the categories
560 and tags directories have sections for our newly added taxonomies.
561
562 ```nil
563 .
564 └── public
565 ├── categories
566 │   ├── index.html
567 │   ├── index.xml
568 │   ├── reviews
569 │   │   ├── index.html
570 │   │   └── index.xml
571 │   └── updates
572 │   ├── index.html
573 │   └── index.xml
574 └── tags
575 ├── fear
576 │   ├── index.html
577 │   └── index.xml
578 ├── herpes
579 │   ├── index.html
580 │   └── index.xml
581 ├── index.html
582 └── index.xml
583 ```
584
585 The index pages of taxonomies provide a list of all available taxonomies of that
586 type, each with list pages that show all content associated with them. This
587 allows themes to easily build navigation pages for browsing or querying
588 taxonomies. Files like these are often useful to output as JSON (done by the
589 theme) to allow Javascript-driven dynamic search features, but a simpler scheme
590 can output HTML pages to browse taxonomies just as you would posts in a section
591 (i.e. Org mode heading).
592
593
594 ## Serving Content {#serving-content}
595
596 You can now serve the **public/** directory over an HTTP server. Hugo is packaged
597 with an internal [HTTP server](https://gohugo.io/commands/hugo_server/) to help with testing, which is quite convenient
598 because it can automatically refresh whenever content in its **content/** directory
599 is updated (so when you export from ox-hugo, you don't have to run `hugo`
600 again). To use it, simply run `hugo server` and point your browser at
601 <http://localhost:1313> (1313 is the default `--port` argument for `hugo server`).
602
603
604 # Additional Information {#additional-information}
605
606 Eventually you'll want to move on to [other themes](https://themes.gohugo.io/), or [develop your own](https://gohugo.io/themes/creating/), but at
607 this point you've got a fully functional blog publishing workflow from start to
608 finish that you can view in-browser as you develop.
609
610
611 ## Attaching Files, Capturing Information & Automation {#attaching-files-capturing-information-and-automation}
612
613 Once you have a basic site structured in your Org file, you're ready to start
614 throwing information in it. It is of course sufficient to open the Org file and
615 edit it, but most Org mode users prefer to automate _everything_, and being able
616 to use Org's capture feature to instantly populate new blog posts is extremely
617 convenient.
618
619 The [ox-hugo documentation](https://ox-hugo.scripter.co/) provides succinct explanations on how to do this,
620 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
621 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
622 time, just save the file as usual with `C-x C-s`).
623
624
625 ## Indexes and Page Resources {#indexes-and-page-resources}
626
627 You may be wondering why our index pages are exported as **\_index** rather than
628 **index**. Hugo uses a concept called [Page Bundles](https://gohugo.io/content-management/page-bundles/) to organize exported
629 content. The gist of this is that a file named **index** is known as a "Leaf Node"
630 and cannot have any children. A file named **\_index** is considered a "Branch
631 Node" and allows nesting other bundles beneath it. In other words, an Org
632 heading with an exported file name of **index** will be treated as a single page
633 with no subfolders. This is useful for single pages, but a section index
634 (e.g. for a blog) with many subpages and other resources will more than likely
635 want to allow nested bundles beneath it.
636
637 You may export an Org heading as a Page Bundle by providing the Org property
638 `:EXPORT_HUGO_BUNDLE:` with an argument (string) that will become the name of
639 the folder created. If you do this, you will need to set the
640 `:EXPORT_FILE_NAME:` property to either **index** for Leaf Nodes, or **\_index** for
641 Branch Nodes.
642
643 The [capture setup](https://ox-hugo.scripter.co/doc/org-capture-setup/) provided by Kaushal Modi above provides methods to
644 automatically create either a normal page, or a leaf node bundle when invoking
645 Org Capture.
646
647
648 ## Drafts and Automatic Timestamps {#drafts-and-automatic-timestamps}
649
650 By default, Hugo will not build any markdown files whose front-matter properties
651 include `draft: true`. This is very convenient for in-progress posts that you
652 leave in your Org file, or in the **content/** directory.
653
654 Ox-hugo will always fill out the draft property, and by default every exported
655 header will have its draft property set to **false**. However, ox-hugo also links
656 this behavior to the TODO feature of Org. When you cycle a heading's TODO value
657 with `S-<RIGHT>` (that's Shift + Right Arrow Key), you will signal to ox-hugo to
658 export this heading as a draft (i.e. `draft: true`), which will prevent Hugo
659 from building it into an HTML page.
660
661 When a heading is cycled to the DONE state in Org, it will automatically
662 generate a timestamp for when the heading was closed. Ox-hugo will export DONE
663 headings with `draft: false` and, better still, will use Org's timestamp to fill
664 out the Date property in the markdown file. This makes it trivial to manage
665 writing multiple posts at once, and automatically timestamp completion dates.
666
667 You may also explicitly set this date parameter with the `:EXPORT_DATE:`
668 property, but the ease of using DONE-state switching is pretty hard to pass up.
669
670
671 ## Renaming Tags and Other Properties {#renaming-tags-and-other-properties}
672
673 If a theme you are using has any idiosyncrasies about your naming conventions
674 (e.g. if you export your content to more than one site using more than one
675 theme), ox-hugo provides a [convenient way](https://ox-hugo.scripter.co/doc/replace-front-matter-keys/) to automatically replace any key
676 values on export. This can be done on a per-heading, or a per-file basis.
677
678 To replace keys for the entire file, simply add a property to the top of your
679 Org file. For example:
680
681 ```org
682 #+hugo_front_matter_key_replace: description>summary
683 ```
684
685 This will make any `:EXPORT_DESCRIPTION:` properties export, instead, to a
686 "summary" key in the front-matter of your output markdown file. It will also be
687 able to replace exported values in the Org body:
688
689 ```org
690 #+begin_description
691 This is the description, but will export as the Summary value in front-matter
692 #+end_description
693 ```
694
695 To do this on a per-heading basis, simply add the
696 `:EXPORT_HUGO_FRONT_MATTER_KEY_REPLACE:` property to a heading's property block,
697 and the replacements will only occur within that heading.
698
699
700 # Thanks {#thanks}
701
702 Thanks to Kaushal Modi, who found this article on the googs within days of me
703 posting it, for reaching out to me and providing thorough feedback and error
704 checking.
705
706 And special thanks to me, for once again overcoming Hamhock the Laziness Demon
707 who has possessed me since birth and hates it when I do anything productive.