Hugo

From HerzbubeWiki
Jump to: navigation, search

This page is about the static website generator Hugo.

References


Glossary

Front matter 
Stuff at the beginning of a content file that contains metadata about the actual content that comes later in the file.
Section 
A site's content is structured into a tree of sections. The subfolders below content automatically are treated as the root sections. To define a subsection place an _index.md file into a subfolder.
Theme 
How a site generated by Hugo looks.


Installation on Mac

Just use the Homebrew package manager and simply install Hugo with this command in the Terminal:

brew install hugo


Using Hugo

Once Hugo is installed on your system you can use this command in the Terminal to do something with Hugo:

hugo [...]


Creating a new site

Create a base folder for Hugo in which you can then manage several site:

mkdir /path/to/hugo-base-folder
cd /path/to/hugo-base-folder

Create the new site with this command. It creates the site's base folder and populates it with a skeleton of files and folders:

hugo new site foo-site


Creating new content

Basics

Content files go into the content subfolder of the site folder. Instead of manually creating the file you type this command:

hugo new foo/bar/baz.md

Notes:

  • This creates a new content file in the specified subfolder and populates it with some default front matter.
  • Hugo automatically figures out the format of the file based on the extension. In the example the .md extension indicates that this is a Markdown file.
  • The content is set to be a draft. To see drafts Hugo's test web server must be started with option -D.


Example content file

This is an example file that shows

  • Some front matter in YAML format between the two --- lines,
  • A bit of teaser text,
  • A "read more" delimiter to delimit the teaser from the main text,
  • And finally the main text.
---
title: "Little Go 1.6.0 released"
date: "2021-03-11T00:27:00+01:00"
author: "patrick"
articlestyles: ["Release note"]
softwareprojects: ["Little Go"]
---

Libero adipisci ipsam consequuntur nesciunt voluptas

<!--more-->

Ut sint expedita quis dignissimos atque tempore asperiores. 


Front matter

  • Front matter contains meta data about the content.
  • Front matter is usually stored as key/value pairs.
  • Front matter can be written in YAML, TOML or JSON.
    • YAML is delimited by surrounding lines with 3 dashes (---) and uses a colon (:) between key and value.
    • TOML is delimited by surrounding lines with 3 plus characters (+++) and uses an equals character (=) between key and value.
  • Themes can define theme-specific keys.
  • You can also specify custom keys - it's not yet clear how to use the data.


Markdown

Hugo supports several kinds of Markdown flavours. The default is Goldmark. Refer to the Markup Configuration page of Hugo's documentation to see what is supported.

Some of the things that are possible but that I haven't explored yet:

  • Embed HTML in the Markdown content.
  • Add CSS classes to titles and blocks of content.
  • Generate a table of content


Shortcodes

A content file can contain shortcodes that are like placeholders that will be replaced with real HTML code generated by Hugo. Hugo comes with a lot of pre-defined shortcodes. Refer to the Shortcodes page of Hugo's documentation for details. You can define your own custom shortcodes - see this Hugo doc page for details.

Note: Shortcodes cannot be used in template files - use a partial template for that.

Examples:

{{% shortcode-name param1 %}}
{{% shortcode-name param1 %}}<p>Hello world!</p>{{% /shortcode-name param1 %}}
{{< shortcode-name param1 >}}<p>Hello world!</p>{{< /shortcode-name param1 >}}

Notes:

  • Parameters may be named, positional, or both - it depends on how the shortcode is defined.
  • Shortcodes may require closing shortcodes, similar to how HTML elements must have a begin/end tag.
  • Instead of the "%" character you can use angle brackets ("<>") as delimiters. This indicates that the shortcode’s inner content does not need further rendering.


Taxonomies

  • Taxonomy information is defined in the front matter
  • Taxonomies might work differently depending on the theme that is being used.
  • Hugo comes with two pre-defined taxonomies: Tags (= keywords) and Categories.
    • Tags are defined like this: tags: ["tag1", "tag2", "tag3"]
    • Categories are defined like this: categories: ["cat1", "cat2", "cat3"]
  • Custom taxonomies
    • Need to be defined in the config.toml file like this:
