Converting Simple Web Page Into Hugo Theme Part 4 - Externalized Configuration
February 11, 2019
Externalizing theme configuration
Everything so far looks OK but navigation is hardcoded in sidebar but it should be configurable so that one can enable/disable/change some options.
Hugo pulls site configuration from two places, global site config file (blogv1/config.toml
) and theme config file (blogv1/themes/only-bones/config.yaml
). Some properties from site config file cannot be overriden by theme config file, more on that here.
Notice different files extensions of the config files. It doesn’t matter as Hugo supports toml, yaml and json format (BTW, you can convert between these configurations (and see what changes) using toolkit.site).
<nav class="main-nav">
<h3>{{ .Site.Title }}</h3>
<ul class="nav">
{{ range .Site.Menus.main }}
<li>
<a href="{{ .URL }}">
{{ .Pre }}
<span>{{ .Name }}</span>
</a>
</li>
{{ end }}
</ul>
<ul class="social">
{{ range .Site.Params.social }}
{{ if .enabled }}
<li>
<a href="{{ .url }}" {{ if ne .name "email" }} target="_blank" rel="noopener" {{ end }} >
{{ .name }}
</a>
</li>
{{ end }}
{{ end }}
</ul>
</nav>
What we did here is that we’ll populate nav menu and social icons from configuration file so that they can be changes when needed.
Our blogv1/config.toml
that will populate nav menu looks like this:
[menu]
[[menu.main]]
identifier = "blog"
name = "Blog"
title = "Blog"
url = "/posts/"
weight = -110.0
[[menu.main]]
identifier = "about"
name = "About"
title = "About"
url = "/about/"
weight = -109.0
[params]
[[params.social]]
name = "linkedin"
url = ""
enabled = true
[[params.social]]
name = "email"
url = "mailto:"
enabled = true
[[params.social]]
name = "twitter"
url = ""
enabled = false
[[params.social]]
name = "github"
url = ""
enabled = false
[[params.social]]
name = "gitlab"
url = ""
enabled = false
[[params.social]]
name = "rss"
url = "/index.xml"
enabled = true
[analytics]
id = "UA-111111111-2"
enabled = true
menu configuration is accessed using Hugos .Site.Menu
struct and social configuration using .Site.Params
struct.
Well use analtyics settings to populate partials/footer.html
:
{{ with .Site.Params.analytics}}
{{ if index . "enabled"}}
<footer>
<script async src="https://www.googletagmanager.com/gtag/js?id={{ index . "id" }}"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '{{ index . "id" }}');
</script>
</footer>
{{ end }}
{{ end }}
Hugos with
function automatically handles case when a config is not defined, it’ll simply skip the enclosing block.
If config is defined it’ll set parsed config object into context so that its properties can be easily accessed using .
notation.
Read more about with
here.
In this case [analytics]
block from config is parsed into ordinary Go map whose entries can be accessed using index
function. More on index
here.
With footer defined, include it into baseof.html layout so that it appears on every page:
<!DOCTYPE html>
<html>
{{- partial "header" . -}}
<body>
<div class="wrapper">
{{- partial "sidebar" . -}}
{{- block "main" . }}{{- end }}
</div>
</body>
{{- partial "footer" . -}}
</html>
In the next part, we’ll see how to use Hugo’s templating to conveniently add some icons for social and nav buttons.