Frontier Software

Hugo

Creating a basic skeleton

At time of writing, this is a bit of a schlep because the recommended command

hugo new site whatever_name

does not produce any basic layouts files to get a newbie started. So rather run

hugo new theme whatever_name

which will produce themes/whatever_name. Then do

mv themes/whatever_name .
rmdir themes

then

cd whatever_name
hugo server

will bring up a simple Hugo site on http://localhost:1313 you can start altering to your taste.

skeleton_home.png

Understanding where Hugo is fetching the title, menu, summaries etc from requires diving into the basic directory structure.

Directory structure

A cool recent feature of Hugo is it’s ability to render ASCII art as SVG using GoAT, and I’ve used that to prettify the output of tree.

The starting project created as above looks like so:

w h                                                         a                                                         t e a a c d h i l L R s t v r s   o a u 1 a         I E t h e c s   n t g 8 y         C A a e r h e t a o n o E D t m _ e d t c j e _ p . u _ p N M i f e n t e s s s n i o t t d a     S E c a . a y f s t n s o s e r     E . v t m p a d t m f t m i o e e u m m e s _ p p p l a b h l s i f h h h m t d c m s l a a x i o o o u a o i i a o e e e e e o l t i i . n s s s l s m s n l o a a a n r n . n n m d t t t t e e t g s t d d d u m . m . . d e - - - b i o . . l e c j e . . s i d c j x 1 2 3 r n f h h e r s s r h h . c s s . . . y d . t t . . s . . t t h o s m m m c e h m m h h . h h m m t d d d e x t l l t t h t t l l m - . m m m t m m l c m l l l m l l a d l n y o n . j p g

layouts/_defaults/baseof.html

<!DOCTYPE html>
<html lang="{{ or site.Language.LanguageCode site.Language.Lang }}" dir="{{ or site.Language.LanguageDirection `ltr` }}">
<head>
  {{ partial "head.html" . }}
</head>
<body>
  <header>
    {{ partial "header.html" . }}
  </header>
  <main>
    {{ block "main" . }}{{ end }}
  </main>
  <footer>
    {{ partial "footer.html" . }}
  </footer>
</body>
</html>

layouts/_defaults/list.html

{{ define "main" }}
  <h1>{{ .Title }}</h1>
  {{ .Content }}
  {{ range .Pages }}
    <h2><a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a></h2>
    {{ .Summary }}
  {{ end }}
{{ end }}

layouts/_defaults/single.html

{{ define "main" }}
  <h1>{{ .Title }}</h1>

  {{ $dateMachine := .Date | time.Format "2006-01-02T15:04:05-07:00" }}
  {{ $dateHuman := .Date | time.Format ":date_long" }}
  <time datetime="{{ $dateMachine }}">{{ $dateHuman }}</time>

  {{ .Content }}
  {{ partial "terms.html" (dict "taxonomy" "tags" "page" .) }}
{{ end }}

layouts/_defaults/home.html

{{ define "main" }}
  {{ .Content }}
  {{ range site.RegularPages }}
    <h2><a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a></h2>
    {{ .Summary }}
  {{ end }}
{{ end }}

layouts/partials/terms.html

{{- /*
For a given taxonomy, renders a list of terms assigned to the page.

@context {page} page The current page.
@context {string} taxonomy The taxonony.

@example: {{ partial "terms.html" (dict "taxonomy" "tags" "page" .) }}
*/}}

{{- $page := .page }}
{{- $taxonomy := .taxonomy }}

{{- with $page.GetTerms $taxonomy }}
  {{- $label := (index . 0).Parent.LinkTitle }}
  <div>
    <div>{{ $label }}:</div>
    <ul>
      {{- range . }}
        <li><a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a></li>
      {{- end }}
    </ul>
  </div>
{{- end }}

layouts/partials/menu.html

{{- /*
Renders a menu for the given menu ID.

@context {page} page The current page.
@context {string} menuID The menu ID.

@example: {{ partial "menu.html" (dict "menuID" "main" "page" .) }}
*/}}

{{- $page := .page }}
{{- $menuID := .menuID }}

{{- with index site.Menus $menuID }}
  <nav>
    <ul>
      {{- partial "inline/menu/walk.html" (dict "page" $page "menuEntries" .) }}
    </ul>
  </nav>
{{- end }}

{{- define "partials/inline/menu/walk.html" }}
  {{- $page := .page }}
  {{- range .menuEntries }}
    {{- $attrs := dict "href" .URL }}
    {{- if $page.IsMenuCurrent .Menu . }}
      {{- $attrs = merge $attrs (dict "class" "active" "aria-current" "page") }}
    {{- else if $page.HasMenuCurrent .Menu .}}
      {{- $attrs = merge $attrs (dict "class" "ancestor" "aria-current" "true") }}
    {{- end }}
    {{- $name := .Name }}
    {{- with .Identifier }}
      {{- with T . }}
        {{- $name = . }}
      {{- end }}
    {{- end }}
    <li>
      <a
        {{- range $k, $v := $attrs }}
          {{- with $v }}
            {{- printf " %s=%q" $k $v | safeHTMLAttr }}
          {{- end }}
        {{- end -}}
      >{{ $name }}</a>
      {{- with .Children }}
        <ul>
          {{- partial "inline/menu/walk.html" (dict "page" $page "menuEntries" .) }}
        </ul>
      {{- end }}
    </li>
  {{- end }}
{{- end }}