[taxonomies]
  tag = "tags"
  category = "categories"
  foo = "foos"
  "the singular" = "the plural"
    • The default taxonomies need to be defined as well if you want them.
    • The key is the singular, the value is the plural.
    • You can have a singular with a space in it by enclosing it within double quotes.
    • Hugo automatically manages uppercasing.
    • Now just add the taxonomy name and the term names to the front matter like it was shown above for "tags" and "categories".


Single page vs. list page

Hugo distinguishes content into two "categories":

  • Single pages: These are pages that display actual content. Example: A page that displays the content of a content file.
  • List pages: These are pages that list other other content. Example: A page that lists the content of a folder.


Hugo automatically generates a list page for the site's top-level folder and for folders immediately below that. It does NOT automatically create list pages for folders that are deeper down in the hierarchy. To achieve this you have to create a special file named _index.md within such a folder. The file does not need to have any content besides the usual front matter, but if you want to you can add text.

hugo new foo/bar/_index.md


If you create an _index.md file in a folder for which Hugo would normally auto-create a list page, the _index.md file is now used instead.


Archetypes

Archetypes are templates that Hugo uses when you create new content files. A new Hugo site is automatically populated with the

archetypes/default.md

archetype file which defines the front matter that is used to initialize a new content file with.


You can have several archetype files. Which one is used depends on the folder in which you create a new content file. If there is an archetype file named the same as the containing folder, then that archetype file is used. Otherwise the default.md file is used.


Archetype files are not static, they define placeholders that are filled when the archetype file is used. TODO: Provide more information.


Templates

Basics

Hugo uses Go templates. Go Templates are HTML files (extension .html) with the addition of variables, functions and processing logic (conditionals, loops). Go Template variables and functions are accessible within

{{ }}

When Hugo renders the site the templates are processed and as a result of the processing logic the variables and functions within a template are replaced with actual content.

Refer to the Templates Introduction page of Hugo's documentation for details.


Syntax

Comments:

Template:/* A comment */

Local variable:

{{ $foo := "bar" }}
{{ $bar := $foo }}


Theme templates

Hugo templates are used for generating the actual output of Hugo. When you're using a theme that theme consists - among other things - of a number of template files located in the folder

themes/foo-theme/layouts


Custom templates

You can also define your own templates under

layouts

These override the templates from the theme. The templates to be used by default must be placed in a folder named _default:

layouts/_default


Single page and list page templates

The template for single pages and for list pages must be named specifically

single.html
list.html


Site main page template

The site's main page (the one at path location /) is styled with a special template file

layouts/index.html


Section templates

A site's content is structured into a tree of sections. The subfolders below content automatically are treated as the root sections. To define a subsection place an _index.md file into a subfolder.

A section template is a template that is used only for a particular section of the site.

  • Create a subfolder below the layouts folder with the exact same path as the section in the content folder.
  • Place single.html or list.html into the new layouts subfolder. These are now applied to the content below the corresponding content folder.


Base templates

Name and location of a base template:

layouts/_default/baseof.html

Example content of the base template that references a block named "main":

[...]
<body>
  {{ block "main" . }}
  {{ end }}
</body>
[...]

Now the single and list templates can define the "main" block which is then inserted into the base template:

{{ define "main" }}
  Everything in here is placed at the block reference location in the base template
{{ end }}

Notes:

  • The block name "main" is nothing special, you can choose something else.
  • You can reference and define more blocks.


Partial templates

Place partial templates under here:

layouts/partials

Partial templates can then be referred to and expaned from other templates.

{{ partial "foo" . }}

Notes:

  • The first parameter defines the name of the partial template file. In the example the partial template foo.html is expanded.
  • The second parameter defines the context to be passed into the template. The "." parameter means the content file that is currently being processed by the template that includes the partial.


To pass a dictionary with custom data

{{ partial "foo" (dict "key1" "value1" "key2" "value2") }}

To access the data:

{{ .key1 }}


Shortcode templates

Place shortcode templates under here:

layouts/shortcodes

Refer to the shortcode template in the content file like this.

{{< foo key="value" >}}

Notes:

  • This expands the shortcode template layouts/shortcodes/foo.html.
  • It passes the key/value pairs to the template. This is optional.

To access the data:

{{ .Get "key" }}


Shortcode templates can also be used in a spanning manner. In the content file:

{{< foo >}}
  bar
{{< /foo >}}

In the template you access the content spanned by the template:

{{ .Inner }}

