“Easy to build, fun to customize, and the loading time is just super-fast!”
What is Hugo?
Hugo is a Static Site Generator (SSG) that is getting traction in the world of website-building. As a static site, there are some limitations to its functionalities. But here are some of the reasons why I love to use Hugo:
- very fast
- easily customizable
- simple to understand & start
- seamless integration with third-party APIs
- did I mention it’s fast?
In this post, I shall share how to build a simple, functional blog that you can style yourself with a bit of CSS using Bootstrap 5.
Using a framework like Bootstrap or Bulma makes website building a lot faster so that you can focus on creating content!
Why is Hugo fast?
- Written in Go (Golang)
- Go is a programming language created at Google which is expressive, lightweight, concise, and efficient. One of its best feature is its concurrent processing where multiple lines of code are run in a single moment. That’s why its so fast!
- No database or dependencies
- A static site does not need a database. It is just codes and media like pictures, videos or sounds. Hugo sites also run without any dependencies on expensive runtimes such as PHP or Python.
Static sites are not suitable to build every type of website. However, Hugo is best to build:
- blogs,
- company websites (eCommerce),
- portfolio websites,
- documentation websites,
- website with a single landing page,
- or sites with thousands of pages.
If you’d like to build any of the above type of website, read on. Comment if you’d like me to share other types of tutorial.
This is the preview of the website we are building in this tutorial:
Install Hugo
Let us begin by installing Hugo on our computer. You can check out their website for different installation methods or based on your device. For this example, I will download and extract the zip file in a Windows 10 machine.
1. Create the Hugo Directory
Open Windows Explorer and create a new folder in the C:\
directory called Hugo (capital H for Hugo) or C:\Hugo
. Inside the Hugo folder, create a file called bin or C:\Hugo\bin
2. Downloading Hugo
Before downloading, you would need to know if your computer is on a 32-bit or 62-bit operating system at the Device Specifications in the System settings. To do that, open Windows Explorer and right-click on This PC
and click on Properties (or you could right-click at Start button and click on System).
Then, you can proceed to the releases page to download the respective zipped folder into the C:\Hugo\bin
created earlier.
Then proceed to extract hugo.exe
, LICENSE
and README.md
into the C:\Hugo\bin
that we created earlier.
3. Add Hugo to Windows PATH settings
Once you have moved the files, you would need to add Hugo to Windows Path Settings. Go to the Device Specifications where you found your OS type (32-bit or 64-bit) earlier.
Then click on New and type C:\Hugo\bin
where hugo.exe
is located in your device.
Then click OK to exit at every window.
To verify that your installation is correct, open Command Prompt (Click start or Windows button, type
cmd
and click Enter). When you typehugo help
and click enter, an output should appear that starts withhugo is the main command, used to build your Hugo site. Hugo is a Fast and Flexible Static Site Generator built with love by spf13 and friends in Go. Complete documentation is available at http://gohugo.io/.
When you type
path
and click Enter, among the path available, you should also see:C:\Hugo\bin
Creating your Hugo website
I will be using Visual Studio Code, a source code editor by Microsoft for Windows, Linus or MacOS. So if you are not using Windows, don’t worry, you can still follow along as the command and the interface will be similar.
1. Create a folder
Since you have installed Hugo on your PATH settings, you can use it anywere in your Windows device (if you’re having trouble with getting Hugo in your PATH, run the create new hugo site command inside C:\Hugo\bin
instead).
2. Open Source Code Editor
When the command prompt appears, type code .
like so, and click Enter:
C:\Documents\MyBlog>code .
To open Visual Studio Code from Terminal in MacOS, can check out their documentation here.
3. Create new Hugo site
A good thing about Visual Studio Code is that it comes packed with its own Terminal. To open it, click Ctrl + `
simultaneously.
Then type hugo new site myblog
in the Terminal (myblog
is just a folder name. You can replace it with any name that you like. It does not determine your website name or other values):
C:\Documents\MyBlog>hugo new site myblog
When you click Enter, a few files and folders are created for you in the following manner:
.
├── archetypes
│ └── default.md
├── content
├── data
├── layouts
├── static
├── themes
└── config.toml
Congratulations, your new Hugo site is built! Let’s start this adventure!
Creating your own theme
Since Hugo is a static site generator, you’d need to employ your knowledge of basic HTML, CSS and JS to design how it looks and how it functions.
Here is an introduction to that topic.
For this tutorial, we are diving into the creation of our own customizable theme with the help of Bootstrap 5. If you are more into ready-made themes, there are plethoras of beautiful, open-sourced Hugo themes available at Hugo Themes Collection.
Create a Hugo skeleton theme
Hugo comes with a command to create a skeleton theme which I will use to develop this blog. To do that:
(Change Directory) cd into myblog
C:\Documents\MyBlog>cd myblog
Use the hugo new theme command and name your theme. Let’s name it
four
C:\Documents\MyBlog\myblog>hugo new theme four
Hugo will create your new theme files that look like this:
.
├── archetypes
│ └── default.md
├── content
├── data
├── layouts
├── resources
│ └── _gen
│ ├── assets
│ └── images
├── static
├── themes
│ └── four
│ ├── archetypes
│ │ └── default.md
│ ├── layouts
│ │ ├── _default
│ │ │ ├── baseof.html
│ │ │ ├── list.html
│ │ │ └── single.html
│ │ ├── partials
│ │ │ ├── footer.html
│ │ │ ├── head.html
│ │ │ └── header.html
│ │ ├── 404.html
│ │ └── index.html
│ ├── static
│ │ ├── css
│ │ └── js
│ ├── LICENSE
│ └── theme.toml
└── config.toml
In the layouts
folder, notice that only baseof.html
comes pre-filled. If you’re familiar with HTML, notice its similarities. But with Golang, it comes with curly brakcets {} codes.
Hugo is designed so that each section is coded separately (as partials) and is combined to create complete html templates throughout your website pages or when you want to. This is similar to Python method of programming where it employs the DRY (Don’t Repeat Yourself) method.
Install Bootstrap
To use Bootstrap 5 in our website, let’s visit their website for the documentation.
- Create new folder in your
four
themes folder calledassets
. Then create two folders calledcss
andjs
in theassets
folder. It should look like so:
four
└── assets
├── css
└── js
- Download the Compiled CSS and JS files from their website. Extract
bootstrap.min.css
into css folder and create a new file calledstyle.css
for any custom changes that we might have. Similarly, extractbootstrap.bundle.min.js
into the js folder created earlier. The structure should like this so far:
four
└── assets
├── css
│ ├── bootstrap.bundle.min.css
│ └── style.css
└── js
└── bootstrap.bundle.min.js
Add the following code inside style.css
:
section {
min-height: 50vh;
}
#heroFour .carousel-item > img {
height: 70vh;
object-fit: cover;
object-position: 50% 50%;
}
baseof.html
- Beside the html tag, add lang=“en” to follow Bootstrap’s Starter Template.
- We are using the row and columns functions to create a responsive sidebar. Add a partial called
sidebar.html
(create a new file calledsidebar.html
in the partial folder). - Add also a partial called
scripts.html
(create a new file calledscripts.html
in the partial folder too). - Your
baseof.html
should look like this:
<!DOCTYPE html>
<html lang="en">
{{- partial "head.html" . -}}
<body>
{{- partial "header.html" . -}}
<div class="container p-3">
<div class="row">
<div class="col-sm-7">{{- block "main" . }}{{- end }}</div>
<div class="col-sm-5">{{- partial "sidebar.html" . -}}</div>
</div>
</div>
{{- partial "footer.html" . -}} {{- partial "scripts.html" . -}}
</body>
</html>
- For the partial
scripts.html
, add the following and click save:
{{ $bootstrapbundle := resources.Get "js/bootstrap.bundle.min.js" }}
<script src="{{ $bootstrapbundle.Permalink }}"></script>
<!-- Add your custom JS below this line -->
$bootstrapbundle is a variable to retrieve the asset file that is inside the assets folder. This method is especially handy if you’d like to use Hugo built-in features such as to minify or fingerprint files stored in assets folder.
head.html
For the partial head.html
, add the following dependencies and click save:
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<!-- Generator -->
{{- hugo.Generator }}
<!-- Bootstrap CSS -->
{{ $bootstrap := resources.Get "/css/bootstrap.min.css" }}
<link rel="stylesheet" href="{{ $bootstrap.Permalink }}" as="style" />
<!-- Fontawesome Icons -->
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css"
integrity="sha512-iBBXm8fW90+nuLcSKlbmrPcLa0OT92xO1BIsZ+ywDWZCvqsWgccV3gFoRBv0z+8dLJgyAHIhR35VZc2oM/gI1w=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
/>
<!-- Custom CSS -->
{{ $style := resources.Get "/css/style.css" | minify | fingerprint }}
<link rel="stylesheet" href="{{ $style.Permalink }}" as="style" />
<!-- Title -->
{{ $title := print .Title " | " .Site.Title }} {{ if .IsHome }}{{ $title =
.Site.Title }}{{ end }}
<title>{{ $title }}</title>
<!-- Favicon -->
<link rel="icon" href="{{- .Site.Params.favicon | default "favicon.ico" |
absURL -}}" sizes="256x256"> {{ template "_internal/disqus.html" . }} {{
template "_internal/google_news.html" . }} {{ template
"_internal/google_analytics.html" . }} {{ template
"_internal/google_analytics_async.html" . }} {{ template
"_internal/opengraph.html" . }} {{ template "_internal/schema.html" . }} {{
template "_internal/twitter_cards.html" . }}
</head>
Variables
As you can see, the $style variable is minified and fingerprinted. Minify will optimize the size of your files and fingerprint will generate random numbers after your style.css to keep your website following the latest updated version.
Site Variables and config.toml
Any variable that begins with .Site such as .Site.Title will be called in the config.toml. This means that you can have a standardized value for your whole website in the config file. You can also use config.yaml or config.json based on your language preference.
Template
I have also added some Hugo ready-made Internal Templates for most common use cases.
header.html
For the partial header.html
, add the following and click save:
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container-fluid">
<a class="navbar-brand" href="{{ "/" | relURL }}">{{ .Site.Title}}</a>
<!-- Activated for mobile view -->
<button
class="navbar-toggler"
type="button"
data-bs-toggle="collapse"
data-bs-target="#navbarSupportedContent"
aria-controls="navbarSupportedContent"
aria-expanded="false"
aria-label="Toggle navigation"
>
<span class="navbar-toggler-icon"></span>
</button>
<!-- Menu Start -->
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
{{ range .Site.Menus.main }}
<li class="nav-item">
{{ $text := print .Name | safeHTML }}
<a class="nav-link" title="{{ $text }}" href="{{ .URL }}">
{{ $text }}
</a>
</li>
{{ end }}
</ul>
<div class="navbar-nav d-flex flex-row justify-content-around">
{{ range .Site.Menus.social }}
{{ $title := print .Title | safeHTML }}
<a class="nav-link" title="{{ $title }}" href="{{ .URL }}">
{{ $text := print .Name | safeHTML }}
<i class="{{ $text }}"></i>
</a>
{{ end }}
</div>
</div>
<!-- Menu End -->
</div>
</nav>
footer.html
For the partial footer.html
, add the following and click save:
<footer class="footer text-center bg-dark py-5 text-light">
<!-- Change YourName to any name of your choice -->
<p>Copyright © {{ now.Format "2006"}} YourName</p>
<p>
Designed by
<a class="link-secondary" href="https://www.heksagon.net/">Heksagon</a> with
love ❤
</p>
<p>
<a class="link-secondary" href="#">Back to top</a>
</p>
</footer>
sidebar.html
For the partial sidebar.html
, add the following and click save:
<div class="card mx-3 my-5 p-3">
<h2>Sidebar</h2>
<p>
Add any function that you like in the <code>sidebar.html</code> partial.
</p>
</div>
404.html
404 page is a page where visitors are redirected to when the url after your domain name is invalid. In order for it to load in that logic, there needs to be some customizations for different servers and automatic in others. Hugo also provides some guidelines for websites serving under these environments:
- GitHub Pages and GitLab Pages.
- Apache.
- Nginx.
- Amazon AWS S3.
- Amazon CloudFront.
- Caddy Server.
- Netlify.
- Azure Static website.
If you just want to test it out in live preview, just go to http://localhost:1313/404.html
Outside the partials
folder, in the layouts
folders, there are two files that were created which are 404.html
and index.html
. In the 404.html
, add the following:
{{ define "main" }}
<section id="main" class="text-center d-flex flex-column justify-content-center">
<h1>Page Not Found</h1>
<div>
<h1><a class="btn btn-lg btn-outline-secondary" href="{{ "/" | relURL }}">Go Home</a></h1>
</div>
</section>
{{ end }}
metadata.html
index.html
which is placed in the root folder of your web server is widely known as the home page. Before we proceed to create the home page, in the partials folder, create a metadata.html
to call the date of the blog post. You can also have aditional information such as tags, author name, and many more. But for this tutorial, we will just add the date of post as metadata like so:
{{ $dateTime := .PublishDate.Format "2006-01-02" }} {{ $dateFormat :=
.Site.Params.dateFormat | default "Jan 2, 2006" }}
<i class="far fa-calendar-alt"></i>
<time datetime="{{ $dateTime }}">{{ .PublishDate.Format $dateFormat }}</time>
index.html
The home page. I added a few of Bootstrap’s template to get you started as soon as possible. Edit to showcase your creativity!
<!DOCTYPE html>
<html lang="en">
{{- partial "head.html" . -}}
<body>
{{- partial "header.html" . -}}
<!-- Hero Carousel -->
<section id="heroFour" class="carousel slide" data-bs-ride="carousel">
<div class="carousel-indicators">
<button type="button" data-bs-target="#heroFour" data-bs-slide-to="0" class="active" aria-current="true" aria-label="Slide 1"></button>
<button type="button" data-bs-target="#heroFour" data-bs-slide-to="1" aria-label="Slide 2"></button>
<button type="button" data-bs-target="#heroFour" data-bs-slide-to="2" aria-label="Slide 3"></button>
</div>
<div class="carousel-inner">
<div class="carousel-item active">
<img src="{{ "/img/hero1.webp" | relURL }}" class="d-block w-100" alt="...">
<div class="carousel-caption d-md-block">
<h1>Life is either a daring adventure or nothing at all</h1>
<p>Helen Keller</p>
</div>
</div>
<div class="carousel-item">
<img src="{{ "/img/hero2.webp" | relURL }}" class="d-block w-100" alt="...">
<div class="carousel-caption d-md-block">
<h1>Traveling – it leaves you speechless, then turns you into a storyteller</h1>
<p>Ibn Battuta</p>
</div>
</div>
<div class="carousel-item">
<img src="{{ "/img/hero3.webp" | relURL }}" class="d-block w-100" alt="...">
<div class="carousel-caption d-md-block">
<h1>Life’s a journey not a destination</h1>
<p>Aerosmith</p>
</div>
</div>
</div>
<button class="carousel-control-prev" type="button" data-bs-target="#heroFour" data-bs-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
<span class="visually-hidden">Previous</span>
</button>
<button class="carousel-control-next" type="button" data-bs-target="#heroFour" data-bs-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true"></span>
<span class="visually-hidden">Next</span>
</button>
</section>
<!-- Our Values -->
<section class="py-5">
<h2 class="text-center">We are committed</h2>
<div class="container">
<div class="row align-items-center">
{{ range .Site.Params.values }}
<div class="col-12 col-sm-4 text-center py-5">
<i class="{{ .iconclass }} "></i>
<h2>{{ .title }}</h2>
<p>{{ .description }}</p>
</div>
{{ end }}
</div>
</div>
</section>
<!-- Jumbotron -->
<section class="py-5 bg-warning">
<div class="p-5 mb-4 rounded-3">
<div class="container-fluid py-5">
<h1 class="display-5 fw-bold">Custom jumbotron</h1>
<p class="col-md-8 fs-4">You are able to create this jumbotron, similar to previous versions of Bootstrap.</p>
<button class="btn btn-primary btn-lg" type="button">Button</button>
</div>
<div class="row align-items-md-stretch">
<div class="col-md-6">
<div class="h-100 p-5 text-white bg-dark rounded-3">
<h2>Dark background</h2>
<p>Swap the background-color utility and add a `.text-*` color utility to mix up the jumbotron look. Then, mix and match with your favourite choice.</p>
<button class="btn btn-outline-light" type="button">More ...</button>
</div>
</div>
<div class="col-md-6">
<div class="h-100 p-5 bg-light border rounded-3">
<h2>Add borders</h2>
<p>You can also keep it light and add a border for some added definition to the boundaries of your content. </p>
<button class="btn btn-outline-secondary" type="button">Be Creative</button>
</div>
</div>
</div>
</div>
</section>
<!-- Blog Section -->
<section class="album py-5 bg-light">
<div class="text-center py-5">
<h2 class="fs-1">Blog</h2>
<p class="fs-4 text-muted">Latest Article</p>
</div>
<div class="container">
<div class="row d-flex justify-content-center">
{{ range (.Paginator 3).Pages.ByPublishDate.Reverse }}
<div class="col-sm-4 my-3">
<div class="card shadow-sm">
<img class="bd-placeholder-img card-img-top" width="100%" height="225" src="{{ .Params.cover.image }}" style="object-fit: cover;"></img>
<div class="card-body">
<h3 class="card-text">{{ .Title }}</h3>
<p class="card-text">{{ partial "metadata.html" . }}: {{ .Params.description }}</p>
<div class="d-flex justify-content-between align-items-center">
<div class="btn-group">
<a href="{{ .RelPermalink }}">
<button type="button" class="btn btn-sm btn-outline-secondary"> View</button></a>
</div>
<div class="btn-group">
{{ with .Params.tags }}
{{ range . }}
{{ $href := print (absURL "tags/") (urlize .) }}
<a class="btn btn-sm btn-outline-secondary" href="{{ $href }}">{{ . }}</a>
{{ end }}
{{ end }}
</div>
</div>
</div>
</div>
</div>
{{ end }}
</div>
<p class="text-end">
<a href="{{ "/posts/" | relURL }}">More...</a>
</p>
</div>
</section>
<!-- Contact Section -->
<section id="contact" class="py-5 bg-warning" style="background-image: url(/img/map-image.png);background-size: contain;background-repeat: no-repeat;">
<div class="container">
<div class="row">
<div class="col-sm-6 d-flex align-items-center">
<h2>Contact Us</h2>
</div>
<div class="col-sm-6">
<form action="">
<div class="m-3">
<label for="exampleFormControlInput1" class="form-label">Email address</label>
<input type="email" class="form-control" id="exampleFormControlInput1" placeholder="your@email.com">
</div>
<div class="m-3">
<label for="exampleFormControlTextarea1" class="form-label">Your messsage here:</label>
<textarea class="form-control" id="exampleFormControlTextarea1" rows="3"></textarea>
</div>
</form>
</div>
</div>
</div>
</section>
{{- partial "footer.html" . -}}
{{- partial "scripts.html" . -}}
</body>
</html>
Contact Section
In the contact section, the form here can be replaced with form providers such as Formspree.io or Formsubmit.io so website visitors can contact you. It also possible to code your own PHP function to receive submissions.
config.toml
This file is used to store main information regarding a Hugo website, integrate certain features and call images. All of the value in this file is adjusted based on your website needs. The most important thing is to link with the theme that was created:
theme = "four"
BaseURL is your website domain name, title is your website title, your own Google Analytics ID and your own Disqus Short Name. Here is a short example that I used for this Hugo tutorial:
baseURL = "http://example.org/"
languageCode = "en-us"
title = "Four: Travel Blog"
theme = "four"
googleAnalytics = "UA-PROPERTY_ID/G-MEASUREMENT_ID"
disqusShortname = "yourdiscussshortname"
[params]
description = "Open Graph Description"
images = [ "/img/hero1.webp" ]
title = "Four: Travel Blog"
favicon = "img/world-map-pin.svg"
[[params.values]]
iconclass = "fas fa-pen text-primary fa-3x py-3"
title = "Blog"
description = "Dedicated to sharing insightful information"
[[params.values]]
iconclass = "fas fa-bolt text-primary fa-3x py-3"
title = "Speed"
description = "Our priority in getting the job done fast"
[[params.values]]
iconclass = "fas fa-comment text-primary fa-3x py-3"
title = "Chat"
description = "Keep in touch with us to know more"
[minify]
minifyOutput = true
[[menu.main]]
identifier = "blog"
name = "Posts"
url = "/posts/"
weight = 1
[[menu.main]]
identifier = "Contact"
name = "Contact"
url = "/#contact"
weight = 2
[[menu.main]]
identifier = "tags"
name = "Tags"
url = "/tags"
weight = 3
[[menu.social]]
name = "fab fa-twitter fa-2x link-info"
title = "Twitter"
url = "/"
weight = 1
[[menu.social]]
name = "fab fa-youtube fa-2x link-danger"
title = "Youtube"
url = "/"
weight = 2
Images
Images are one of the most important elements of a website. They make your website colourful and interesting. If not optimized, it can also slow down your website loading speed. Notice that in this example, most of the images used are in webp format.
I wrote a short article regarding optimizing images to WebP format.
In the static folder for the four
theme, create a new folder called img
to keep images for the config.toml
and index.html
:
static
├── css
├── img
│ ├── hero1.webp
│ ├── hero2.webp
│ ├── hero3.webp
│ ├── map-image.png
│ └── world-map-pin.svg
└── js
Hugo Default layout
In the themes layouts folder, there is another folder called _default
which stores the basic Hugo layouts:
list.html
is the layout template to list all blog postssingle.html
is the layout template to list a single postterms.html
is the layout template to list taxonomies. In this examples, onlytags
taxonomy is used.
Each layout is styled based on suitable Bootstrap classes:
list.html
{{ define "main" }}
<h1>{{ .Title }}</h1>
<div class="row d-flex justify-content-center">
{{ range .Pages.ByPublishDate.Reverse }}
<div class="col-lg-6 my-3">
<div class="card shadow-sm">
<img class="bd-placeholder-img card-img-top" width="100%" height="225" src="{{ .Params.cover.image }}" style="object-fit: cover;"></img>
<div class="card-body">
<h3 class="card-text">{{ .Title }}</h3>
<p class="card-text">{{ partial "metadata.html" . }}: {{ .Params.description }}</p>
<div class="d-flex justify-content-between align-items-center">
<div class="btn-group">
<a href="{{ .RelPermalink }}">
<button type="button" class="btn btn-sm btn-outline-secondary"> View</button></a>
</div>
<div class="btn-group">
{{ with .Params.tags }}
{{ range . }}
{{ $href := print (absURL "tags/") (urlize .) }}
<a class="btn btn-sm btn-outline-secondary" href="{{ $href }}">{{ . }}</a>
{{ end }}
{{ end }}
</div>
</div>
</div>
</div>
</div>
{{ end }}
</div>
{{ end }}
single.html
{{ define "main" }}
<h1>{{ .Title }}</h1>
<img
class="w-100"
src="{{ .Params.cover.image }}"
alt="{{ .Params.cover.alt }}"
/>
<p class="text-center">{{ .Params.cover.caption }}</p>
<div class="row text-center">
<div class="col">{{ partial "metadata.html" . }}</div>
<div class="col">
<div class="btn-group">
{{ with .Params.tags }} {{ range . }} {{ $href := print (absURL "tags/")
(urlize .) }}
<a class="btn btn-sm btn-outline-secondary" href="{{ $href }}">{{ . }}</a>
{{ end }} {{ end }}
</div>
</div>
</div>
<br /><br />
{{ .Content }} {{- partial "disqus.html" . -}} {{ end }}
terms.html
{{- define "main" }}
<section class="row">
<div class="has-text-centered">
<h1 class="fs-1">{{ .Title }}</h1>
<p>{{ .Description }}</p>
</div>
<div class="col">
<div class="container">
<ul class="list-group">
{{- $type := .Type }} {{- range $key, $value := .Data.Terms.Alphabetical
}} {{- $name := .Name }} {{- $count := .Count }} {{- with $.Site.GetPage
(printf "/%s/%s" $type $name) }}
<li class="list-group-item btn btn-sm btn-outline-secondary">
<a
class="stretched-link text-decoration-none link-secondary fs-4"
href="{{ .Permalink }}"
>{{ .Name }}
<sup
><strong class=""><sup>{{ $count }}</sup></strong></sup
></a
>
</li>
{{- end }} {{- end }}
</ul>
</div>
</div>
</section>
{{- end }}{{/* end main */ -}}
Comment Section
Notice in single.html
, there is a partial that wasn’t created, disqus.html
. This partial is already included in the internal templates declared at the head.html
. However, Hugo recommends to add the following partial called disqus.html
to avoid unwanted discussions with associated Disqus account in the localhost environment:
<div id="disqus_thread"></div>
<script type="text/javascript">
;(function () {
// Don't ever inject Disqus on localhost--it creates unwanted
// discussions from 'localhost:1313' on your Disqus account...
if (window.location.hostname == 'localhost') return
var dsq = document.createElement('script')
dsq.type = 'text/javascript'
dsq.async = true
var disqus_shortname = '{{ .Site.DisqusShortname }}'
dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js'
;(
document.getElementsByTagName('head')[0] ||
document.getElementsByTagName('body')[0]
).appendChild(dsq)
})()
</script>
<noscript
>Please enable JavaScript to view the
<a href="https://disqus.com/?ref_noscript"
>comments powered by Disqus.</a
></noscript
>
<a href="https://disqus.com/" class="dsq-brlink"
>comments powered by <span class="logo-disqus">Disqus</span></a
>
If you like to use other comment providers as suggested by Hugo, you can
- remove Disqus internal template in
head.html
- remove the Disqus Shortname is
config.toml
and - change the partial in
single.html
to a comment provider of choice
Blog Content
Write a blog
This blog project is almost complete. Now run the following in the terminal:
C:\Documents\MyBlog\myblog>hugo new posts/post1.md
This command creates a new posts
folder inside content
folder with a markdown file called post1.md
:
---
title: 'Post1'
date: 2021-04-01T23:11:13Z
draft: true
---
These three variables are called Front Matter and are based on the template in default.md
in the archetypes
folder. You can adjust your defaults there so that when you run hugo new
, your desired template appears. I will just adjust post1.md to be as such:
---
title: 'My First Post'
date: 2021-04-01T23:11:13Z
draft: true
tags: ['Africa', 'adventure']
description: 'This is the first post description'
images: ['/img/post1.webp']
cover:
image: '/img/post1.webp'
alt: 'This is a random image from Unsplash'
caption: 'This is a random image from Unsplash'
---
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua. Pellentesque eu tincidunt tortor
aliquam nulla facilisi cras fermentum odio. A erat nam at lectus urna duis. Sed
velit dignissim sodales ut eu sem. Lectus urna duis convallis convallis tellus.
Diam sit amet nisl suscipit adipiscing bibendum est. Sed felis eget velit
aliquet sagittis id consectetur. Vulputate dignissim suspendisse in est ante in
nibh mauris cursus. Morbi quis commodo odio aenean. Mollis nunc sed id semper
risus in hendrerit gravida rutrum. Ac ut consequat semper viverra nam. Hac
habitasse platea dictumst vestibulum rhoncus. Amet porttitor eget dolor morbi
non. Justo eget magna fermentum iaculis eu non. Id eu nisl nunc mi ipsum
faucibus vitae aliquet nec. Aliquam id diam maecenas ultricies. Non sodales
neque sodales ut etiam. Amet massa vitae tortor condimentum lacinia quis. Erat
imperdiet sed euismod nisi porta. Nisl suscipit adipiscing bibendum est
ultricies integer quis auctor. Viverra suspendisse potenti nullam ac. Tincidunt
id aliquet risus feugiat in. Varius quam quisque id diam vel. Egestas erat
imperdiet sed euismod nisi. Scelerisque felis imperdiet proin fermentum leo vel
orci porta non. Ut faucibus pulvinar elementum integer. Fermentum odio eu
feugiat pretium nibh ipsum consequat nisl.
Blog Images
Create a new file in the main static
folder called img
and save all your images for your blog posts here. This is to segregate your blog content and your theme images for easier editing and website management later on.
.
├── archetypes
│ └── default.md
├── content
├── data
├── layouts
├── static
│ └── img
│ └── post1.webp
├── themes
└── config.toml
Live Preview
Finally, the time to test your site in a web environment. Hugo comes with a built-in live preview capability with Hugo server. Just need to run the following command in the terminal (-D is with drafts enabled to view our drafted First Post):
C:\Documents\MyBlog\myblog>hugo server -D
Go to any web browser and run http://localhost:1313/. You should be able to see and explore your completed site now. Save after you make any changes to view the change taking place live.
Deploy to a Live Site
After you have made changes and want your website to be accessible from your purchased domain name, here are the steps:
1. Purchase a domain name and hosting
If you plan to monetize your website or establish an authority, having your own domain is the way to go. Here are a few recommended web hosting providers which helps me earn a small commission if you register with these links:
For free web hosting for static sites, can check out the following links:
2. draft: false
Change the front matter from draft true to false and check all functions, images and styling works in live preview.
3. Generate Static Site
Once everything is ready for production, run the following command
C:\Documents\MyBlog\myblog>hugo
Hugo will generate a complete static site (HTML, CSS, JS) in the public folder. To make your website live, you’d just need to put the contents of this folder in the root folder of your website.
Conclusion
Congratulations! Your Website is now LIVE in the World Wide Web. If you’d like me to do more tutorials like this, do share in the comment section here. This Hugo tutorial covers only the basic of creating a functional but simple blog using Bootstrap 5.
Check out the preview of the live site that is built in this article: