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.
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:
Union file system
If you think you need a symbolic link in your project directory, use Hugo’s union file system instead.
I discovered the above the hardway. I wanted to use common layout files across several sites, and thought I’d do this the traditional Unix way with symbolic links. While this worked for layouts, when I tried to do this with content I got weird bugs because some “softlinked” files were ignored by Hugo.
Exactly what I wanted to achieve is covered by Hugo’s modules which I initially found incomprehensible because it’s built on Go’s module system, requiring a go.mod file and complicated pathnames like github.com/my/repo
which is weird if you’re not using github.
Anyways, it turns out none of that is necessary if you simply add a {"module": { "mounts": ...}}
section to your site configuration file as described in Union file system.
An advantage over symbolic links is global files can be kept in the module’s directories and local files in the given site’s directories.
Types
Object and method names are capitalized. Although not required, to avoid confusion we recommend beginning variable and map key names with a lowercase letter or underscore.
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.
- The draft value is true
- The date is in the future
- The publishDate is in the future
- The expiryDate is in the past
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-04-12 11:09:09 +0200 +0200
PAGE.Draft false
PAGE.GetTerms "artists" Pages(0)
PAGE.Title Hugo
PAGE.LinkTitle hugo
PAGE.Params map[date:2024-01-15 13:34:29 +0200 +0200 draft:false iscjklanguage:false lastmod:2024-04-12 11:09:09 +0200 +0200 linktitle:hugo publishdate:2024-01-15 13:34:29 +0200 +0200 title:Hugo]
PAGE.Sitemap { -1 sitemap.xml false}
PAGE.Aliases []
Links
PAGE.Permalink https://frontiersoftware.co.za/html-tools/hugo/
PAGE.RelPermalink /html-tools/hugo/
PAGE.GitInfo
.AuthorDate 2024-04-12
.CommitDate 2024-04-12
.AuthorEmail robert.joeblog@gmail.com
.AuthorName Robert Laing
.Subject added jq section
PAGE.CodeOwners: []
PAGE.Kind: section
PAGE.Type: html-tools
PAGE.BundleType: branch
PAGE.AllTranslations: Pages(1)
PAGE.AlternativeOutputFormats: [{alternate {rss application/rss+xml index alternate false false true false false false false 0} /html-tools/hugo/index.xml https://frontiersoftware.co.za/html-tools/hugo/index.xml}]
PAGE.Content
PAGE.CurrentSection: Page(/html-tools/hugo)
PAGE.Data
PAGE.Eq
PAGE.File: _index
PAGE.FirstSection: Page(/html-tools)
PAGE.Fragments: {[0xc003128d80] [creating-a-basic-skeleton directory-structurehttpsgohugoiogetting-starteddirectory-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 types union-file-systemhttpsgohugoiogetting-starteddirectory-structureunion-file-system] map[creating-a-basic-skeleton:0xc003128c80 directory-structurehttpsgohugoiogetting-starteddirectory-structure:0xc003128dc0 draft-future-and-expired-contenthttpsgohugoiogetting-startedusagedraft-future-and-expired-content:0xc003129580 front-matterhttpsgohugoiocontent-managementfront-matter:0xc003129500 frontmatter-accessors:0xc0031296c0 layouts_defaultsbaseofhtml:0xc003128f40 layouts_defaultshomehtml:0xc003129240 layouts_defaultslisthtml:0xc003129040 layouts_defaultssinglehtml:0xc003129140 layoutspartialsmenuhtml:0xc003129440 layoutspartialstermshtml:0xc003129340 page-methodshttpsgohugoiomethodspage:0xc003129600 themes:0xc003129780 types:0xc003128ec0 union-file-systemhttpsgohugoiogetting-starteddirectory-structureunion-file-system:0xc003128e40]}
PAGE.FuzzyWordCount : 0
PAGE.GetPage PATH
PAGE.HeadingsFiltered: []
PAGE.OutputFormats: [{canonical {html text/html index canonical false true false false false false true 10} /html-tools/hugo/ https://frontiersoftware.co.za/html-tools/hugo/} {alternate {rss application/rss+xml index alternate false false true false false false false 0} /html-tools/hugo/index.xml https://frontiersoftware.co.za/html-tools/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