When you use "<" and ">" the content spanned by the template is not rendered as markdown. Use "%" instead to make it render as usual.


Themes

  • Go to the Hugo themes gallery website (see References section)
  • Select a theme that you like
  • Click its Download button. This will not download anything, it will lead you to the GitHub repository where the theme is developed.
  • Read through repository's README file. It will tell you how to actually install the theme in your Hugo site folder.
  • Basically you'll clone the repository and tweak some settings in the config.toml file.
  • A theme is made up - among other things - of Hugo templates. The template files are stored in the theme's layouts folder.


Variables

Variables can only be used in the "layouts" folder within templates.

Syntax 1 refers to front matter in the content file:

{{ .Foo }}

Some variables:

  • .Title. Expands to the value of the front matter key "title".
  • .Date. Expands to the value of the front matter key "date".
  • .URL: Expands to the URL path only.
  • .Params.Foo: Expands to the value of the front matter custom key "foo".


Syntax 2 refers to a variable value defined earlier in the template.

{{ $Foo }}

And the definition looks like this:

{{ $Foo := "bar" }}


There are many other kinds of variables which are explained in the Hugo docs. Please refer to that for more.


Functions, conditionals

TODO


Data folder

Serves as a kind of a mini database. Can contain .yaml, .toml or .json files.

Access the content of a data file from a template like this:

<!-- Iterates over the content of a file foo.json -->
{{ .range .Site.data.foo }}
  <!-- Expands to the value of key "bar" -->
  {{ .bar }}
{{ end }}


Testing

Start the web server built into Hugo:

hugo server

Then use this URL in the browser to access the site:

http://localhost:1313

(the actual URL is displayed at the end of the output of the hugo server command)

Note: To also see draft content, use the -D option.


Recipes

Footnotes

At the place of origin:

[¹]({{< ref "#footnote-1" >}} "Footnote 1")
[²]({{< ref "#footnote-2" >}} "Footnote 2")

Enumerate the footnotes at the end of the page:

---

# {#footnote-1}
¹ Footnote text.

# {#footnote-2}
² Another footnote text.