Front Matter

Draft, future, and expired content

Something I and probably many other newbies tripped over was that getting the values wrong in any of these 4 key-value pairs prevents the page from rendering.

Page Methods

Frontmatter Accessors

PAGE.Date 2024-01-15 13:34:29 +0200 +0200

PAGE.ExpiryDate 0001-01-01 00:00:00 +0000 UTC

PAGE.PublishDate 2024-01-15 13:34:29 +0200 +0200

PAGE.Lastmod 2024-01-20 10:41:04 +0200 +0200

PAGE.Description

PAGE.Draft false

PAGE.GetTerms "artists" Pages(0)

PAGE.Keywords []

PAGE.Layout

PAGE.Title Hugo

PAGE.LinkTitle hugo

PAGE.Params map[date:2024-01-15 13:34:29 +0200 +0200 draft:false iscjklanguage:false lastmod:2024-01-20 10:41:04 +0200 +0200 linktitle:hugo publishdate:2024-01-15 13:34:29 +0200 +0200 title:Hugo]

PAGE.Sitemap { -1 sitemap.xml}

PAGE.Slug

PAGE.Summary

PAGE.Weight 0

PAGE.Aliases []

Links

PAGE.Permalink https://frontiersoftware.co.za/hugo/

PAGE.RelPermalink /hugo/

PAGE.GitInfo

.AuthorDate 2024-01-20

.CommitDate 2024-01-20

.AuthorEmail robert.joeblog@gmail.com

.AuthorName Robert Laing

.Subject added to Hugo list page

PAGE.CodeOwners: []

PAGE.Kind: section

PAGE.Type: hugo

PAGE.BundleType: branch

PAGE.AllTranslations: Pages(0)

PAGE.AlternativeOutputFormats: [{alternate {rss application/rss+xml index alternate false false true false false 0} /hugo/index.xml https://frontiersoftware.co.za/hugo/index.xml}]

PAGE.Content

PAGE.CurrentSection: Page(/hugo/_index.md)

PAGE.Data

PAGE.Eq

PAGE.File: hugo/_index.md

PAGE.FirstSection: Page(/hugo/_index.md)

PAGE.Fragments: {[0xc001f22fc0] [creating-a-basic-skeleton directory-structure draft-future-and-expired-contenthttpsgohugoiogetting-startedusagedraft-future-and-expired-content front-matterhttpsgohugoiocontent-managementfront-matter frontmatter-accessors layouts_defaultsbaseofhtml layouts_defaultshomehtml layouts_defaultslisthtml layouts_defaultssinglehtml layoutspartialsmenuhtml layoutspartialstermshtml page-methodshttpsgohugoiomethodspage themes] map[creating-a-basic-skeleton:0xc001f22ec0 directory-structure:0xc001f23000 draft-future-and-expired-contenthttpsgohugoiogetting-startedusagedraft-future-and-expired-content:0xc001f23700 front-matterhttpsgohugoiocontent-managementfront-matter:0xc001f23680 frontmatter-accessors:0xc001f23800 layouts_defaultsbaseofhtml:0xc001f230c0 layouts_defaultshomehtml:0xc001f233c0 layouts_defaultslisthtml:0xc001f231c0 layouts_defaultssinglehtml:0xc001f232c0 layoutspartialsmenuhtml:0xc001f235c0 layoutspartialstermshtml:0xc001f234c0 page-methodshttpsgohugoiomethodspage:0xc001f23780 themes:0xc001f238c0]}

PAGE.FuzzyWordCount : 0

PAGE.GetPage PATH

PAGE.HeadingsFiltered: []

PAGE.OutputFormats: [{canonical {html text/html index canonical false true false false true 10} /hugo/ https://frontiersoftware.co.za/hugo/} {alternate {rss application/rss+xml index alternate false false true false false 0} /hugo/index.xml https://frontiersoftware.co.za/hugo/index.xml}]

PAGE.Resources: [skeleton_home.png]

Pages Methods

Sort Orders

Inserting strings is called interpolation. Extracting substrings could be called extrapolation.

Some common synonyms of interpolate are insert, insinuate, intercalate, interject, interpose, and introduce. While all these words mean “to put between or among others,” interpolate applies to the inserting of something extraneous or spurious. https://www.merriam-webster.com/thesaurus/interpolate

Themes

blowfish

menus

Directory traversal I’ve developed my own homegrown way of recursively walking a Hugo site’s content tree as described in this discourse thread since the official way of putting the menu in the site config file isn’t what I want as I add and remove pages. With more experience, I changed the deprecated template with an inline partial My code for layouts/partials/menu.html looks like this: <nav> {{ partial "inline/walk.html" (dict "dir" .

branch

Sections vs Taxonomies An imortant difference between content/mysection and content/mytaxonony is there may not be an _index.md file in a taxonomy whereas there should be for a section.

leaf

Files named index.md (as opposed to _index.md) are leaves, and use layouts/single.html as their template.