Notes:

  • Use Unicode superscript digit characters to compose the footnote number. Example: U+00B9 (character name = SUPERSCRIPT DIGIT ONE).
  • Use the usual Markdown syntax to create a link at the site of origin. In the URL part use the Hugo shortcode template "ref" to generate the URL with a specific page-local anchor (e.g. #footnote-1).
  • At the end of the page use "---" (which is, I believe, Markdown) to create a ruler line that separates the footnotes from the main content of the page.
  • Enumerate the footnotes with an empty heading and a Hugo construct that specifies the anchor to generate. This works because Hugo automatically creates anchors for all headings. Without the Hugo construct shown in the example above, Hugo generates an anchor based on the heading text. Since we don't really want a heading to be shown we use an empty heading text and specify the anchor name with the Hugo construct.


Building and publishing the site

General procedure

Type

hugo

to build. This creates a folder

public

and populates it with the generated content. It's probably a good idea to add the public folder to .gitignore.

To rebuild the site, delete the public folder first as it won't get cleaned out by Hugo itself.


For herzbube.ch

On pelargir:

cd /var/www/hugo
rm -rf new-site.herzbube.ch

Locally:

scp -r public root@pelargir.herzbube.ch:/var/www/hugo/new-site.herzbube.ch

Test in browser:

https://new-site.herzbube.ch/

On pelargir when finished with testing:

cd /var/www/hugo
rm -rf old-site.herzbube.ch
mv herzbube.ch old-site.herzbube.ch
mv new-site.herzbube.ch herzbube.ch
mkdir new-site.herzbube.ch

(the last statement is necessary so that Apache does not generate a warning about a missing document root when it is periodically restarted)


For kino.herzbube.ch

On pelargir:

cd /var/www/hugo
rm -rf kino.herzbube.ch

Locally:

scp -r public root@pelargir.herzbube.ch:/var/www/hugo/kino.herzbube.ch


For grunzwanzling.ch

On pelargir:

cd /var/www/hugo
rm -rf grunzwanzling.ch

Locally:

scp -r public root@pelargir.herzbube.ch:/var/www/hugo/grunzwanzling.ch


Migrating from Drupal

Data to migrate

  • Nodes. Node types are:
    • Story
      • Title. Simple text.
      • Body. HTML. Conceptually this can be broken into a teaser and into the body that follows after the teaser. The HTML comment <!--break> is sometimes - but not always - used to mark the teaser break.
      • 0-n file attachments.
    • Page. 10 pages in total: About, Software projects, CMS Evaluation, Evaluation of free UML Tools, one page per software project.
      • Same structure as Story.
    • Book review
      • Title. Simple text.
      • Several headings. HTML. Typically one of the heading elements, sometimes with the "style" attribute. These can also be ignored by the migration because both reviews (yes, there are only two) contain the same static headings.
      • 1-n Authors. Text.
      • Rating. Text in the format n/max. Max is always 5.
      • Recommendation, Plot, Opinion, Bibliography. HTML.
      • 0-n Links. URL + link text.
  • Meta data for nodes
    • Publishing date + time. This may be different from the date of the last revision.
    • Author.
    • URL alias. Specifies the path of the rendered page.
    • 0-n Topics.
    • 0-1 Article Style.
    • 0-1 Project. (not for book reviews)
  • Comments
    • Body. HTML.
    • Publishing date + time.
    • Author.
  • Taxonomy. Vocabularies:
    • Topics. Tree.
    • Article Styles. Flat list.
    • Software Projects. Flat list.
  • Views
    • List of book reviews
  • Links. The static link menu displayed on every page. Contains only two links.
  • Footer. The static footer displayed on every page.
  • Files
  • Redirects
    • Can be found under Administer > Configuration > URL Redirects.
    • There are currently only 7, which means that these are migrated manually.


Data to drop:

  • A node's view count
  • Old node revisions


Functionality/data that is no longer needed/wanted:

  • Authentication
  • CAPTCHA
  • Comments
  • Search
  • Page view count
  • Hierarchical structure of the taxonomy vocabulary "Topics"


Manually migrate

  • Writing the automated migration script is a brainfuck, so anything that is not bulk will be migrated manually.
  • Book reviews. There are only 2 of these
  • List of book reviews -> hopefully will be auto-generated by Hugo
  • Links
  • Footer
  • Files
  • Redirects. There are only 7 of these.


Automated migration

  • Node types "story" and "page": Title, body, publishing date, author, URL path, taxonomy terms
  • Comments
  • Taxonomy vocabularies/terms


Automation

I wrote a PHP script drupal2hugo.php for exporting bulk data from Drupal. The script can be found in my tools Git repo here:

https://git.herzbube.ch/gitweb.cgi/tools.git/blob/HEAD:/drupal2hugo/drupal2hugo.php


Hugo issues to solve for herzbube.ch

Taxonomy terms for custom taxonomies not shown

When a page is displayed that is tagged with one or more terms from the custom taxonomies "Article Styles" and "Software Projects", these terms are not shown at the end of the page.

  • Positive example: The page Implementing Binary Search shows the taxonomy term "Algorithms" at the bottom.
  • Negative example: The page Little Go 1.7.0 released should show the terms "Release notes" and "Little Go" at the bottom, but neither of the two terms is shown.

This could be a problem with the Mainroad theme and not with Hugo in general.


List pages with wrong titles

The main menu is configured with menu entries. When the user clicks one of the entries, the resulting list page has a tab title and page title that does not match the menu entry name.

Example: The main menu has an entry "Blog entries". When the user clicks this the resulting list page says "Blogs" at the top, and also in the title of the browser tab.

Notes from initial research:

  • Likely has to do with section configuration
  • May not be a theme problem


Categories or tags not shown on list pages

The Mainroad theme does not display categories or tags on list pages.

Example: https://www.herzbube.ch/blog/


List page for a tag does not show the current filter

When the list page for a tag is shown, the Mainroad theme does not provide an indication which filter is in effect.

Since tags are also not shown on list pages (see previous issue) the user has to look at the URL to get an indication what she is looking at.


No navigation to first/last page on list pages

On list pages the Mainroad theme only has buttons to jump to the previous/next page, but not to the first/last page.


Links and formatting not rendered in summaries

The Mainroad theme does not render links or other formatting in summaries generated on list pages.

Examples:


Incorrect rendering of "Read more" link on list pages

The "Read more" link for the post Bye bye Subversion is rendered with red text color instead of white text color on list pages. Example: this list page.