The documentation of the Hugo static site generator in one long page. LOOKING FOR MAINTAINER. Look at forks for improvements.
This is the documentation of Hugo condensed into one long page. I did this to make the documentation easier to search and navigate. This page was automatically generated using a Python script using the documentation available at Hugo’s GitHub repository.
Hugo is not your average static site generator.
Hugo is a general-purpose website framework. Technically speaking, Hugo is a static site generator. Unlike systems that dynamically build a page with each visitor request, Hugo builds pages when you create or update your content. Since websites are viewed far more often than they are edited, Hugo is designed to provide an optimal viewing experience for your website’s end users and an ideal writing experience for website authors.
Websites built with Hugo are extremely fast and secure. Hugo sites can be hosted anywhere, including Netlify, Heroku, GoDaddy, DreamHost, GitHub Pages, Surge, Aerobatic, Firebase, Google Cloud Storage, Amazon S3, Rackspace, Azure, and CloudFront and work well with CDNs. Hugo sites run without the need for a database or dependencies on expensive runtimes like Ruby, Python, or PHP.
We think of Hugo as the ideal website creation tool with nearly instant build times, able to rebuild whenever a change is made.
{{< youtube “CdiDYZ51a2o” >}}
In technical terms, Hugo takes a source directory of files and templates and uses these as input to create a complete website.
Hugo is for people that prefer writing in a text editor over a browser.
Hugo is for people who want to hand code their own website without worrying about setting up complicated runtimes, dependencies and databases.
Hugo is for people building a blog, a company site, a portfolio site, documentation, a single landing page, or a website with thousands of pages.
See what’s coming next in the Hugo roadmap.
The purpose of website generators is to render content into HTML files. Most are “dynamic site generators.” That means the HTTP server—i.e., the program that sends files to the browser to be viewed—runs the generator to create a new HTML file every time an end user requests a page.
Over time, dynamic site generators were programmed to cache their HTML files to prevent unnecessary delays in delivering pages to end users. A cached page is a static version of a web page.
Hugo takes caching a step further and all HTML files are rendered on your computer. You can review the files locally before copying them to the computer hosting the HTTP server. Since the HTML files aren’t generated dynamically, we say that Hugo is a static site generator.
This has many benefits. The most noticeable is performance. HTTP servers are very good at sending files—so good, in fact, that you can effectively serve the same number of pages with a fraction of the memory and CPU needed for a dynamic site.
To track Hugo’s progress, see our GitHub Milestones.
In no particular order, here are some other features currently being worked on:
Feel free to contribute to Hugo’s development, improve Hugo’s documentation, or open a new issue if you have an idea for a new feature.
{{% note %}}
Hugo v0.15 and later are released under the Apache 2.0 license.
Earlier versions of Hugo were released under the Simple Public License.
{{% /note %}}
Version 2.0, January 2004
http://www.apache.org/licenses/LICENSE-2.0
Terms and Conditions for use, reproduction, and distribution
“License” shall mean the terms and conditions for use, reproduction, and
distribution as defined by Sections 1 through 9 of this document.
“Licensor” shall mean the copyright owner or entity authorized by the copyright
owner that is granting the License.
“Legal Entity” shall mean the union of the acting entity and all other entities
that control, are controlled by, or are under common control with that entity.
For the purposes of this definition, “control” means (i) the power, direct or
indirect, to cause the direction or management of such entity, whether by
contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
“You” (or “Your”) shall mean an individual or Legal Entity exercising
permissions granted by this License.
“Source” form shall mean the preferred form for making modifications, including
but not limited to software source code, documentation source, and configuration
files.
“Object” form shall mean any form resulting from mechanical transformation or
translation of a Source form, including but not limited to compiled object code,
generated documentation, and conversions to other media types.
“Work” shall mean the work of authorship, whether in Source or Object form, made
available under the License, as indicated by a copyright notice that is included
in or attached to the work (an example is provided in the Appendix below).
“Derivative Works” shall mean any work, whether in Source or Object form, that
is based on (or derived from) the Work and for which the editorial revisions,
annotations, elaborations, or other modifications represent, as a whole, an
original work of authorship. For the purposes of this License, Derivative Works
shall not include works that remain separable from, or merely link (or bind by
name) to the interfaces of, the Work and Derivative Works thereof.
“Contribution” shall mean any work of authorship, including the original version
of the Work and any modifications or additions to that Work or Derivative Works
thereof, that is intentionally submitted to Licensor for inclusion in the Work
by the copyright owner or by an individual or Legal Entity authorized to submit
on behalf of the copyright owner. For the purposes of this definition,
“submitted” means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems, and
issue tracking systems that are managed by, or on behalf of, the Licensor for
the purpose of discussing and improving the Work, but excluding communication
that is conspicuously marked or otherwise designated in writing by the copyright
owner as “Not a Contribution.”
“Contributor” shall mean Licensor and any individual or Legal Entity on behalf
of whom a Contribution has been received by Licensor and subsequently
incorporated within the Work.
Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the Work and such
Derivative Works in Source or Object form.
Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable (except as stated in this section) patent license to make, have
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
such license applies only to those patent claims licensable by such Contributor
that are necessarily infringed by their Contribution(s) alone or by combination
of their Contribution(s) with the Work to which such Contribution(s) was
submitted. If You institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
Contribution incorporated within the Work constitutes direct or contributory
patent infringement, then any patent licenses granted to You under this License
for that Work shall terminate as of the date such litigation is filed.
You may reproduce and distribute copies of the Work or Derivative Works thereof
in any medium, with or without modifications, and in Source or Object form,
provided that You meet the following conditions:
You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets
replaced with your own identifying information. (Don’t include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same “printed page” as the copyright notice for easier identification within third-party archives.
{{< code file=“apache-notice.txt” download=“apache-notice.txt” >}}
Copyright yyyy
Licensed under the Apache License, Version 2.0 (the “License”);
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an “AS IS” BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
{{< /code >}}
If this is your first time using Hugo and you’ve already installed Hugo on your machine, we recommend the quick start.
{{% note %}}
This quick start uses macOS
in the examples. For instructions about how to install Hugo on other operating systems, see install.
You also need Git installed to run this tutorial.
{{% /note %}}
{{% note %}}
Homebrew
, a package manager for macOS
, can be installed from brew.sh. See install if you are running Windows etc.
{{% /note %}}
brew install hugo
To verify your new install:
hugo version
{{< asciicast HDlKrUrbfT7yiWsbd6QoxzRTN >}}
hugo new site quickstart
The above will create a new Hugo site in a folder named quickstart
.
{{< asciicast 1PH9A2fs14Dnyarx5v8OMYQer >}}
See themes.gohugo.io for a list of themes to consider. This quickstart uses the beautiful Ananke theme.
cd quickstart;\
git init;\
git submodule add https://github.com/budparr/gohugo-theme-ananke.git themes/ananke;\
# Edit your config.toml configuration file
# and add the Ananke theme.
echo 'theme = "ananke"' >> config.toml
{{< asciicast WJM2LEZQs8VRhNeuZ5NiGPp9I >}}
hugo new posts/my-first-post.md
Edit the newly created content file if you want. Now, start the Hugo server with drafts enabled:
▶ hugo server -D
Started building sites ...
Built site for language en:
1 of 1 draft rendered
0 future content
0 expired content
1 regular pages created
8 other pages created
0 non-page files copied
1 paginator pages created
0 categories created
0 tags created
total in 18 ms
Watching for changes in /Users/bep/sites/quickstart/{data,content,layouts,static,themes}
Serving pages from memory
Web Server is available at http://localhost:1313/ (bind address 127.0.0.1)
Press Ctrl+C to stop
Navigate to your new site at http://localhost:1313/.
Your new site already looks great, but you will want to tweak it a little before you release it to the public.
Open up config.toml
in a text editor:
baseURL = "http://example.org/"
languageCode = "en-us"
title = "My New Hugo Site"
theme = "ananke"
Replace the title
above with something more personal. Also, if you already have a domain ready, set the baseURL
. Note that this value is not needed when running the local development server.
{{% note %}}
Tip: Make the changes to the site configuration or any other file in your site while the Hugo server is running, and you will see the changes in the browser right away.
{{% /note %}}
For theme specific configuration options, see the theme site.
For further theme customization, see Customize a Theme.
{{< asciicast pWp4uvyAkdWgQllD9RCfeBL5k >}}
{{% note %}}
There is lots of talk about “Hugo being written in Go”, but you don’t need to install Go to enjoy Hugo. Just grab a precompiled binary!
{{% /note %}}
Hugo is written in Go with support for multiple platforms. The latest release can be found at Hugo Releases.
Hugo currently provides pre-built binaries for the following:
Hugo may also be compiled from source wherever the Go compiler tool chain can run; e.g., on other operating systems such as DragonFly BSD, OpenBSD, Plan 9, Solaris, and others. See https://golang.org/doc/install/source for the full set of supported combinations of target operating systems and compilation architectures.
Download the appropriate version for your platform from Hugo Releases. Once downloaded, the binary can be run from anywhere. You don’t need to install it into a global location. This works well for shared hosts and other systems where you don’t have a privileged account.
Ideally, you should install it somewhere in your PATH
for easy use. /usr/local/bin
is the most probable location.
If you are on macOS and using Homebrew, you can install Hugo with the following one-liner:
{{< code file=“install-with-homebrew.sh” >}}
brew install hugo
{{< /code >}}
For more detailed explanations, read the installation guides that follow for installing on macOS and Windows.
If you are on a Windows machine and use Chocolatey for package management, you can install Hugo with the following one-liner:
{{< code file=“install-with-chocolatey.ps1” >}}
choco install hugo -confirm
{{< /code >}}
Hugo uses govendor to vendor dependencies, but we don’t commit the vendored packages themselves to the Hugo git repository. Therefore, a simple go get
is not supported because the command is not vendor aware. You must use govendor
to fetch Hugo’s dependencies.
{{< code file=“from-gh.sh” >}}
go get github.com/kardianos/govendor
govendor get github.com/gohugoio/hugo
go install github.com/gohugoio/hugo
{{< /code >}}
govendor get
will fetch Hugo and all its dependent libraries to $GOPATH/src/github.com/gohugoio/hugo
, and go install
compiles everything into a final hugo
(or hugo.exe
) executable inside $GOPATH/bin/
.
{{% note %}}
If you are a Windows user, substitute the $HOME
environment variable above with %USERPROFILE%
.
{{% /note %}}
~/Sites
as the starting point for your site. (~/Sites
is used for example purposes. If you are familiar enough with the command line and file system, you should have no issues following along with the instructions.)There are three ways to install Hugo on your Mac
brew
utilityThere is no “best” way to install Hugo on your Mac. You should use the method that works best for your use case.
There are pros and cons to each of the aforementioned methods:
Homebrew. Homebrew is the simplest method and will require the least amount of work to maintain. The drawbacks aren’t severe. The default package will be for the most recent release, so it will not have bug fixes until the next release (i.e., unless you install it with the --HEAD
option). Hugo brew
releases may lag a few days behind because it has to be coordinated with another team. Nevertheless, brew
is the recommended installation method if you want to work from a stable, widely used source. Brew works well and is easy to update.
Tarball. Downloading and installing from the tarball is also easy, although it requires a few more command line skills than does Homebrew. Updates are easy as well: you just repeat the process with the new binary. This gives you the flexibility to have multiple versions on your computer. If you don’t want to use brew
, then the tarball/binary is a good choice.
Building from Source. Building from source is the most work. The advantage of building from source is that you don’t have to wait for a release to add features or bug fixes. The disadvantage is that you need to spend more time managing the setup, which is manageable but requires more time than the preceding two options.
{{% note %}}
Since building from source is appealing to more seasoned command line users, this guide will focus more on installing Hugo via Homebrew and Tarball.
{{% /note %}}
brew
if you haven’t alreadyGo to the brew
website, https://brew.sh/, and follow the directions there. The most important step is the installation from the command line:
{{< code file=“install-brew.sh” >}}
ruby -e “$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)”
{{< /code >}}
brew
Command to Install hugo
Installing Hugo using brew
is as easy as the following:
{{< code file=“install-brew.sh” >}}
brew install hugo
{{< /code >}}
If Homebrew is working properly, you should see something similar to the following:
==> Downloading https://homebrew.bintray.com/bottles/hugo-0.21.sierra.bottle.tar.gz
######################################################################### 100.0%
==> Pouring hugo-0.21.sierra.bottle.tar.gz
🍺 /usr/local/Cellar/hugo/0.21: 32 files, 17.4MB
{{% note “Installing the Latest Hugo with Brew” %}}
Replace brew install hugo
with brew install hugo --HEAD
if you want the absolute latest in-development version.
{{% /note %}}
brew
should have updated your path to include Hugo. You can confirm by opening a new terminal window and running a few commands:
$ # show the location of the hugo executable
which hugo
/usr/local/bin/hugo
# show the installed version
ls -l $( which hugo )
lrwxr-xr-x 1 mdhender admin 30 Mar 28 22:19 /usr/local/bin/hugo -> ../Cellar/hugo/0.13_1/bin/hugo
# verify that hugo runs correctly
hugo version
Hugo Static Site Generator v0.13 BuildDate: 2015-03-09T21:34:47-05:00
When installing from the tarball, you have to decide if you’re going to install the binary in /usr/local/bin
or in your home directory. There are three camps on this:
Install it in /usr/local/bin
so that all the users on your system have access to it. This is a good idea because it’s a fairly standard place for executables. The downside is that you may need elevated privileges to put software into that location. Also, if there are multiple users on your system, they will all run the same version. Sometimes this can be an issue if you want to try out a new release.
Install it in ~/bin
so that only you can execute it. This is a good idea because it’s easy to do, easy to maintain, and doesn’t require elevated privileges. The downside is that only you can run Hugo. If there are other users on your site, they have to maintain their own copies. That can lead to people running different versions. Of course, this does make it easier for you to experiment with different releases.
Install it in your Sites
directory. This is not a bad idea if you have only one site that you’re building. It keeps every thing in a single place. If you want to try out new releases, you can make a copy of the entire site and update the Hugo executable.
All three locations will work for you. In the interest of brevity, this guide focuses on option #2.
Open https://github.com/gohugoio/hugo/releases in your browser.
Find the current release by scrolling down and looking for the green tag that reads “Latest Release.”
Download the current tarball for the Mac. The name will be something like hugo_X.Y_osx-64bit.tgz
, where X.YY
is the release number.
By default, the tarball will be saved to your ~/Downloads
directory. If you choose to use a different location, you’ll need to change that in the following steps.
Verify that the tarball wasn’t corrupted during the download:
tar tvf ~/Downloads/hugo_X.Y_osx-64bit.tgz
-rwxrwxrwx 0 0 0 0 Feb 22 04:02 hugo_X.Y_osx-64bit/hugo_X.Y_osx-64bit.tgz
-rwxrwxrwx 0 0 0 0 Feb 22 03:24 hugo_X.Y_osx-64bit/README.md
-rwxrwxrwx 0 0 0 0 Jan 30 18:48 hugo_X.Y_osx-64bit/LICENSE.md
The .md
files are documentation for Hugo. The other file is the executable.
bin
Directory# create the directory if needed
mkdir -p ~/bin
# make it the working directory
cd ~/bin
# extract the tarball
tar -xvzf ~/Downloads/hugo_X.Y_osx-64bit.tgz
Archive: hugo_X.Y_osx-64bit.tgz
x ./
x ./hugo
x ./LICENSE.md
x ./README.md
# verify that it runs
./hugo version
Hugo Static Site Generator v0.13 BuildDate: 2015-02-22T04:02:30-06:00
You may need to add your bin directory to your PATH
variable. The which
command will check for us. If it can find hugo
, it will print the full path to it. Otherwise, it will not print anything.
# check if hugo is in the path
which hugo
/Users/USERNAME/bin/hugo
If hugo
is not in your PATH
, add it by updating your ~/.bash_profile
file. First, start up an editor:
nano ~/.bash_profile
Add a line to update your PATH
variable:
export PATH=$PATH:$HOME/bin
Then save the file by pressing Control-X, then Y to save the file and return to the prompt.
Close the terminal and open a new terminal to pick up the changes to your profile. Verify your success by running the which hugo
command again.
You’ve successfully installed Hugo.
If you want to compile Hugo yourself, you’ll need to install Go (aka Golang). You can install Go directly from the Go website or via Homebrew using the following command:
brew install go
If you want to compile a specific version of Hugo, go to https://github.com/gohugoio/hugo/releases and download the source code for the version of your choice. If you want to compile Hugo with all the latest changes (which might include bugs), clone the Hugo repository:
git clone https://github.com/gohugoio/hugo
{{% warning “Sometimes “Latest” = “Bugs””%}}
Cloning the Hugo repository directly means taking the good with the bad. By using the bleeding-edge version of Hugo, you make your development susceptible to the latest features, as well as the latest bugs. Your feedback is appreciated. If you find a bug in the latest release, please create an issue on GitHub.
{{% /warning %}}
Make the directory containing the source your working directory and then fetch Hugo’s dependencies:
mkdir -p src/github.com/gohugoio
ln -sf $(pwd) src/github.com/gohugoio/hugo
# set the build path for Go
export GOPATH=$(pwd)
go get
This will fetch the absolute latest version of the dependencies. If Hugo fails to build, it may be the result of a dependency’s author introducing a breaking change.
Once you have properly configured your directory, you can compile Hugo using the following command:
go build -o hugo main.go
Then place the hugo
executable somewhere in your $PATH
. You’re now ready to start using Hugo.
The following aims to be a complete guide to installing Hugo on your Windows PC.
C:\Hugo\Sites
as the starting point for your new project.C:\Hugo\bin
to store executable files.You’ll need a place to store the Hugo executable, your content, and the generated Hugo website:
C:\Hugo
, assuming you want Hugo on your C drive, although this can go anywhereC:\Hugo\bin
C:\Hugo\Sites
..\Hugo\bin
folder.hugo
executable will be named as hugo_hugo-version_platform_arch.exe
. Rename the executable to hugo.exe
for ease of use.hugo.exe
executable to your PATH by navigating to C:\Hugo\bin
(or the location of your hugo.exe file) and use the command set PATH=%PATH%;C:\Hugo\bin
. If the hugo
command does not work after a reboot, you may have to run the command prompt as administrator.C:\Hugo\bin
folder.C:\Hugo\bin
folder – Windows will do this by default unless you tell it to extract somewhere else.hugo_0.18_windows_amd64.exe
), license.md
, and readme.md
. (You can delete the ZIP download now.) Rename that hugo executable (hugo_hugo-version_platform_arch.exe
) to hugo.exe
for ease of use.Now you need to add Hugo to your Windows PATH settings:
hugo.exe
was extracted, which is C:\Hugo\bin
if you went by the instructions above. The PATH entry should be the folder where Hugo lives and not the binary. Press Enter when you’re done typing.{{% note “Path Editor in Windows 10”%}}
The path editor in Windows 10 was added in the large November 2015 Update. You’ll need to have that or a later update installed for the above steps to work. You can see what Windows 10 build you have by clicking on the Start button → Settings → System → About. See here for more.)
{{% /note %}}
Windows 7 and 8.1 do not include the easy path editor included in Windows 10, so non-technical users on those platforms are advised to install a free third-party path editor like Windows Environment Variables Editor or Path Editor.
Run a few commands to verify that the executable is ready to run, and then build a sample site to get started.
At the prompt, type hugo help
and press the Enter key. You should see output that starts with:
hugo 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 https://gohugo.io/.
If you do, then the installation is complete. If you don’t, double-check the path that you placed the hugo.exe
file in and that you typed that path correctly when you added it to your PATH
variable. If you’re still not getting the output, search the Hugo discussion forum to see if others have already figured out our problem. If not, add a note—in the “Support” category—and be sure to include your command and the output.
At the prompt, change your directory to the Sites
directory.
C:\Program Files> cd C:\Hugo\Sites
C:\Hugo\Sites>
Run the command to generate a new site. I’m using example.com
as the name of the site.
C:\Hugo\Sites> hugo new site example.com
You should now have a directory at C:\Hugo\Sites\example.com
. Change into that directory and list the contents. You should get output similar to the following:
C:\Hugo\Sites>cd example.com
C:\Hugo\Sites\example.com>dir
Directory of C:\hugo\sites\example.com
04/13/2015 10:44 PM <DIR> .
04/13/2015 10:44 PM <DIR> ..
04/13/2015 10:44 PM <DIR> archetypes
04/13/2015 10:44 PM 83 config.toml
04/13/2015 10:44 PM <DIR> content
04/13/2015 10:44 PM <DIR> data
04/13/2015 10:44 PM <DIR> layouts
04/13/2015 10:44 PM <DIR> static
1 File(s) 83 bytes
7 Dir(s) 6,273,331,200 bytes free
@dhersam has created a nice video on common issues:
{{< youtube c8fJIRNChmU >}}
In any of the Linux distributions that support snaps:
snap install hugo
{{% note %}}
Hugo-as-a-snap can write only inside the user’s $HOME
directory—and gvfs-mounted directories owned by the user—because of Snaps’ confinement and security model. More information is also available in this related GitHub issue.
{{% /note %}}
Debian and Ubuntu provide a hugo
version via apt-get
:
sudo apt-get install hugo
man
pagesYou can also install Hugo from the Arch user repository on Arch Linux or derivatives such as Manjaro.
Be aware that Hugo is built from source. This means that additional tools like Git and Go will be installed as well.
sudo pacman -S yaourt
yaourt -S hugo
See the related discussion in the Hugo forums.
Upgrading Hugo is as easy as downloading and replacing the executable you’ve placed in your PATH
.
The Hugo executable has one optional external dependency for source code highlighting (Pygments).
If you want to have source code highlighting using the highlight shortcode, you need to install the Python-based Pygments program. The procedure is outlined on the Pygments homepage.
Now that you’ve installed Hugo, read the Quick Start guide and explore the rest of the documentation. If you have questions, ask the Hugo community directly by visiting the Hugo Discussion Forum.
The following is a description of the most common commands you will use while developing your Hugo project. See the Command Line Reference for a comprehensive view of Hugo’s CLI.
Once you have installed Hugo, make sure it is in your PATH
. You can test that Hugo has been installed correctly via the help
command:
hugo help
The output you see in your console should be similar to the following:
hugo 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/.
Usage:
hugo [flags]
hugo [command]
Available Commands:
benchmark Benchmark Hugo by building a site a number of times.
check Contains some verification checks
config Print the site configuration
convert Convert your content to different formats
env Print Hugo version and environment info
gen A collection of several useful generators.
help Help about any command
import Import your site from others.
list Listing out various types of content
new Create new content for your site
server A high performance webserver
undraft Undraft changes the content's draft status from 'True' to 'False'
version Print the version number of Hugo
Flags:
-b, --baseURL string hostname (and path) to the root, e.g. http://spf13.com/
-D, --buildDrafts include content marked as draft
-E, --buildExpired include expired content
-F, --buildFuture include content with publishdate in the future
--cacheDir string filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache/
--canonifyURLs if true, all relative URLs will be canonicalized using baseURL
--cleanDestinationDir remove files from destination not found in static directories
--config string config file (default is path/config.yaml|json|toml)
-c, --contentDir string filesystem path to content directory
-d, --destination string filesystem path to write files to
--disable404 do not render 404 page
--disableKinds stringSlice disable different kind of pages (home, RSS etc.)
--disableRSS do not build RSS files
--disableSitemap do not build Sitemap file
--enableGitInfo add Git revision, date and author info to the pages
--forceSyncStatic copy all files when static is changed.
-h, --help help for hugo
--i18n-warnings print missing translations
--ignoreCache ignores the cache directory
-l, --layoutDir string filesystem path to layout directory
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--noChmod don't sync permission mode of files
--noTimes don't sync modification time of files
--pluralizeListTitles pluralize titles in lists using inflect (default true)
--preserveTaxonomyNames preserve taxonomy names as written ("Gérard Depardieu" vs "gerard-depardieu")
--quiet build in quiet mode
--renderToMemory render to memory (only useful for benchmark testing)
-s, --source string filesystem path to read files relative from
--stepAnalysis display memory and timing of different steps of the program
-t, --theme string theme to use (located in /themes/THEMENAME/)
--themesDir string filesystem path to themes directory
--uglyURLs if true, use /filename.html instead of /filename/
-v, --verbose verbose output
--verboseLog verbose logging
-w, --watch watch filesystem for changes and recreate as needed
hugo
CommandThe most common usage is probably to run hugo
with your current directory being the input directory.
This generates your website to the public/
directory by default, although you can customize the output directory in your site configuration by changing the publishDir
field.
The site Hugo renders into public/
is ready to be deployed to your web server:
hugo
0 draft content
0 future content
99 pages created
0 paginator pages created
16 tags created
0 groups created
in 90 ms
Hugo allows you to set draft
, publishdate
, and even expirydate
in your content’s front matter. By default, Hugo will not publish:
publishdate
valuedraft: true
statusexpirydate
valueAll three of these can be overridden during both local development and deployment by adding the following flags to hugo
and hugo server
, respectively, or by changing the boolean values assigned to the fields of the same name (without --
) in your configuration:
--buildFuture
--buildDrafts
--buildExpired
Hugo comes with LiveReload built in. There are no additional packages to install. A common way to use Hugo while developing a site is to have Hugo run a server with the hugo server
command and watch for changes:
hugo server
0 draft content
0 future content
99 pages created
0 paginator pages created
16 tags created
0 groups created
in 120 ms
Watching for changes in /Users/yourname/sites/yourhugosite/{data,content,layouts,static}
Serving pages from /Users/yourname/sites/yourhugosite/public
Web Server is available at http://localhost:1313/
Press Ctrl+C to stop
This will run a fully functioning web server while simultaneously watching your file system for additions, deletions, or changes within the following areas of your project organization:
/static/*
/content/*
/data/*
/i18n/*
/layouts/*
/themes/<CURRENT-THEME>/*
config
Whenever you make changes, Hugo will simultaneously rebuild the site and continue to serve content. As soon as the build is finished, LiveReload tells the browser to silently reload the page.
Most Hugo builds are so fast that you may not notice the change unless looking directly at the site in your browser. This means that keeping the site open on a second monitor (or another half of your current monitor) allows you to see the most up-to-date version of your website without the need to leave your text editor.
{{% note “Closing </body>
Tag”%}}
Hugo injects the LiveReload <script>
before the closing </body>
in your templates and will therefore not work if this tag is not present…
{{% /note %}}
LiveReload works by injecting JavaScript into the pages Hugo generates. The script creates a connection from the browser’s web socket client to the Hugo web socket server.
LiveReload is awesome for development. However, some Hugo users may use hugo server
in production to instantly display updated content. The following methods make it easy to disable LiveReload:
hugo server --watch=false
Or…
hugo server --disableLiveReload
The latter flag can be omitted by adding the following key-value to your config.toml
or config.yml
file, respectively:
disableLiveReload = true
disableLiveReload: true
After running hugo server
for local web development, you need to do a final hugo
run without the server
part of the command to rebuild your site. You may then deploy your site by copying the public/
directory to your production web server.
Since Hugo generates a static website, your site can be hosted anywhere using any web server. See Hosting and Deployment for methods for hosting and automating deployments contributed by the Hugo community.
{{% warning “Generated Files are NOT Removed on Site Build” %}}
Running hugo
does not remove generated files before building. This means that you should delete your public/
directory (or the publish directory you specified via flag or configuration file) before running the hugo
command. If you do not remove these files, you run the risk of the wrong files (e.g., drafts or future posts) being left in the generated site.
{{% /warning %}}
Hugo does not remove generated files before building. An easy workaround is to use different directories for development and production.
To start a server that builds draft content (helpful for editing), you can specify a different destination; e.g., a dev/
directory:
hugo server -wDs ~/Code/hugo/docs -d dev
When the content is ready for publishing, use the default public/
dir:
hugo -s ~/Code/hugo/docs
This prevents draft content from accidentally becoming available.
Running the hugo new site
generator from the command line will create a directory structure with the following elements:
.
├── archetypes
├── config.toml
├── content
├── data
├── layouts
├── static
└── themes
The following is a high-level overview of each of the directories with links to each of their respective sections with in the Hugo docs.
archetypes
hugo new
command.date
, title
(inferred from the file name), and draft = true
. This saves time and promotes consistency for sites using multiple content types. You can create your own archetypes with custom preconfigured front matter fields as well.config.toml
content
blog
, articles
, and tutorials
—you will have three directories at content/blog
, content/articles
, and content/tutorials
. Hugo uses sections to assign default content types.data
layouts
.html
files that specify how views of your content will be rendered into a static website. Templates include list pages, your homepage, taxonomy templates, partials, single page templates, and more.static
static
folder is for verifying site ownership on Google Search Console, where you want Hugo to copy over a complete HTML file without modifying its content.{{% note %}}
Hugo does not currently ship with an asset pipeline (#3207). You can solicit support from the community in the Hugo forums or check out a few of the Hugo starter kits for examples of how Hugo developers are managing static assets.
{{% /note %}}
The directory structure of a Hugo website—or more precisely, the source organization of files containing the website’s content and templates—provides most of the configuration information that Hugo needs in order to generate a finished website.
Because of Hugo’s sensible defaults, many websites may not need a configuration file. Hugo is designed to recognize certain typical usage patterns.
Similar to the template lookup order, Hugo has a default set of rules for searching for a configuration file in the root of your website’s source directory as a default behavior:
./config.toml
./config.yaml
./config.json
In your config
file, you can direct Hugo as to how you want your website rendered, control your website’s menus, and arbitrarily define site-wide parameters specific to your project.
The following is a typical example of a YAML configuration file. Note the document opens with 3 hyphens and closes with 3 periods. The values nested under params:
will populate the .Site.Params
variable for use in templates:
baseURL: “https://yoursite.example.com/”
title: “My Hugo Site”
footnoteReturnLinkContents: “↩”
permalinks:
post: /:year/:month/:title/
params:
Subtitle: “Hugo is Absurdly Fast!”
AuthorName: “Jon Doe”
GitHubUser: “spf13”
ListOfFoo:
- “foo1”
- “foo2”
SidebarRecentLimit: 5
…
{{< /code >}}
The following is the full list of Hugo-defined variables in an example YAML file. The values provided in this example represent the default values used by Hugo.
archetypeDir: “archetypes”
baseURL: “”
buildDrafts: false
buildFuture: false
buildExpired: false
relativeURLs: false
canonifyURLs: false
config: “config.toml”
contentDir: “content”
dataDir: “data”
defaultExtension: “html”
defaultLayout: “post”
defaultContentLanguage: “en”
defaultContentLanguageInSubdir: false
disableLiveReload: false
disableRSS: false
disableSitemap: false
enableGitInfo: false
enableRobotsTXT: false
disable404: false
disableHugoGeneratorInject: false
disableKinds:
disablePathToLower: false “”
enableEmoji: false
enableMissingTranslationPlaceholders: false
footnoteAnchorPrefix: “”
footnoteReturnLinkContents: “”
googleAnalytics: “”
hasCJKLanguage: false
languageCode: “”
layoutDir: “layouts”
log: false
logFile: “”
metaDataFormat: “toml”
newContentEditor: “”
noChmod: false
noTimes: false
paginate: 10
paginatePath: “page”
permalinks:
pluralizeListTitles: true
preserveTaxonomyNames: false
publishDir: “public”
pygmentsCodeFencesGuessSyntax: false
pygmentsStyle: “monokai”
pygmentsUseClasses: false
rssLimit: 15
SectionPagesMenu: “”
sitemap:
source: “”
staticDir: “static”
stepAnalysis: false
themesDir: “themes”
theme: “”
title: “”
uglyURLs: false
verbose: false
verboseLog: false
watch: true
taxonomies:
{{< /code >}}
The following is an example of a TOML configuration file. The values under params
will populate the .Site.Params
variable for use in templates:
contentDir = "content"
layoutDir = "layouts"
publishDir = "public"
buildDrafts = false
baseURL = "https://yoursite.example.com/"
canonifyURLs = true
title = "My Hugo Site"
[taxonomies]
category = "categories"
tag = "tags"
[params]
subtitle = "Hugo is Absurdly Fast!"
author = "John Doe"
The following is the full list of Hugo-defined variables in an example TOML file. The values provided in this example represent the default values used by Hugo.
{{< code file=“config.toml” download=“config.toml”>}}
+++
archetypeDir = “archetypes”
baseURL = “”
buildDrafts = false
buildFuture = false
buildExpired = false
relativeURLs = false
canonifyURLs = false
config = “config.toml”
contentDir = “content”
dataDir = “data”
defaultExtension = “html”
defaultLayout = “post”
defaultContentLanguage = “en”
defaultContentLanguageInSubdir = false
disableLiveReload = false
disableRSS = false
disableSitemap = false
enableGitInfo = false
enableRobotsTXT = false
disable404 = false
disableHugoGeneratorInject = false
disableKinds =
disablePathToLower = false
enableEmoji = false
enableMissingTranslationPlaceholders = false
footnoteAnchorPrefix = “”
footnoteReturnLinkContents = “”
googleAnalytics = “”
hasCJKLanguage = false
languageCode = “”
layoutDir = “layouts”
log = false
logFile =
rssLimit = 15
metaDataFormat = “toml”
newContentEditor = “”
noChmod = false
noTimes = false
paginate = 10
paginatePath = “page”
permalinks =
pluralizeListTitles = true
preserveTaxonomyNames = false
publishDir = “public”
pygmentsCodeFencesGuessSyntax = false
pygmentsStyle = “monokai”
pygmentsUseClasses = false
SectionPagesMenu =
sitemap =
source = “”
staticDir = “static”
stepAnalysis = false
themesDir = “themes”
theme = “”
title = “”
uglyURLs = false
verbose = false
verboseLog = false
watch = true
taxonomies
category = “categories”
tag = “tags”
+++
{{< /code >}}
{{% note %}}
If you are developing your site on a *nix machine, here is a handy shortcut for finding a configuration option from the command line:
~/sites/yourhugosite
hugo config | grep emoji
enableemoji: true
{{% /note %}}
In addition to the 3 config options already mentioned, configuration key-values can be defined through operating system environment variables.
For example, the following command will effectively set a website’s title on Unix-like systems:
$ env HUGO_TITLE="Some Title" hugo
{{% note “Setting Environment Variables” %}}
Names must be prefixed with HUGO_
and the configuration key must be set in uppercase when setting operating system environment variables.
{{% /note %}}
The following statement inside ./config.toml
will cause Hugo to ignore files ending with .foo
and .boo
when rendering:
ignoreFiles = [ "\\.foo$", "\\.boo$" ]
The above is a list of regular expressions. Note that the backslash (\
) character is escaped in this example to keep TOML happy.
Blackfriday is Hugo’s built-in Markdown rendering engine.
Hugo typically configures Blackfriday with sane default values that should fit most use cases reasonably well.
However, if you have specific needs with respect to Markdown, Hugo exposes some of its Blackfriday behavior options for you to alter. The following table lists these Hugo options, paired with the corresponding flags from Blackfriday’s source code ( html.go and markdown.go).
{{< readfile file=“/content/readfiles/bfconfig.md” markdown=“true” >}}
{{% note %}}
blackfriday
key and can be set on both the site level and the page level. Any setting on a page will override its respective site setting.{{< code file=“bf-config.toml” >}}
blackfriday
angledQuotes = true
fractions = false
plainIDAnchors = true
extensions = “hardLineBreak”
{{< code file=“bf-config.yml” >}}
blackfriday:
angledQuotes: true
fractions: false
plainIDAnchors: true
extensions:
- hardLineBreak
{{< /code >}}
Hugo v0.20 introduced the ability to render your content to multiple output formats (e.g., to JSON, AMP html, or CSV). See Output Formats for information on how to add these values to your Hugo project’s configuration file.
Hugo provides a robust theming system that is easy to implement yet feature complete. You can view the themes created by the Hugo community on the Hugo themes website.
Hugo themes are powered by the excellent Go template library and are designed to reduce code duplication. They are easy to both customize and keep in synch with the upstream theme.
{{% note “No Default Theme” %}}
Hugo currently doesn’t ship with a “default” theme. This decision is intentional. We leave it up to you to decide which theme best suits your Hugo project.
{{% /note %}}
The community-contributed themes featured on themes.gohugo.io are hosted in a centralizedGitHubrepository
{{% warning “Get git
First” %}}
Without Git installed on your computer, none of the following theme instructions will work. Git tutorials are beyond the scope of the Hugo docs, but GitHub and codecademy offer free, interactive courses for beginners.
{{% /warning %}}
You can install all available Hugo themes by cloning the entire HugoThemerepositoryonGitHub
git clone --depth 1 --recursive https://github.com/gohugoio/hugoThemes.git themes
Before you use a theme, remove the .git folder in that theme’s root folder. Otherwise, this will cause problem if you deploy using Git.
Change into the themes
directory and download a theme by replacing URL_TO_THEME
with the URL of the theme repository:
cd themes
git clone URL_TO_THEME
The following example shows how to use the “Hyde” theme, which has its source hosted at https://github.com/spf13/hyde:
{{< code file=“clone-theme.sh” >}}
cd themes
git clone https://github.com/spf13/hyde
{{< /code >}}
Alternatively, you can download the theme as a .zip
file, unzip the theme contents, and then move the unzipped source into your themes
directory.
{{% note “Read the README
” %}}
Always review the README.md
file that is shipped with a theme. Often, these files contain further instructions required for theme setup; e.g., copying values from an example configuration file.
{{% /note %}}
Please make certain you have installed the themes you want to use in the
/themes
directory. This is the default directory used by Hugo. Hugo comes with the ability to change the themes directory via the themesDir
variable in your site configuration, but this is not recommended.
Hugo applies the decided theme first and then applies anything that is in the local directory. This allows for easier customization while retaining compatibility with the upstream version of the theme. To learn more, go to customizing themes.
There are two different approaches to using a theme with your Hugo website: via the Hugo CLI or as part of your
To change a theme via the Hugo CLI, you can pass the -t
flag when building your site:
hugo -t themename
Likely, you will want to add the theme when running the Hugo local server, especially if you are going to customize the theme:
hugo server -t themename
config
FileIf you’ve already decided on the theme for your site and do not want to fiddle with the command line, you can add the theme directly to your site configuration file:
theme: themename
{{% note “A Note on themename
” %}}
The themename
in the above examples must match the name of the specific theme directory inside /themes
; i.e., the directory name (likely lowercase and urlized) rather than the name of the theme displayed in the Themes Showcase site.
{{% /note %}}
themesrepo
The following are key concepts for Hugo site customization with themes. Hugo permits you to supplement or override any theme template or static file with files in your working directory.
{{% note %}}
When you use a theme cloned from its git repository, do not edit the theme’s files directly. Instead, theme customization in Hugo is a matter of overriding the templates made available to you in a theme. This provides the added flexibility of tweaking a theme to meet your needs while staying current with a theme’s upstream.
{{% /note %}}
There are times where you want to include static assets that differ from versions of the same asset that ships with a theme.
For example, a theme may use jQuery 1.8 in the following location:
/themes/<THEME>/static/js/jquery.min.js
You want to replace the version of jQuery that ships with the theme with the newer jquery-3.1.1.js
. The easiest way to do this is to replace the file with a file of the same name in the same relative path in your project’s root. Therefore, change jquery-3.1.1.js
to jquery.min.js
so that it is identical to the theme’s version and place the file here:
/static/js/jquery.min.js
Anytime Hugo looks for a matching template, it will first check the working directory before looking in the theme directory. If you would like to modify a template, simply create that template in your local layouts
directory.
The template lookup order explains the rules Hugo uses to determine which template to use for a given piece of content. Read and understand these rules carefully.
This is especially helpful when the theme creator used partial templates. These partial templates are perfect for easy injection into the theme with minimal maintenance to ensure future compatibility.
For example:
/themes/<THEME>/layouts/_default/single.html
Would be overwritten by
/layouts/_default/single.html
{{% warning %}}
This only works for templates that Hugo “knows about” (i.e., that follow its convention for folder structure and naming). If a theme imports template files in a creatively named directory, Hugo won’t know to look for the local /layouts
first.
{{% /warning %}}
If the archetype that ships with the theme for a given content type (or all content types) doesn’t fit with how you are using the theme, feel free to copy it to your /archetypes
directory and make modifications as you see fit.
{{% warning “Beware of layouts/_default
” %}}
The _default
directory is a very powerful force in Hugo, especially as it pertains to overwriting theme files. If a default file is located in the local archetypes or layout directory (i.e., archetypes/default.md
or /layouts/_default/*.html
, respectively), it will override the file of the same name in the corresponding theme directory (i.e., themes/<THEME>/archetypes/default.md
or themes/<THEME>/layout/_defaults/*.html
, respectively).
It is usually better to override specific files; i.e. rather than using layouts/_default/*.html
in your working directory.
{{% /warning %}}
partials: /templates/partials/
{{% warning “Use Relative Links” %}}
If you’re creating a theme with plans to share it with the community, use relative URLs since users of your theme may not publish from the root of their website. See relURL and absURL.
{{% /warning %}}
Hugo can initialize a new blank theme directory within your existing themes
using the hugo new
command:
hugo new theme [name]
A theme consists of templates and static assets such as javascript and css files. Themes can also provide archetypes, which are archetypal content types used by the hugo new
command to scaffold new content files with preconfigured front matter.
{{% note “Use the Hugo Generator Tag” %}}
The .Hugo.Generator
tag is included in all themes featured in the Hugo Themes Showcase. We ask that you include the generator tag in all sites and themes you create with Hugo to help the core team track Hugo’s usage and popularity.
{{% /note %}}
Hugo is built around the concept that things should be as simple as possible.
Fundamentally, website content is displayed in two different ways, a single
piece of content and a list of content items. With Hugo, a theme layout starts
with the defaults. As additional layouts are defined, they are used for the
content type or section they apply to. This keeps layouts simple, but permits
a large amount of flexibility.
The default single file layout is located at layouts/_default/single.html
.
The default list file layout is located at layouts/_default/list.html
.
Theme creators should liberally use partial templates
throughout their theme files. Not only is a good DRY practice to include shared
code, but partials are a special template type that enables the themes end user
to be able to overwrite just a small piece of a file or inject code into the
theme from their local /layouts. These partial templates are perfect for easy
injection into the theme with minimal maintenance to ensure future
compatibility.
Everything in the static directory will be copied directly into the final site
when rendered. No structure is provided here to enable complete freedom. It is
common to organize the static content into:
/css
/js
/img
The actual structure is entirely up to you, the theme creator, on how you would like to organize your files.
If your theme makes use of specific keys in the front matter, it is a good idea
to provide an archetype for each content type you have. Read more about archetypes.
A static site generator needs to extend beyond front matter and a couple templates to be both scalable and manageable. Hugo was designed with not only developers in mind, but also content managers and authors.
{{% note %}}
This section is not updated with the new nested sections support in Hugo 0.24, see https://github.com/gohugoio/hugoDocs/issues/36
{{% /note %}}
{{% todo %}}
See above
{{% /todo %}}
In Hugo, your content should be organized in a manner that reflects the rendered website.
While Hugo supports content nested at any level, the top levels (i.e. content/<DIRECTORIES>
) are special in Hugo and are considered the content sections. Without any additional configuration, the following will just work:
.
└── content
└── about
| └── _index.md // <- http://example.com/about/
├── post
| ├── firstpost.md // <- http://example.com/post/firstpost/
| ├── happy
| | └── ness.md // <- http://example.com/post/happy/ness/
| └── secondpost.md // <- http://example.com/post/secondpost/
└── quote
├── first.md // <- http://example.com/quote/first/
└── second.md // <- http://example.com/quote/second/
The following demonstrates the relationships between your content organization and the output URL structure for your Hugo website when it renders. These examples assume you are using pretty URLs, which is the default behavior for Hugo. The examples also assume a key-value of baseurl = "http://example.com"
in your site’s configuration file.
_index.md
_index.md
has a special role in Hugo. It allows you to add front matter and content to your list templates as of v0.18. These templates include those for section templates, taxonomy templates, taxonomy terms templates, and your homepage template. In your templates, you can grab information from _index.md
using the .Site.GetPage
function.
You can keep one _index.md
for your homepage and one in each of your content sections, taxonomies, and taxonomy terms. The following shows typical placement of an _index.md
that would contain content and front matter for a posts
section list page on a Hugo website:
. url
. ⊢--^-⊣
. path slug
. ⊢--^-⊣⊢---^---⊣
. filepath
. ⊢------^------⊣
content/posts/_index.md
At build, this will output to the following destination with the associated values:
url ("/posts/")
⊢-^-⊣
baseurl section ("posts")
⊢--------^---------⊣⊢-^-⊣
permalink
⊢----------^-------------⊣
http://example.com/posts/index.html
Single content files in each of your sections are going to be rendered as single page templates. Here is an example of a single post
within posts
:
path ("posts/my-first-hugo-post.md")
. ⊢-----------^------------⊣
. section slug
. ⊢-^-⊣⊢--------^----------⊣
content/posts/my-first-hugo-post.md
At the time Hugo builds your site, the content will be output to the following destination:
url ("/posts/my-first-hugo-post/")
⊢------------^----------⊣
baseurl section slug
⊢--------^--------⊣⊢-^--⊣⊢-------^---------⊣
permalink
⊢--------------------^---------------------⊣
http://example.com/posts/my-first-hugo-post/index.html
To continue the example, the following demonstrates destination paths for a file located at content/events/chicago/lollapalooza.md
in the same site:
section
⊢--^--⊣
url
⊢-------------^------------⊣
baseURL path slug
⊢--------^--------⊣ ⊢------^-----⊣⊢----^------⊣
permalink
⊢----------------------^-----------------------⊣
http://example.com/events/chicago/lollapalooza/
{{% note %}}
As of v0.20, Hugo does not recognize nested sections. While you can nest as many content directories as you’d like, any child directory of a section will still be considered the same section as that of its parents. Therefore, in the above example, {{.Section}}
for lollapalooza.md
is events
and not chicago
. See the related issue on GitHub.
{{% /note %}}
The following concepts will provide more insight into the relationship between your project’s organization and the default behaviors of Hugo when building the output website.
section
A default content type is determined by a piece of content’s section. section
is determined by the location within the project’s content
directory. section
cannot be specified or overridden in front matter.
slug
A content’s slug
is either name.extension
or name/
. The value for slug
is determined by
lollapalooza.md
) ORpath
A content’s path
is determined by the section’s path to the file. The file path
url
The url
is the relative URL for the piece of content. The url
Hugo believes that you organize your content with a purpose. The same structure that works to organize your source content is used to organize the rendered site. As displayed above, the organization of the source content will be mirrored in the destination.
There are times where you may need more control over your content. In these cases, there are fields that can be specified in the front matter to determine the destination of a specific piece of content.
The following items are defined in this order for a specific reason: items explained further down in the list will override earlier items, and not all of these items can be defined in front matter:
filename
This isn’t in the front matter, but is the actual name of the file minus the extension. This will be the name of the file in the destination (e.g., content/posts/my-post.md
becomes example.com/posts/my-post/
).
slug
When defined in the front matter, the slug
can take the place of the filename for the destination.
{{< /code >}}
This will render to the following destination according to Hugo’s default behavior:
example.com/posts/new-post/
section
section
is determined by a content’s location on disk and cannot be specified in the front matter. See sections for more information.
type
A content’s type
is also determined by its location on disk but, unlike section
, it can be specified in the front matter. See types. This can come in especially handy when you want a piece of content to render using a different layout. In the following example, you can create a layout at layouts/new/mylayout.html
that Hugo will use to render this piece of content, even in the midst of many other posts.
{{< /code >}}
url
A complete URL can be provided. This will override all the above as it pertains to the end destination. This must be the path from the baseURL (starting with a /
). url
will be used exactly as it provided in the front matter and will ignore the --uglyURLs
setting in your site configuration:
{{< /code >}}
Assuming your baseURL
is configured to https://example.com
, the addition of url
to the front matter will make old-url.md
render to the following destination:
https://example.com/blog/new-url/
You can see more information on how to control output paths in URL Management.
Markdown is the main content format and comes in two flavours: The excellent Blackfriday project (name your files *.md
or set markup = "markdown"
in front matter) or its fork Mmark (name your files *.mmark
or set markup = "mmark"
in front matter), both very fast markdown engines written in Go.
For Emacs users, goorgeous provides built-in native support for Org-mode (name your files *.org
or set markup = "org"
in front matter)
{{% note “Deeply Nested Lists” %}}
Before you begin writing your content in markdown, Blackfriday has a known issue (#329) with handling deeply nested lists. Luckily, there is an easy workaround. Use 4-spaces (i.e., tab) rather than 2-space indentations.
{{% /note %}}
You can configure multiple aspects of Blackfriday as show in the following list. See the docs on Configuration for the full list of explicit directions you can give to Hugo when rendering your site.
{{< readfile file=“/content/readfiles/bfconfig.md” markdown=“true” >}}
Hugo provides some convenient methods for extending markdown.
Hugo supports GitHub-styled task lists (i.e., TODO lists) for the Blackfriday markdown renderer. If you do not want to use this feature, you can disable it in your configuration.
{{< code file=“content/my-to-do-list.md” >}}
The preceding markdown produces the following HTML in your rendered website:
<ul class="task-list">
<li><input type="checkbox" disabled="" class="task-list-item"> a task list item</li>
<li><input type="checkbox" disabled="" class="task-list-item"> list syntax required</li>
<li><input type="checkbox" disabled="" class="task-list-item"> incomplete</li>
<li><input type="checkbox" checked="" disabled="" class="task-list-item"> completed</li>
</ul>
The following shows how the example task list will look to the end users of your website. Note that visual styling of lists is up to you. This list has been styled according to the Hugo Docs stylesheet.
To add emojis directly to content, set enableEmoji
to true
in your site configuration. To use emojis in templates or shortcodes, see emojify
function.
For a full list of emojis, see the Emoji cheat sheet.
If you write in Markdown and find yourself frequently embedding your content with raw HTML, Hugo provides built-in shortcodes functionality. This is one of the most powerful features in Hugo and allows you to create your own Markdown extensions very quickly.
See Shortcodes for usage, particularly for the built-in shortcodes that ship with Hugo, and Shortcode Templating to learn how to build your own.
Hugo supports GitHub-flavored markdown’s use of triple back ticks, as well as provides a special highlight
nested shortcode to render syntax highlighting via Pygments. For usage examples and a complete explanation, see the syntax highlighting documentation in developer tools.
Mmark is a fork of BlackFriday and markdown superset that is well suited for writing IETF documentation. You can see examples of the syntax in the Mmark GitHub repository or the full syntax on Miek Gieben’s website.
As Hugo ships with Mmark, using the syntax is as easy as changing the extension of your content files from .md
to .mmark
.
In the event that you want to only use Mmark in specific files, you can also define the Mmark syntax in your content’s front matter:
---
title: My Post
date: 2017-04-01
markup: mmark
---
{{% warning %}}
Thare are some features not available in Mmark; one example being that shortcodes are not translated when used in an included .mmark
file (#3131), and EXTENSION_ABBREVIATION
(#1970) and the aforementioned GFM todo lists (#2270) are not fully supported. Contributions are welcome.
{{% /warning %}}
MathJax is a JavaScript library that allows the display of mathematical expressions described via a LaTeX-style syntax in the HTML (or Markdown) source of a web page. As it is a pure a JavaScript library, getting it to work within Hugo is fairly straightforward, but does have some oddities that will be discussed here.
This is not an introduction into actually using MathJax to render typeset mathematics on your website. Instead, this page is a collection of tips and hints for one way to get MathJax working on a website built with Hugo.
The first step is to enable MathJax on pages that you would like to have typeset math. There are multiple ways to do this (adventurous readers can consult the Loading and Configuring section of the MathJax documentation for additional methods of including MathJax), but the easiest way is to use the secure MathJax CDN by include a <script>
tag for the officially recommended secure CDN (cdn.js.com):
{{< code file=“add-mathjax-to-page.html” >}}
{{< /code >}}
One way to ensure that this code is included in all pages is to put it in one of the templates that live in the layouts/partials/
directory. For example, I have included this in the bottom of my template footer.html
because I know that the footer will be included in every page of my website.
MathJax is a stable open-source library with many features. I encourage the interested reader to view the MathJax Documentation, specifically the sections on Basic Usage and MathJax Configuration Options.
{{% note %}}
The following issues with Markdown assume you are using .md
for content and BlackFriday for parsing. Using Mmark as your content format will obviate the need for the following workarounds.
When using Mmark with MathJax, use displayMath: [′$$′,′$$′
. See the Mmark README.md
for more information. In addition to MathJax, Mmark has been shown to work well with KaTeX. See this related blog post from a Hugo user.
{{% /note %}}
After enabling MathJax, any math entered between proper markers (see the MathJax documentation) will be processed and typeset in the web page. One issue that comes up, however, with Markdown is that the underscore character (_
) is interpreted by Markdown as a way to wrap text in emph
blocks while LaTeX (MathJax) interprets the underscore as a way to create a subscript. This “double speak” of the underscore can result in some unexpected and unwanted behavior.
There are multiple ways to remedy this problem. One solution is to simply escape each underscore in your math code by entering \_
instead of _
. This can become quite tedious if the equations you are entering are full of subscripts.
Another option is to tell Markdown to treat the MathJax code as verbatim code and not process it. One way to do this is to wrap the math expression inside a <div>
</div>
block. Markdown would ignore these sections and they would get passed directly on to MathJax and processed correctly. This works great for display style mathematics, but for inline math expressions the line break induced by the <div>
is not acceptable. The syntax for instructing Markdown to treat inline text as verbatim is by wrapping it in backticks (`
). You might have noticed, however, that the text included in between backticks is rendered differently than standard text (on this site these are items highlighted in red). To get around this problem, we could create a new CSS entry that would apply standard styling to all inline verbatim text that includes MathJax code. Below I will show the HTML and CSS source that would accomplish this (note this solution was adapted from this blog post—all credit goes to the original author).
{{< code file=“mathjax-markdown-solution.html” >}}
{{< /code >}}
As before, this content should be included in the HTML source of each page that will be using MathJax. The next code snippet contains the CSS that is used to have verbatim MathJax blocks render with the same font style as the body of the page.
{{< code file=“mathjax-style.css” >}}
code.has-jax {
font: inherit;
font-size: 100%;
background: inherit;
border: inherit;
color: #515151;
}
{{< /code >}}
In the CSS snippet, notice the line color: #515151;
. #515151
is the value assigned to the color
attribute of the body
class in my CSS. In order for the equations to fit in with the body of a web page, this value should be the same as the color of the body.
With this setup, everything is in place for a natural usage of MathJax on pages generated using Hugo. In order to include inline mathematics, just put LaTeX code in between `TeXCode`
or `TeXCode`
. To include display style mathematics, just put LaTeX code in between <div>TeXCode
. All the math will be properly typeset and displayed within your Hugo generated web page!
Hugo has new concept called external helpers. It means that you can write your content using Asciidoc, reStructuredText. If you have files with associated extensions, Hugo will call external commands to generate the content. (See the Hugo source code for external helpers.)
For example, for Asciidoc files, Hugo will try to call the asciidoctor
or asciidoc
command. This means that you will have to install the associated tool on your machine to be able to use these formats. (See the Asciidoctor docs for installation instructions).
To use these formats, just use the standard extension and the front matter exactly as you would do with natively supported .md
files.
{{% warning “Performance of External Helpers” %}}
Because additional formats are external commands generation performance will rely heavily on the performance of the external tool you are using. As this feature is still in its infancy, feedback is welcome.
{{% /warning %}}
Markdown syntax is simple enough to learn in a single sitting. The following are excellent resources to get you up and running:
Front matter allows you to keep metadata attached to an instance of a content type—i.e., embedded inside a content file—and is one of the many features that gives Hugo its strength.
Hugo supports three formats for front matter, each with their own identifying tokens.
+++
.---
.{
’ and ‘}
’, followed by a new line.+++
title = "spf13-vim 3.0 release and new website"
description = "spf13-vim is a cross platform distribution of vim plugins and resources for Vim."
tags = [ ".vimrc", "plugins", "spf13-vim", "vim" ]
date = "2012-04-06"
categories = [
"Development",
"VIM"
]
slug = "spf13-vim-3-0-release-and-new-website"
+++
---
title: "spf13-vim 3.0 release and new website"
description: "spf13-vim is a cross platform distribution of vim plugins and resources for Vim."
#tags: [ ".vimrc", "plugins", "spf13-vim", "vim" ]
lastmod: 2015-12-23
date: "2012-04-06"
categories:
- "Development"
- "VIM"
slug: "spf13-vim-3-0-release-and-new-website"
---
{
"title": "spf13-vim 3.0 release and new website",
"description": "spf13-vim is a cross platform distribution of vim plugins and resources for Vim.",
"tags": [ ".vimrc", "plugins", "spf13-vim", "vim" ],
"date": "2012-04-06",
"categories": [
"Development",
"VIM"
],
"slug": "spf13-vim-3-0-release-and-new-website"
}
There are a few predefined variables that Hugo is aware of. See Page Variables for how to call many of these predefined variables in your templates.
aliases
date
description
draft
true
, the content will not be rendered unless the --buildDrafts
flag is passed to the hugo
command.expiryDate
--buildExpired
flag is passed to the hugo
command.isCJKLanguage
true
, Hugo will explicitly treat the content as a CJK language; both .Summary
and .WordCount
work properly in CJK languages.keywords
layout
type
is not specified in the front matter, Hugo will look for the layout of the same name in the layout directory that corresponds with a content’s section. See “Defining a Content Type”lastmod
linkTitle
linktitle
before the title
. Hugo can also order lists of content by linktitle
.markup
"rst"
for reStructuredText (requiresrst2html
) or "md"
(default) for Markdown.outputs
publishDate
--buildFuture
flag is passed to hugo
.slug
taxonomies
tags
and categories
in the above front matter examples.title
type
url
weight
{{% note “Hugo’s Default URL Destinations” %}}
If neither slug
nor url
is present and permalinks are not configured otherwise in your site config
file, Hugo will use the filename of your content to create the output URL. See Content Organization for an explanation of paths in Hugo and URL Management for ways to customize Hugo’s default behaviors.
{{% /note %}}
You can add fields to your front matter arbitrarily to meet your needs. These user-defined key-values are placed into a single .Params
variable for use in your templates.
The following fields can be accessed via .Params.include_toc
and .Params.show_comments
, respectively. The Variables section provides more information on using Hugo’s page- and site-level variables in your templates.
include_toc: true
show_comments: false
These two user-defined fields can then be accessed via .Params.include_toc
and .Params.show_comments
, respectively. The Variables section provides more information on using Hugo’s page- and site-level variables in your templates.
You can assign content-specific weight
in the front matter of your content. These values are especially useful for ordering in list views. You can use weight
for ordering of content and the convention of <TAXONOMY>_weight
for ordering content within a taxonomy. See Ordering and Grouping Hugo Lists to see how weight
can be used to organize your content in list views.
It’s possible to set some options for Markdown rendering in a content’s front matter as an override to the BlackFriday rendering options set in your project configuration.
Hugo loves Markdown because of its simple content format, but there are times when Markdown falls short. Often, content authors are forced to add raw HTML (e.g., video <iframes>
) to Markdown content. We think this contradicts the beautiful simplicity of Markdown’s syntax.
Hugo created shortcodes to circumvent these limitations.
A shortcode is a simple snippet inside a content file that Hugo will render using a predefined template. Note that shortcodes will not work in template files. If you need the type of drop-in functionality that shortcodes provide but in a template, you most likely want a partial template instead.
In addition to cleaner Markdown, shortcodes can be updated any time to reflect new classes, techniques, or standards. At the point of site generation, Hugo shortcodes will easily merge in your changes. You avoid a possibly complicated search and replace operation.
In your content files, a shortcode can be called by calling {{%/* shortcodename parameters */%}}
. Shortcode parameters are space delimited, and parameters with internal spaces can be quoted.
The first word in the shortcode declaration is always the name of the shortcode. Parameters follow the name. Depending upon how the shortcode is defined, the parameters may be named, positional, or both, although you can’t mix parameter types in a single call. The format for named parameters models that of HTML with the format name="value"
.
Some shortcodes use or require closing shortcodes. Again like HTML, the opening and closing shortcodes match (name only) with the closing declaration, which is prepended with a slash.
Here are two examples of paired shortcodes:
{{%/* mdshortcode */%}}Stuff to `process` in the *center*.{{%/* /mdshortcode */%}}
{{</* highlight go */>}} A bunch of code here {{</* /highlight */>}}
The examples above use two different delimiters, the difference being the %
character in the first and the <>
characters in the second.
The %
character indicates that the shortcode’s inner content—called in the shortcode template with the .Inner
variable—needs further processing by the page’s rendering processor (i.e. markdown via Blackfriday). In the following example, Blackfriday would convert **World**
to <strong>World</strong>
:
{{%/* myshortcode */%}}Hello **World!**{{%/* /myshortcode */%}}
The <
character indicates that the shortcode’s inner content does not need further rendering. Often shortcodes without markdown include internal HTML:
{{</* myshortcode */>}}<p>Hello <strong>World!</strong></p>{{</* /myshortcode */>}}
You can call shortcodes within other shortcodes by creating your own templates that leverage the .Parent
variable. .Parent
allows you to check the context in which the shortcode is being called. See Shortcode templates.
Hugo ships with a set of predefined shortcodes that represent very common usage. These shortcodes are provided for author convenience and to keep your markdown content clean.
figure
figure
is an extension of the image syntax in markdown, which does not provide a shorthand for the more semantic HTML5 <figure>
element.
The figure
shortcode can use the following named parameters:
src
link
title
caption
class
attr
(i.e., attribution)attrlink
alt
figure
Input{{< code file=“figure-input-example.md” >}}
{{</* figure src=“/media/spf13.jpg” title=“Steve Francia” */>}}
{{< /code >}}
figure
Output{{< output file=“figure-output-example.html” >}}
gist
Bloggers often want to include GitHub gists when writing posts. Let’s suppose we want to use the gist at the following url:
https://gist.github.com/spf13/7896402
We can embed the gist in our content via username and gist ID pulled from the URL:
{{</* gist spf13 7896402 */>}}
gist
InputIf the gist contains several files and you want to quote just one of them, you can pass the filename (quoted) as an optional third argument:
{{< code file=“gist-input.md” >}}
{{</* gist spf13 7896402 “img.html” */>}}
{{< /code >}}
gist
Output{{< output file=“gist-output.html” >}}
{{< gist spf13 7896402 >}}
{{< /output >}}
gist
DisplayTo demonstrate the remarkably efficiency of Hugo’s shortcode feature, we have embedded the spf13
gist
example in this page. The following simulates the experience for visitors to your website. Naturally, the final display will be contingent on your stylesheets and surrounding markup.
{{< gist spf13 7896402 >}}
highlight
This shortcode will convert the source code provided into syntax-highlighted HTML. Read more on highlighting. highlight
takes exactly one required language
parameter and requires a closing shortcode.
highlight
Input{{< code file=“content/tutorials/learn-html.md” >}}
{{</* highlight html */>}}
highlight
OutputThe highlight
shortcode example above would produce the following HTML when the site is rendered:
{{< output file=“tutorials/learn-html/index.html” >}}
<section id=“main”>
<div>
<h1 id=“title”>{{ .Title }}</h1>
{{ range .Data.Pages }}
{{ .Render “summary”}}
{{ end }}
</div>
</section>
{{< /output >}}
{{% note “More on Syntax Highlighting” %}}
To see even more options for adding syntax-highlighted code blocks to your website, see Syntax Highlighting in Developer Tools.
{{% /note %}}
instagram
If you’d like to embed a photo from Instagram, you only need the photo’s ID. You can discern an Instagram photo ID from the URL:
https://www.instagram.com/p/BWNjjyYFxVx/
instagram
Input{{< code file=“instagram-input.md” >}}
{{</* instagram BWNjjyYFxVx */>}}
{{< /code >}}
You also have the option to hide the caption:
{{< code file=“instagram-input-hide-caption.md” >}}
{{</* instagram BWNjjyYFxVx hidecaption */>}}
{{< /code >}}
instagram
OutputBy adding the preceding hidecaption
example, the following HTML will be added to your rendered website’s markup:
{{< output file=“instagram-hide-caption-output.html” >}}
{{< instagram BWNjjyYFxVx hidecaption >}}
{{< /output >}}
instagram
DisplayUsing the preceding instagram
with hidecaption` example above, the following simulates the displayed experience for visitors to your website. Naturally, the final display will be contingent on your stylesheets and surrounding markup.
{{< instagram BWNjjyYFxVx hidecaption >}}
ref
and relref
These shortcodes will look up the pages by their relative path (e.g., blog/post.md
) or their logical name (post.md
) and return the permalink (ref
) or relative permalink (relref
) for the found page.
ref
and relref
also make it possible to make fragmentary links that work for the header links generated by Hugo.
{{% note “More on Cross References” %}}
Read a more extensive description of ref
and relref
in the cross references documentation.
{{% /note %}}
ref
and relref
take exactly one required parameter of reference, quoted and in position 0
.
ref
and relref
Input[Neat]({{</* ref "blog/neat.md" */>}})
[Who]({{</* relref "about.md#who" */>}})
ref
and relref
OutputAssuming that standard Hugo pretty URLs are turned on.
<a href="/blog/neat">Neat</a>
<a href="/about/#who:c28654c202e73453784cfd2c5ab356c0">Who</a>
speakerdeck
To embed slides from Speaker Deck, click on “< /> Embed” (under Share right next to the template on Speaker Deck) and copy the URL:
<script async class="speakerdeck-embed" data-id="4e8126e72d853c0060001f97" data-ratio="1.33333333333333" src="//speakerdeck.com/assets/embed.js"></script>
speakerdeck
Example InputExtract the value from the field data-id
and pass it to the shortcode:
{{< code file=“speakerdeck-example-input.md” >}}
{{</* speakerdeck 4e8126e72d853c0060001f97 */>}}
{{< /code >}}
speakerdeck
Example Output{{< output file=“speakerdeck-example-input.md” >}}
{{< speakerdeck 4e8126e72d853c0060001f97 >}}
{{< /output >}}
speakerdeck
Example DisplayFor the preceding speakerdeck
example, the following simulates the displayed experience for visitors to your website. Naturally, the final display will be contingent on your stylesheets and surrounding markup.
{{< speakerdeck 4e8126e72d853c0060001f97 >}}
tweet
You want to include a single tweet into your blog post? Everything you need is the URL of the tweet:
https://twitter.com/spf13/status/877500564405444608
tweet
InputPass the tweet’s ID from the URL as a parameter to the tweet
shortcode:
{{< code file=“example-tweet-input.md” >}}
{{</* tweet 877500564405444608 */>}}
{{< /code >}}
tweet
OutputUsing the preceding tweet
example, the following HTML will be added to your rendered website’s markup:
{{< output file=“example-tweet-output.html” >}}
{{< tweet 877500564405444608 >}}
{{< /output >}}
tweet
DisplayUsing the preceding tweet
example, the following simulates the displayed experience for visitors to your website. Naturally, the final display will be contingent on your stylesheets and surrounding markup.
{{< tweet 877500564405444608 >}}
vimeo
Adding a video from Vimeo is equivalent to the YouTube shortcode above.
https://vimeo.com/channels/staffpicks/146022717
vimeo
InputExtract the ID from the video’s URL and pass it to the vimeo
shortcode:
{{< code file=“example-vimeo-input.md” >}}
{{</* vimeo 146022717 */>}}
{{< /code >}}
vimeo
OutputUsing the preceding vimeo
example, the following HTML will be added to your rendered website’s markup:
{{< output file=“example-vimeo-output.html” >}}
{{< vimeo 146022717 >}}
{{< /output >}}
{{% tip %}}
If you want to further customize the visual styling of the YouTube or Vimeo output, add a class
named parameter when calling the shortcode. The new class
will be added to the <div>
that wraps the <iframe>
and will remove the inline styles. Note that you will need to call the id
as a named parameter as well.
{{</* vimeo id="146022717" class="my-vimeo-wrapper-class" */>}}
{{% /tip %}}
vimeo
DisplayUsing the preceding vimeo
example, the following simulates the displayed experience for visitors to your website. Naturally, the final display will be contingent on your stylesheets and surrounding markup.
{{< vimeo 146022717 >}}
youtube
The youtube
shortcode embeds a responsive video player for YouTube videos. Only the ID of the video is required, e.g.:
https://www.youtube.com/watch?v=w7Ft2ymGmfc
youtube
InputCopy the YouTube video ID that follows v=
in the video’s URL and pass it to the youtube
shortcode:
{{< code file=“example-youtube-input.md” >}}
{{</* youtube w7Ft2ymGmfc */>}}
{{< /code >}}
Furthermore, you can automatically start playback of the embedded video by setting the autoplay
parameter to true
. Remember that you can’t mix named an unnamed parameters, so you’ll need to assign the yet unnamed video id to the parameter id
:
{{< code file=“example-youtube-input-with-autoplay.md” >}}
{{</* youtube id=“w7Ft2ymGmfc” autoplay=“true” */>}}
{{< /code >}}
youtube
OutputUsing the preceding youtube
example, the following HTML will be added to your rendered website’s markup:
{{< code file=“example-youtube-output.html” >}}
{{< youtube id=“w7Ft2ymGmfc” autoplay=“true” >}}
{{< /code >}}
youtube
DisplayUsing the preceding youtube
example (without autoplay="true"
), the following simulates the displayed experience for visitors to your website. Naturally, the final display will be contingent on your stylesheets and surrounding markup. The video is also include in the Quick Start of the Hugo documentation.
{{< youtube w7Ft2ymGmfc >}}
To learn more about creating custom shortcodes, see the shortcode template documentation.
{{% note %}}
This section is not updated with the new nested sections support in Hugo 0.24, see https://github.com/gohugoio/hugoDocs/issues/36
{{% /note %}}
{{% todo %}}
See above
{{% /todo %}}
Hugo believes that you organize your content with a purpose. The same structure that works to organize your source content is used to organize the rendered site (see directory structure).
Following this pattern, Hugo uses the top level of your content organization as the content section.
The following example shows a content directory structure for a website that has three sections: “authors,” “events,” and “posts”:
.
└── content
├── authors
| ├── _index.md // <- example.com/authors/
| ├── john-doe.md // <- example.com/authors/john-doe/
| └── jane-doe.md // <- example.com/authors/jane-doe/
└── events
| ├── _index.md // <- example.com/events/
| ├── event-1.md // <- example.com/events/event-1/
| ├── event-2.md // <- example.com/events/event-2/
| └── event-3.md // <- example.com/events/event-3/
└── posts
| ├── _index.md // <- example.com/posts/
| ├── event-1.md // <- example.com/posts/event-1/
| ├── event-2.md // <- example.com/posts/event-2/
| ├── event-3.md // <- example.com/posts/event-3/
| ├── event-4.md // <- example.com/posts/event-4/
| └── event-5.md // <- example.com/posts/event-5/
Hugo will automatically create pages for each section root that list all of the content in that section. See the documentation on section templates for details on customizing the way these pages are rendered.
As of Hugo v0.18, section pages can also have a content file and front matter. These section content files must be placed in their corresponding section folder and named _index.md
in order for Hugo to correctly render the front matter and content.
{{% warning “index.md
vs _index.md
” %}}
Hugo themes developed before v0.18 often used an index.md
(i.e., without the leading underscore [_
]) in a content section as a hack to emulate the behavior of _index.md
. The hack may work…sometimes; however, the order of page rendering can be unpredictable in Hugo. What works now may fail to render appropriately as your site grows. It is strongly advised to use _index.md
as content for your section index pages. Note: _index.md
’s layout, as representative of a section, is a list page template and not a single page template. If you want to alter the new default behavior for _index.md
, configure disableKinds
accordingly in your site’s configuration.
{{% /warning %}}
By default, everything created within a section will use the content type that matches the section name. For example, Hugo will assume that posts/post-1.md
has a posts
content type. If you are using an archetype for your posts section, Hugo will generate front matter according to what it finds in archetypes/posts.md
.
Larger sites often have multiple content authors. Hugo provides standardized author profiles to organize relationships between content and content creators for sites operating under a distributed authorship model.
You can create a profile containing metadata for each author on your website. These profiles have to be saved under data/_authors/
. The filename of the profile will later be used as an identifier. This way Hugo can associate content with one or multiple authors. An author’s profile can be defined in the JSON, YAML, or TOML format.
Let’s suppose Alice Allison is a blogger. A simple unique identifier would be alice
. Now, we have to create a file called alice.toml
in the data/_authors/
directory. The following example is the standardized template written in TOML:
{{< code file=“data/_authors/alice.toml” >}}
givenName = “Alice” # or firstName as alias
familyName = “Allison” # or lastName as alias
displayName = “Alice Allison”
thumbnail = “static/authors/alice-thumb.jpg”
image = “static/authors/alice-full.jpg”
shortBio = “My name is Alice and I’m a blogger.”
bio = “My name is Alice and I’m a blogger… some other stuff”
email = “alice.allison@email.com”
weight = 10
social
params
All variables are optional but it’s advised to fill all important ones (e.g. names and biography) because themes can vary in their usage.
You can store files for the thumbnail
and image
attributes in the static
folder. Then add the path to the photos relative to static
; e.g., /static/path/to/thumbnail.jpg
.
weight
allows you to define the order of an author in an .Authors
list and can be accessed on list or via the .Site.Authors
variable.
The social
section contains all the links to the social network accounts of an author. Hugo is able to generate the account links for the most popular social networks automatically. This way, you only have to enter your username. You can find a list of all supported social networks here. All other variables, like website
in the example above remain untouched.
The params
section can contain arbitrary data much like the same-named section in the config file. What it contains is up to you.
Earlier it was mentioned that content can be associated with an author through their corresponding identifier. In our case, blogger Alice has the identifier alice
. In the front matter of a content file, you can create a list of identifiers and assign it to the authors
variable. Here are examples for alice
using YAML and TOML, respectively.
---
title: Why Hugo is so Awesome
date: 2016-08-22T14:27:502:00
authors: ["alice"]
---
Nothing to read here. Move along...
+++
title = Why Hugo is so Awesome
date = "2016-08-22T14:27:502:00"
authors: ["alice"]
+++
Nothing to read here. Move along...
Future authors who might work on this blog post can append their identifiers to the authors
array in the front matter as well.
After a successful setup it’s time to give some credit to the authors by showing them on the website. Within the templates Hugo provides a list of the author’s profiles if they are listed in the authors
variable within the front matter.
The list is accessible via the .Authors
template variable. Printing all authors of a the blog post is straight forward:
{{ range .Authors }}
{{ .DisplayName }}
{{ end }}
=> Alice Allison
Even if there are co-authors you may only want to show the main author. For this case you can use the .Author
template variable (note the singular form). The template variable contains the profile of the author that is first listed with his identifier in the front matter.
{{% note %}}
You can find a list of all template variables to access the profile information in Author Variables.
{{% /note %}}
As aforementioned, Hugo is able to generate links to profiles of the most popular social networks. The following social networks with their corrersponding identifiers are supported: github
, facebook
, twitter
, googleplus
, pinterest
, instagram
, youtube
and linkedin
.
This is can be done with the .Social.URL
function. Its only parameter is the name of the social network as they are defined in the profile (e.g. facebook
, googleplus
). Custom variables like website
remain as they are.
Most articles feature a small section with information about the author at the end. Let’s create one containing the author’s name, a thumbnail, a (summarized) biography and links to all social networks:
{{< code file=“layouts/partials/author-info.html” download=“author-info.html” >}}
{{ with .Author }}
{{ .ShortBio }}
That question can be answered with a list of all authors and another list containing all articles that they each have written. Now we have to translate this idea into templates. The taxonomy feature allows us to logically group content based on information that they have in common; e.g. a tag or a category. Well, many articles share the same author, so this should sound familiar, right?
In order to let Hugo know that we want to group content based on their author, we have to create a new taxonomy called author
(the name corresponds to the variable in the front matter). Here is the snippet in a config.yaml
and config.toml
, respectively:
taxonomies:
author: authors
[taxonomies]
author = "authors"
In the next step we can create a template to list all authors of your website. Later, the list can be accessed at www.example.com/authors/
. Create a new template in the layouts/taxonomy/
directory called authors.term.html
. This template will be exclusively used for this taxonomy.
{{< code file=“layouts/taxonomy/author.term.html” download=“author.term.html” >}}
.Data.Terms
contains the identifiers of all authors and we can range over it to create a list with all author names. The $profile
variable gives us access to the profile of the current author. This allows you to generate a nice info box with a thumbnail, a biography and social media links, like at the end of a blog post.
Last but not least, we have to create the second list that contains all publications of an author. Each list will be shown in its own page and can be accessed at www.example.com/authors/<IDENTIFIER>
. Replace <IDENTIFIER>
with a valid author identifier like alice
.
The layout for this page can be defined in the template layouts/taxonomy/author.html
.
{{< code file=“layouts/taxonomy/author.html” download=“author.html” >}}
{{ range .Data.Pages }}
The example above generates a simple list of all posts written by a single author. Inside the loop you’ve access to the complete set of page variables. Therefore, you can add additional information about the current posts like the publishing date or the tags.
With a lot of content this list can quickly become very long. Consider to use the pagination feature. It splits the list into smaller chunks and spreads them over multiple pages.
A content type can have a unique set of metadata (i.e., front matter) or customized template and can be created by the hugo new
command via archetypes.
Tumblr
Hugo assumes that your site will be organized into sections and each section represents a corresponding type. This is to reduce the amount of configuration necessary for new Hugo projects.
If you are taking advantage of this default behavior, each new piece of content you place into a section will automatically inherit the type. Therefore a new file created at content/posts/new-post.md
will automatically be assigned the type posts
. Alternatively, you can set the content type in a content file’s front matter in the field “type
”.
You can manually add files to your content directories, but Hugo can create and populate a new content file with preconfigured front matter via archetypes.
Creating a new content type is easy. You simply define the templates and archetype unique to your new content type, or Hugo will use defaults.
{{% note “Declaring Content Types” %}}
Remember, all of the following are optional. If you do not specifically declare content types in your front matter or develop specific layouts for content types, Hugo is smart enough to assume the content type from the file path and section. (See Content Sections for more information.)
{{% /note %}}
The following examples take you stepwise through creating a new type layout for a content file that contains the following front matter:
{{< code file=“content/events/my-first-event.md” copy=“false” >}}
+++
title = My First Event
date = “2016-06-24T19:20:04-07:00”
description = “Today is my 36th birthday. How time flies.”
type = “event”
layout = “birthday”
+++
{{< /code >}}
By default, Hugo assumes *.md
under events
is of the events
content type. However, we have specified that this particular file at content/events/ my-first-event.md
is of type event
and should render using the birthday
layout.
Create a directory with the name of the type in /layouts
. For creating these custom layouts, type is always singular; e.g., events => event
and posts => post
.
For this example, you need to create layouts/event/birthday.html
.
{{% note %}}
If you have multiple content files in your events
directory that are of the special
type and you don’t want to define the layout
specifically for each piece of content, you can create a layout at layouts/special/single.html
to observe the single page template lookup order.
{{% /note %}}
{{% warning %}}
With the “everything is a page” data model introduced in v0.18 (see Content Organization), you can use _index.md
in content directories to add both content and front matter to list pages. However, type
and layout
declared in the front matter of _index.md
are not currently respected at build time as of v0.19. This is a known issue (#3005).
{{% /warning %}}
Many sites support rendering content in a few different ways; e.g., a single page view and a summary view to be used when displaying a list of section contents.
Hugo limits assumptions about how you want to display your content to an intuitive set of sane defaults and will support as many different views of a content type as your site requires. All that is required for these additional views is that a template exists in each /layouts/<TYPE>
directory with the same name.
The lookup order for the content/events/my-first-event.md
templates would be as follows:
layouts/event/birthday.html
layouts/event/single.html
layouts/events/single.html
layouts/_default/single.html
We can then create a custom archetype with preconfigured front matter at event.md
in the /archetypes
directory; i.e. archetypes/event.md
.
Read Archetypes for more information on archetype usage with hugo new
.
Tumblr
{{% note %}}
This section is outdated, see https://github.com/gohugoio/hugoDocs/issues/11
{{% /note %}}
{{% todo %}}
See above
{{% /todo %}}
Archetypes are content files in the archetypes directory of your project that contain preconfigured front matter for your website’s content types. Archetypes facilitate consistent metadata across your website content and allow content authors to quickly generate instances of a content type via the hugo new
command.
{{< youtube S3Tj3UcTFz8 >}}
The hugo new
generator for archetypes assumes your working directory is the content folder at the root of your project. Hugo is able to infer the appropriate archetype by assuming the content type from the content section passed to the CLI command:
hugo new <content-section>/<file-name.md>
We can use this pattern to create a new .md
file in the posts
section:
{{< code file=“archetype-example.sh” >}}
hugo new posts/my-first-post.md
{{< /code >}}
{{% note “Override Content Type in a New File” %}}
To override the content type Hugo infers from content−section
, add the --kind
flag to the end of the hugo new
command.
{{% /note %}}
Running this command in a new site that does not have default or custom archetypes will create the following file:
{{< output file=“content/posts/my-first-post.md” >}}
+++
date = “2017-02-01T19:20:04-07:00”
title = “my first post”
draft = true
+++
{{< /output >}}
{{% note %}}
In this example, if you do not already have a content/posts
directory, Hugo will create both content/posts/
and content/posts/my-first-post.md
for you.
{{% /note %}}
The auto-populated fields are worth examining:
title
is generated from the new content’s filename (i.e. in this case, my-first-post
becomes "my first post"
)date
and title
are the variables that ship with Hugo and are therefore included in all content files created with the Hugo CLI. date
is generated in RFC 3339 format by way of Go’s now()
function, which returns the current time.draft = true
, is not inherited by your default or custom archetypes but is included in Hugo’s automatically scaffolded default.md
archetype for convenience.Three variables per content file are often not enough for effective content management of larger websites. Luckily, Hugo provides a simple mechanism for extending the number of variables through custom archetypes, as well as default archetypes to keep content creation DRY.
Similar to the lookup order for templates in your layouts
directory, Hugo looks for a section- or type-specific archetype, then a default archetype, and finally an internal archetype that ships with Hugo. For example, Hugo will look for an archetype for content/posts/my-first-post.md
in the following order:
archetypes/posts.md
archetypes/default.md
themes/<THEME>/archetypes/posts.md
themes/<THEME>/archetypes/default.md
(Auto-generated with hugo new site
){{% note “Using a Theme Archetype” %}}
If you wish to use archetypes that ship with a theme, the theme
field must be specified in your configuration file.
{{% /note %}}
By default, hugo new
content files include front matter in the TOML format regardless of the format used in archetypes/*.md
.
You can specify a different default format in your site configuration file file using the metaDataFormat
directive. Possible values are toml
, yaml
, and json
.
Default archetypes are convenient if your content’s front matter stays consistent across multiple content sections.
When you create a new Hugo project using hugo new site
, you’ll notice that Hugo has already scaffolded a file at archetypes/default.md
.
The following examples are from a site that’s using tags
and categories
as taxonomies. If we assume that all content files will require these two key-values, we can create a default.md
archetype that extends Hugo’s base archetype. In this example, we are including “golang” and “hugo” as tags and “web development” as a category.
{{< code file=“archetypes/default.md” >}}
+++
tags = “golang”,“hugo”
{{% warning “EOL Characters in Text Editors”%}}
If you get an EOF error
when using hugo new
, add a carriage return after the closing +++
or ---
for your TOML or YAML front matter, respectively. (See the troubleshooting article on EOF errors for more information.)
{{% /warning %}}
With an archetypes/default.md
in place, we can use the CLI to create a new post in the posts
content section:
{{< code file=“new-post-from-default.sh” >}}
$ hugo new posts/my-new-post.md
{{< /code >}}
Hugo then creates a new markdown file with the following front matter:
{{< output file=“content/posts/my-new-post.md” >}}
+++
categories = “webdevelopment”
We see that the title
and date
key-values have been added in addition to the tags
and categories
key-values from archetypes/default.md
.
{{% note “Ordering of Front Matter” %}}
You may notice that content files created with hugo new
do not respect the order of the key-values specified in your archetype files. This is a known issue.
{{% /note %}}
Suppose your site’s posts
section requires more sophisticated front matter than what has been specified in archetypes/default.md
. You can create a custom archetype for your posts at archetypes/posts.md
that includes the full set of front matter to be added to the two default archetypes fields.
{{< code file=“archetypes/posts.md”>}}
+++
description = “”
tags = “”
categories = “”
+++
{{< /code >}}
With an archetypes/posts.md
in place, you can use the Hugo CLI to create a new post with your preconfigured front matter in the posts
content section:
{{< code file=“new-post-from-custom.sh” >}}
$ hugo new posts/post-from-custom.md
{{< /code >}}
This time, Hugo recognizes our custom archetypes/posts.md
archetype and uses it instead of archetypes/default.md
. The generated file will now include the full list of front matter parameters, as well as the base archetype’s title
and date
:
{{< output file=“content/posts/post-from-custom-archetype.md” >}}
+++
categories = “”
date = 2017-02-13T17:24:43-08:00
description = “”
tags = “”
title = “post from custom archetype”
+++
{{< /output >}}
As an example of archetypes in practice, the following is the functions
archetype from the Hugo docs:
{{< code file=“archetypes/functions.md” >}}
{{< readfile file=“/themes/gohugoioTheme/archetypes/functions.md” >}}
{{< /code >}}
{{% note %}}
The preceding archetype is kept up to date with every Hugo build by using Hugo’s readFile
function. For similar examples, see Local File Templates.
{{% /note %}}
Hugo includes support for user-defined groupings of content called taxonomies. Taxonomies are classifications of logical relationships between content.
{{< youtube “-np9GX6cL38” >}}
Let’s assume you are making a website about movies. You may want to include the following taxonomies:
Then, in each of the movies, you would specify terms for each of these taxonomies (i.e., in the front matter of each of your movie content files). From these terms, Hugo would automatically create pages for each Actor, Director, Studio, Genre, Year, and Award, with each listing all of the Movies that matched that specific Actor, Director, Studio, Genre, Year, and Award.
To continue with the example of a movie site, the following demonstrates content relationships from the perspective of the taxonomy:
Actor <- Taxonomy
Bruce Willis <- Term
The Sixth Sense <- Content
Unbreakable <- Content
Moonrise Kingdom <- Content
Samuel L. Jackson <- Term
Unbreakable <- Content
The Avengers <- Content
xXx <- Content
From the perspective of the content, the relationships would appear differently, although the data and labels used are the same:
Unbreakable <- Content
Actors <- Taxonomy
Bruce Willis <- Term
Samuel L. Jackson <- Term
Director <- Taxonomy
M. Night Shyamalan <- Term
...
Moonrise Kingdom <- Content
Actors <- Taxonomy
Bruce Willis <- Term
Bill Murray <- Term
Director <- Taxonomy
Wes Anderson <- Term
...
Hugo natively supports taxonomies.
Without adding a single line to your site’s configuration file, Hugo will automatically create taxonomies for tags
and categories
. If you do not want Hugo to create any taxonomies, set disableKinds
in your site’s configuration to the following:
disableKinds = ["taxonomy","taxonomyTerm"]
When taxonomies are used—and taxonomy templates are provided—Hugo will automatically create both a page listing all the taxonomy’s terms and individual pages with lists of content associated with each term. For example, a categories
taxonomy declared in your configuration and used in your content front matter will create the following pages:
example.com/categories/
that lists all the terms within the taxonomy/categories/development/
) for each of the terms that shows a listing of all pages marked as part of that taxonomy within any content file’s front matterTaxonomies must be defined in your website configuration before they can be used throughout the site. You need to provide both the plural and singular labels for each taxonomy. For example, singular key = "plural value"
for TOML and singular key: "plural value"
for YAML.
[taxonomies]
tag = "tags"
category = "categories"
series = "series"
taxonomies:
tag: "tags"
category: "categories"
series: "series"
By default, taxonomy names are normalized.
Therefore, if you want to have a taxonomy term with special characters such as Gérard Depardieu
instead of Gerard Depardieu
, set the value for preserveTaxonomyNames
to true
in your site configuration. Hugo will then preserve special characters in taxonomy values but will still title-ize the values for titles and normalize them in URLs.
Note that if you use preserveTaxonomyNames
and intend to manually construct URLs to the archive pages, you will need to pass the taxonomy values through the urlize
template function.
{{% note %}}
You can add content and front matter to your taxonomy list and taxonomy terms pages. See Content Organization for more information on how to add an _index.md
for this purpose.
Note also that taxonomy permalinks are not configurable.
{{% /note %}}
Once a taxonomy is defined at the site level, any piece of content can be assigned to it, regardless of content type or content section.
Assigning content to a taxonomy is done in the front matter. Simply create a variable with the plural name of the taxonomy and assign all terms you want to apply to the instance of the content type.
{{% note %}}
If you would like the ability to quickly generate content files with preconfigured taxonomies or terms, read the docs on Hugo archetypes.
{{% /note %}}
+++
title = "Hugo: A fast and flexible static site generator"
tags = [ "Development", "Go", "fast", "Blogging" ]
categories = [ "Development" ]
series = [ "Go Web Dev" ]
slug = "hugo"
project_url = "https://github.com/gohugoio/hugo"
+++
---
title: "Hugo: A fast and flexible static site generator"
#tags: ["Development", "Go", "fast", "Blogging"]
categories: ["Development"]
series: ["Go Web Dev"]
slug: "hugo"
project_url: "https://github.com/gohugoio/hugo"
---
{
"title": "Hugo: A fast and flexible static site generator",
"tags": [
"Development",
"Go",
"fast",
"Blogging"
],
"categories" : [
"Development"
],
"series" : [
"Go Web Dev"
],
"slug": "hugo",
"project_url": "https://github.com/gohugoio/hugo"
}
A content file can assign weight for each of its associate taxonomies. Taxonomic weight can be used for sorting or ordering content in taxonomy list templates and is declared in a content file’s front matter. The convention for declaring taxonomic weight is taxonomyname_weight
.
The following TOML and YAML examples show a piece of content that has a weight of 22, which can be used for ordering purposes when rendering the pages assigned to the “a”, “b” and “c” values of the tags
taxonomy. It has also been assigned the weight of 44 when rendering the “d” category page.
weight
+++
title = "foo"
tags = [ "a", "b", "c" ]
tags_weight = 22
categories = ["d"]
categories_weight = 44
+++
weight
---
title: foo
#tags: [ "a", "b", "c" ]
tags_weight: 22
categories: ["d"]
categories_weight: 44
---
By using taxonomic weight, the same piece of content can appear in different positions in different taxonomies.
{{% note “Limits to Ordering Taxonomies” %}}
Currently taxonomies only support the default weight => date
ordering of list content. For more information, see the documentation on taxonomy templates.
{{% /note %}}
With the use of the .Summary
page variable, Hugo generates summaries of content to use as a short version in summary views.
It is natural to accompany the summary with links to the original content, and a common design pattern is to see this link in the form of a “Read More …” button. See the .RelPermalink
, .Permalink
, and .Truncated
page variables.
By default, Hugo automatically takes the first 70 words of your content as its summary and stores it into the .Summary
page variable for use in your templates. Taking the Hugo-defined approach to summaries may save time, but it has pros and cons:
{{% note %}}
The Hugo-defined summaries are set to use word count calculated by splitting the text by one or more consecutive white space characters. If you are creating content in a CJK
language and want to use Hugo’s automatic summary splitting, set hasCJKLanguage
to true
in you site configuration.
{{% /note %}}
Alternatively, you may add the <!--more-->
summary divider where you want to split the article. For org content, use # more
where you want to split the article. Content that comes before the summary divider will be used as that content’s summary and stored in the .Summary
page variable with all HTML formatting intact.
{{% note “Summary Divider”%}}
The concept of a summary divider is not unique to Hugo. It is also called the “more tag” or “excerpt separator” in other literature.
{{% /note %}}
<!--more-->
(or # more
for org content) in each content file. This can be automated by adding the summary divider below the front matter of an archetype.{{% warning “Be Precise with the Summary Divider” %}}
Be careful to enter <!--more-->
exactly; i.e., all lowercase and with no whitespace.
{{% /warning %}}
You can show content summaries with the following code. You could use the following snippet, for example, in a sectiontemplate
{{< code file=“page-list-with-summaries.html” >}}
{{ range first 10 .Data.Pages }}
Note how the .Truncated
boolean valuable may be used to hide the “Read More…” link when the content is not truncated; i.e., when the summary contains the entire article.
sectiontemplate
The ref
and relref
shortcodes link documents together, both of which are built-in Hugo shortcodes. These shortcodes are also used to provide links to headings inside of your content, whether across documents or within a document. The only difference between ref
and relref
is whether the resulting URL is absolute (http://1.com/about/
) or relative (/about/
), respectively.
ref
and relref
{{</* ref "document" */>}}
{{</* ref "#anchor" */>}}
{{</* ref "document#anchor" */>}}
{{</* relref "document" */>}}
{{</* relref "#anchor" */>}}
{{</* relref "document#anchor" */>}}
The single parameter to ref
is a string with a content documentname
(e.g., about.md
) with or without an appended in-document anchor
(#who
) without spaces.
The documentname
is the name of a document, including the format extension; this may be just the filename, or the relative path from the content/
directory. With a document content/blog/post.md
, either format will produce the same result:
{{</* relref "blog/post.md" */>}} => `/blog/post/`
{{</* relref "post.md" */>}} => `/blog/post/`
If you have the same filename used across multiple sections, you should only use the relative path format; otherwise, the behavior will be undefined
. This is best illustrated with an example content
directory:
.
└── content
├── events
│ └── my-birthday.md
├── galleries
│ └── my-birthday.md
├── meta
│ └── my-article.md
└── posts
└── my-birthday.md
To be sure to get the correct reference in this case, use the full path:
{{< code file=“content/meta/my-article.md” copy=“false” >}}
{{</* relref “events/my-birthday.md” */>}} => /events/my-birthday/
{{< /code >}}
{{< todo >}}Remove this warning when https://github.com/gohugoio/hugo/issues/3703 is released.{{< /todo >}}
A relative document name must not begin with a slash (/
).
{{</* relref "/events/my-birthday.md" */>}} => ""
If the page exists in multiple output formats, ref
or relref
can be used with a output format name:
[Neat]({{</* ref "blog/neat.md" "amp" */>}})
When an anchor
is provided by itself, the current page’s unique identifier will be appended; when an anchor
is provided appended to documentname
, the found page’s unique identifier will be appended:
{{</* relref "#anchors" */>}} => #anchors:9decaf7
{{</* relref "about-hugo/hugo-features.md#content" */>}} => /blog/post/#who:badcafe
The above examples render as follows for this very page as well as a reference to the “Content” heading in the Hugo docs features pageyoursite
{{</* relref "#who" */>}} => #who:9decaf7
{{</* relref "blog/post.md#who" */>}} => /blog/post/#who:badcafe
More information about document unique identifiers and headings can be found below
{{</* ref "blog/post.md" */>}}
=> http://example.com/blog/post/
{{</* ref "post.md#tldr" */>}}
=> http://example.com/blog/post/#tldr:caffebad
{{</* relref "post.md" */>}}
=> /blog/post/
{{</* relref "blog/post.md#tldr" */>}}
=> /blog/post/#tldr:caffebad
{{</* ref "#tldr" */>}}
=> #tldr:badcaffe
{{</* relref "#tldr" */>}}
=> #tldr:badcaffe
When using Markdown document types, Hugo generates heading anchors automatically. The generated anchor for this section is hugo-heading-anchors
. Because the heading anchors are generated automatically, Hugo takes some effort to ensure that heading anchors are unique both inside a document and across the entire site.
Ensuring heading uniqueness across the site is accomplished with a unique identifier for each document based on its path. Unless a document is renamed or moved between sections in the filesystem, the unique identifier for the document will not change: blog/post.md
will always have a unique identifier of 81df004c333b392d34a49fd3a91ba720
.
ref
and relref
were added so you can make these reference links without having to know the document’s unique identifier. (The links in document tables of contents are automatically up-to-date with this value.)
{{</* relref "content-management/cross-references.md#hugo-heading-anchors" */>}}
/content-management/cross-references/#hugo-heading-anchors:77cd9ea530577debf4ce0f28c8dca242
shortcode
The default Hugo target directory for your built website is public/
. However, you can change this value by specifying a different publishDir
in your site configuration. The directories created at build time for a section reflect the position of the content’s directory within the content
folder and namespace matching its layout within the contentdir
hierarchy.
The permalinks
option in your site configuration allows you to adjust the directory paths (i.e., the URLs) on a per-section basis. This will change where the files are written to and will change the page’s internal “canonical” location, such that template references to .RelPermalink
will honor the adjustments made as a result of the mappings in this option.
{{% note “Default Publish and Content Folders” %}}
These examples use the default values for publishDir
and contentDir
; i.e., publish
and content
, respectively. You can override the default values in your site’s config
file.
{{% /note %}}
For example, if one of your sections is called post
and you want to adjust the canonical path to be hierarchical based on the year, month, and post title, you could set up the following configurations in YAML and TOML, respectively.
{{< code file=“config.yml” copy=“false” >}}
permalinks:
post: /:year/:month/:title/
{{< /code >}}
{{< code file=“config.toml” copy=“false” >}}
permalinks
Only the content under post/
will have the new URL structure. For example, the file content/post/sample-entry.md
with date: 2017-02-27T19:20:00-05:00
in its front matter will render to public/2017/02/sample-entry/index.html
at build time and therefore be reachable at http://example.com/2013/11/sample-entry/
.
The following is a list of values that can be used in a permalink
definition in your site config
file. All references to time are dependent on the content’s date.
:year
:month
:monthname
:day
:weekday
:weekdayname
:yearday
:section
:title
:slug
:filename
For people migrating existing published content to Hugo, there’s a good chance you need a mechanism to handle redirecting old URLs.
Luckily, redirects can be handled easily with aliases in Hugo.
Let’s assume you create a new piece of content at content/posts/my-awesome-blog-post.md
. The content is a revision of your previous post at content/posts/my-original-url.md
. You can create an aliases
field in the front matter of your new my-awesome-blog-post.md
where you can add previous paths. The following examples show how to create this filed in TOML and YAML front matter, respectively.
{{< code file=“content/posts/my-awesome-post.md” copy=“false” >}}
+++
aliases = “/posts/my−original−url/”,“/2010/01/01/even−earlier−url.html”
{{< /code >}}
Now when you visit any of the locations specified in aliases—i.e., assuming the same site domain—you’ll be redirected to the page they are specified on. For example, a visitor to example.com/posts/my-original-url/
will be immediately redirected to example.com/posts/my-awesome-blog-post/
.
On multilingual sites, each translation of a post can have unique aliases. To use the same alias across multiple languages, prefix it with the language code.
In /posts/my-new-post.es.md
:
---
aliases:
- /es/posts/my-original-post/
---
When aliases are specified, Hugo creates a directory to match the alias entry. Inside the directory, Hugo creates an .html
file specifying the canonical URL for the page and the new redirect target.
For example, a content file at posts/my-intended-url.md
with the following in the front matter:
---
title: My New post
aliases: [/posts/my-old-url/]
---
Assuming a baseURL
of example.com
, the contents of the auto-generated alias .html
found at https://example.com/posts/my-old-url/ will contain the following:
<!DOCTYPE html>
<html>
<head>
<title>http://example.com/posts/my-intended-url</title>
<link rel="canonical" href="http://example.com/posts/my-intended-url"/>
<meta name=\"robots\" content=\"noindex\">
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<meta http-equiv="refresh" content="0; url=http://example.com/posts/my-intended-url"/>
</head>
</html>
The http-equiv="refresh"
line is what performs the redirect, in 0 seconds in this case. If an end user of your website goes to https://example.com/posts/my-old-url
, they will now be automatically redirected to the newer, correct URL. The addition of <meta name=\"robots\" content=\"noindex\">
lets search engine bots know they they should not crawl and index your new alias page.
You may customize this alias page by creating an alias.html
template in the
layouts folder of your site (i.e., layouts/alias.html
). In this case, the data passed to the template is
Permalink
Page
Hugo’s default behavior is to render your content with “pretty” URLs. No non-standard server-side configuration is required for these pretty URLs to work.
The following demonstrates the concept:
content/posts/_index.md
=> example.com/posts/index.html
content/posts/post-1.md
=> example.com/posts/post-1/
If you would like to have what are often referred to as “ugly URLs” (e.g., example.com/urls.html), set uglyurls = true
or uglyurls: true
in your site’s config.toml
or config.yaml
, respectively. You can also use the --uglyURLs=true
flag from the command line with hugo
or hugo server
…
If you want a specific piece of content to have an exact URL, you can specify this in the front matter under the url
key. The following are examples of the same content directory and what the eventual URL structure will be when Hugo runs with its default behavior.
See Content Organization for more details on paths.
.
└── content
└── about
| └── _index.md // <- http://example.com/about/
├── post
| ├── firstpost.md // <- http://example.com/post/firstpost/
| ├── happy
| | └── ness.md // <- http://example.com/post/happy/ness/
| └── secondpost.md // <- http://example.com/post/secondpost/
└── quote
├── first.md // <- http://example.com/quote/first/
└── second.md // <- http://example.com/quote/second/
Here’s the same organization run with hugo --uglyURLs
:
.
└── content
└── about
| └── _index.md // <- http://example.com/about/index.html
├── post
| ├── firstpost.md // <- http://example.com/post/firstpost.html
| ├── happy
| | └── ness.md // <- http://example.com/post/happy/ness.html
| └── secondpost.md // <- http://example.com/post/secondpost.html
└── quote
├── first.md // <- http://example.com/quote/first.html
└── second.md // <- http://example.com/quote/second.html
By default, all relative URLs encountered in the input are left unmodified, e.g. /css/foo.css
would stay as /css/foo.css
. The canonifyURLs
field in your site config
has a default value of false
.
By setting canonifyURLs
to true
, all relative URLs would instead be canonicalized using baseURL
. For example, assuming you have baseURL = https://example.com/
, the relative URL /css/foo.css
would be turned into the absolute URL http://example.com/css/foo.css
.
Benefits of canonicalization include fixing all URLs to be absolute, which may aid with some parsing tasks. Note, however, that all modern browsers handle this on the client without issue.
Benefits of non-canonicalization include being able to have scheme-relative resource inclusion; e.g., so that http
vs https
can be decided according to how the page was retrieved.
{{% note “canonifyURLs
default change” %}}
In the May 2014 release of Hugo v0.11, the default value of canonifyURLs
was switched from true
to false
, which we think is the better default and should continue to be the case going forward. Please verify and adjust your website accordingly if you are upgrading from v0.10 or older versions.
{{% /note %}}
To find out the current value of canonifyURLs
for your website, you may use the handy hugo config
command added in v0.13.
hugo config | grep -i canon
Or, if you are on Windows and do not have grep
installed:
hugo config | FINDSTR /I canon
In addition to specifying permalink values in your site configuration for different content sections, Hugo provides even more granular control for individual pieces of content.
Both slug
and url
can be defined in individual front matter. For more information on content destinations at build time, see Content Organization.
By default, all relative URLs are left unchanged by Hugo, which can be problematic when you want to make your site browsable from a local file system.
Setting relativeURLs
to true
in your site configuration will cause Hugo to rewrite all relative URLs to be relative to the current content.
For example, if your /post/first/
page contains a link to /about/
, Hugo will rewrite the URL to ../../about/
.
{{% note “Lazy Blogger”%}}
If all you want is a simple menu for your sections, see the “Section Menu for Lazy Bloggers” in Menu Templates.
{{% /note %}}
You can do this:
A menu is a named array of menu entries accessible by name via the .Site.Menus
site variable. For example, you can access your site’s main
menu via .Site.Menus.main
.
{{% note “Menus on Multilingual Sites” %}}
If you make use of the multilingual feature, you can define language-independent menus.
{{% /note %}}
A menu entry has the following properties (i.e., variables) available to it:
.URL
.Name
.Menu
.Identifier
.Pre
.Post
.Weight
.Parent
.Children
Note that menus also have the following functions available as well:
.HasChildren
Additionally, there are some relevant functions available to menus on a page:
.IsMenuCurrent
.HasMenuCurrent
Hugo allows you to add content to a menu via the content’s front matter.
If all you need to do is add an entry to a menu, the simple form works well.
---
menu: "main"
---
---
menu: ["main", "footer"]
---
---
menu:
docs:
parent: 'extras'
weight: 20
---
You can also add entries to menus that aren’t attached to a piece of content. This takes place in your Hugo project’s config
file.
Here’s an example snippet pulled from a config.toml
:
{{< code file=“config.toml” >}}
[menu.main
Here’s the equivalent snippet in a config.yaml
:
{{< /code >}}
{{% note %}}
The URLs must be relative to the context root. If the baseURL
is http://example.com/mysite/
, then the URLs in the menu must not include the context root mysite
. Using an absolute URL will overide the baseURL. If the value used for URL
in the above example is http://subdomain.example.com/
, the output will be http://subdomain.example.com
.
{{% /note %}}
All nesting of content is done via the parent
field.
The parent of an entry should be the identifier of another entry. The identifier should be unique (within a menu).
The following order is used to determine an Identifier:
.Name > .LinkTitle > .Title
This means that .Title
will be used unless .LinkTitle
is present, etc. In practice, .Name
and .Identifier
are only used to structure relationships and therefore never displayed.
In this example, the top level of the menu is defined in your site config
file). All content entries are attached to one of these entries via the .Parent
field.
See Menu Templates for information on how to render your site menus within your templates.
{{% note “TOC Heading Levels are Fixed” %}}
Currently, the {{.TableOfContents}}
page variable does not allow you to specify which heading levels you want the TOC to render. See the related GitHub discussion (#1778). As such, the resulting <nav id="TableOfContents"><ul></ul></nav>
is going to start at <h1>
when pulling from {{.Content}}
.
{{% /note %}}
Create your markdown the way you normally would with the appropriate headings. Here is some example content:
<!-- Your front matter up here -->
## Introduction
One morning, when Gregor Samsa woke from troubled dreams, he found himself transformed in his bed into a horrible vermin.
## My Heading
He lay on his armour-like back, and if he lifted his head a little he could see his brown belly, slightly domed and divided by arches into stiff sections. The bedding was hardly able to cover it and seemed ready to slide off any moment.
### My Subheading
A collection of textile samples lay spread out on the table - Samsa was a travelling salesman - and above it there hung a picture that he had recently cut out of an illustrated magazine and housed in a nice, gilded frame. It showed a lady fitted out with a fur hat and fur boa who sat upright, raising a heavy fur muff that covered the whole of her lower arm towards the viewer. Gregor then turned to look out the window at the dull weather. Drops
Hugo will take this Markdown and create a table of contents from ## Introduction
, ## My Heading
, and ### My Subheading
and then store it in the page variable.TableOfContents
.
The built-in .TableOfContents
variables outputs a <nav id="TableOfContents">
element with a child <ul>
, whose child <li>
elements begin with any <h1>
‘s (i.e., #
in markdown) inside your content.’
The following is an example of a very basic single page template:
{{< code file=“layout/_default/single.html” download=“single.html” >}}
{{ define “main” }}
The following is a partial template that adds slightly more logic for page-level control over your table of contents. It assumes you are using a toc
field in your content’s front matter that, unless specifically set to false
, will add a TOC to any page with a .WordCount
(see Page Variables) greater than 400. This example also demonstrates how to use conditionals in your templating:
{{< code file=“layouts/partials/toc.html” download=“toc.html” >}}
{{ if and (gt .WordCount 400 ) (ne .Params.toc “false”) }}
{{% note %}}
With the preceding example, even pages with > 400 words and toc
not set to false
will not render a table of contents if there are no headings in the page for the {{.TableOfContents}}
variable to pull from.
{{% /note %}}
single page template: /templates/single-page-templates/
Hugo ships with support for Disqus, a third-party service that provides comment and community capabilities to websites via JavaScript.
Your theme may already support Disqus, but if not, it is easy to add to your templates via Hugo’s built-in Disqus partial.
Hugo comes with all the code you need to load Disqus into your templates. Before adding Disqus to your site, you’ll need to set up an account.
Disqus comments require you set a single value in your site’s configuration file. The following show the configuration variable in a config.toml
and config.yml
, respectively:
disqusShortname = "yourdiscussshortname"
disqusShortname: "yourdiscussshortname"
For many websites, this is enough configuration. However, you also have the option to set the following in the front matter of a single content file:
disqus_identifier
disqus_title
disqus_url
See Partial Templates to learn how to add the Disqus partial to your Hugo website’s templates.
There are a few alternatives to commenting on static sites for those who do not want to use Disqus:
You should define the available languages in a Languages
section in your site configuration.
The following is an example of a TOML site configuration for a multilingual Hugo project:
{{< code file=“config.toml” download=“config.toml” >}}
DefaultContentLanguage = “en”
copyright = “Everything is mine”
params.navigation
Languages
[Languages.fr]
copyright = “Tout est à moi”
title = “Mon blog”
weight = 2
Languages.fr.params
Anything not defined in a Languages
block will fall back to the global
value for that key (e.g., copyright
for the English [en
] language).
With the configuration above, all content, sitemap, RSS feeds, paginations,
and taxonomy pages will be rendered below /
in English (your default content language) and then below /fr
in French.
When working with front matter Params
in single page templates, omit the params
in the key for the translation.
If you want all of the languages to be put below their respective language code, enable defaultContentLanguageInSubdir: true
.
Only the obvious non-global options can be overridden per language. Examples of global options are baseURL
, buildDrafts
, etc.
Taxonomies and Blackfriday configuration can also be set per language:
{{< code file=“bf-config.toml” >}}
Taxonomies
tag = “tags”
blackfriday
angledQuotes = true
hrefTargetBlank = true
Languages
[Languages.fr]
weight = 2
title = “Français”
Languages.fr.Taxonomies
Translated articles are identified by the name of the content file.
/content/about.en.md
/content/about.fr.md
In this example, the about.md
will be assigned the configured defaultContentLanguage
.
/content/about.md
/content/about.fr.md
This way, you can slowly start to translate your current content without having to rename everything. If left unspecified, the default value for defaultContentLanguage
is en
.
By having the same base filename, the content pieces are linked together as translated pieces.
If you need distinct URLs per language, you can set the slug in the non-default language file. For example, you can define a custom slug for a French translation in the front matter of content/about.fr.md
as follows:
slug: "a-propos"
At render, Hugo will build both /about/
and /a-propos/
as properly linked translated pages.
{{%note %}}
Hugo currently uses the base filename as the translation key, which can be an issue with identical filenames in different sections.
We will fix this in https://github.com/gohugoio/hugo/issues/2699
{{% /note %}}
{{< todo >}}Rewrite/remove the above one issue is fixed.{{< /todo >}}
To create a list of links to translated content, use a template similar to the following:
{{< code file=“layouts/partials/i18nlist.html” >}}
{{ if .IsTranslated }}
The above can be put in a partial
(i.e., inside layouts/partials/
) and included in any template, be it for a single content page or the homepage. It will not print anything if there are no translations for a given page, or if there are translations—in the case of the homepage, section listing, etc.—a site with only render one language.
The above also uses the i18n
function described in the next section.
Hugo uses go-i18n to support string translations. See the project’s source repository to find tools that will help you manage your translation workflows.
Translations are collected from the themes/<THEME>/i18n/
folder (built into the theme), as well as translations present in i18n/
at the root of your project. In the i18n
, the translations will be merged and take precedence over what is in the theme folder. Language files should be named according to RFC 5646 with names such as en-US.toml
, fr.toml
, etc.
From within your templates, use the i18n
function like this:
{{ i18n "home" }}
This uses a definition like this one in i18n/en-US.toml
:
[home]
other = "Home"
Often you will want to use to the page variables in the translations strings. To do that, pass on the “.” context when calling i18n
:
{{ i18n "wordCount" . }}
This uses a definition like this one in i18n/en-US.toml
:
[wordCount]
other = "This article has {{ .WordCount }} words."
An example of singular and plural form:
[readingTime]
one = "One minute read"
other = "{{.Count}} minutes read"
And then in the template:
{{ i18n "readingTime" .ReadingTime }}
To track down missing translation strings, run Hugo with the --i18n-warnings
flag:
hugo --i18n-warnings | grep i18n
i18n|MISSING_TRANSLATION|en|wordCount
At the time of this writing, Golang does not yet have support for internationalized locales, but if you do some work, you can simulate it. For example, if you want to use French month names, you can add a data file like data/mois.yaml
with this content:
1: "janvier"
2: "février"
3: "mars"
4: "avril"
5: "mai"
6: "juin"
7: "juillet"
8: "août"
9: "septembre"
10: "octobre"
11: "novembre"
12: "décembre"
… then index the non-English date names in your templates like so:
<time class="post-date" datetime="{{ .Date.Format "2006-01-02T15:04:05Z07:00" | safeHTML }}">
Article publié le {{ .Date.Day }} {{ index $.Site.Data.mois (printf "%d" .Date.Month) }} {{ .Date.Year }} (dernière modification le {{ .Lastmod.Day }} {{ index $.Site.Data.mois (printf "%d" .Lastmod.Month) }} {{ .Lastmod.Year }})
</time>
This technique extracts the day, month and year by specifying .Date.Day
, .Date.Month
, and .Date.Year
, and uses the month number as a key, when indexing the month name data file.
You can define your menus for each language independently. The creation of a menu works analogous to earlier versions of Hugo, except that they have to be defined in their language-specific block in the configuration file:
defaultContentLanguage = "en"
[languages.en]
weight = 0
languageName = "English"
[[languages.en.menu.main]]
url = "/"
name = "Home"
weight = 0
[languages.de]
weight = 10
languageName = "Deutsch"
[[languages.de.menu.main]]
url = "/"
name = "Startseite"
weight = 0
The rendering of the main navigation works as usual. .Site.Menus
will just contain the menu of the current language. Pay attention to the generation of the menu links. absLangURL
takes care that you link to the correct locale of your website. Otherwise, both menu entries would link to the English version as the default content language that resides in the root directory.
<ul>
{{- $currentPage := . -}}
{{ range .Site.Menus.main -}}
<li class="{{ if $currentPage.IsMenuCurrent "main" . }}active{{ end }}">
<a href="{{ .URL | absLangURL }}">{{ .Name }}</a>
</li>
{{- end }}
</ul>
If a string does not have a translation for the current language, Hugo will use the value from the default language. If no default value is set, an empty string will be shown.
While translating a Hugo website, it can be handy to have a visual indicator of missing translations. The enableMissingTranslationPlaceholders
configuration option will flag all untranslated strings with the placeholder i18n
, where identifier
is the id of the missing translation.
{{% note %}}
Hugo will generate your website with these missing translation placeholders. It might not be suited for production environments.
{{% /note %}}
To support Multilingual mode in your themes, some considerations must be taken for the URLs in the templates. If there is more than one language, URLs must meet the following criteria:
.Permalink
or .URL
relLangURL
template function or the absLangURL
template function OR{{ .LanguagePrefix }}
If there is more than one language defined, the LanguagePrefix
variable will equal /en
(or whatever your CurrentLanguage
is). If not enabled, it will be an empty string and is therefore harmless for single-language Hugo websites.
{{% note %}}
The following is only a primer on Go templates. For an in-depth look into Go templates, check the official Go docs.
{{% /note %}}
Go templates provide an extremely simple template language that adheres to the belief that only the most basic of logic belongs in the template or view layer.
Golang templates are HTML files with the addition of variables and functions. Golang template variables and functions are accessible within {{ }}
.
{{ foo }}
Parameters for functions are separated using spaces. The following example calls the add
function with inputs of 1
and 2
:
{{ add 1 2 }}
Accessing the Page Parameter bar
defined in a piece of content’s front matter.
{{ .Params.bar }}
{{ if or (isset .Params "alt") (isset .Params "caption") }} Caption {{ end }}
Each Go template gets a data object. In Hugo, each template is passed a Page
. See variables for more information.
This is how you access a Page
variable from a template:
<title>{{ .Title }}</title>
Values can also be stored in custom variables and referenced later:
{{ $address := "123 Main St."}}
{{ $address }}
{{% warning %}}
Variables defined inside if
conditionals and similar are not visible on the outside. See https://github.com/golang/go/issues/10608.
Hugo has created a workaround for this issue in Scratch.
{{% /warning %}}
Go templates only ship with a few basic functions but also provide a mechanism for applications to extend the original set.
Hugo template functions provide additional functionality specific to building websites. Functions are called by using their name followed by the required parameters separated by spaces. Template functions cannot be added without recompiling Hugo.
{{ add 1 2 }}
=> 3
{{ lt 1 2 }}
=> true (i.e., since 1 is less than 2)
Note that both examples make us of Go template’s math functions.
{{% note “Additional Boolean Operators” %}}
There are more boolean operators than those listed in the Hugo docs in the Golang template documentation.
{{% /note %}}
When including another template, you will pass to it the data it will be
able to access. To pass along the current context, please remember to
include a trailing dot. The templates location will always be starting at
the /layout/
directory within Hugo.
{{ template "partials/header.html" . }}
Starting with Hugo v0.12, you may also use the partial
call
for partial templates:
{{ partial "header.html" . }}
Go templates provide the most basic iteration and conditional logic.
Just like in Go, the Go templates make heavy use of range
to iterate over
a map, array, or slice. The following are different examples of how to use
range.
{{ range array }}
{{ . }}
{{ end }}
{{range $element := array}}
{{ $element }}
{{ end }}
{{range $index, $element := array}}
{{ $index }}
{{ $element }}
{{ end }}
if
, else
, with
, or
, and and
provide the framework for handling conditional logic in Go Templates. Like range
, each statement is closed with an {{end}}
.
Go Templates treat the following values as false:
if
{{ if isset .Params "title" }}<h4>{{ index .Params "title" }}</h4>{{ end }}
if
… else
{{ if isset .Params "alt" }}
{{ index .Params "alt" }}
{{else}}
{{ index .Params "caption" }}
{{ end }}
and
& or
{{ if and (or (isset .Params "title") (isset .Params "caption")) (isset .Params "attr")}}
with
An alternative way of writing “if
” and then referencing the same value
is to use “with
” instead. with
rebinds the context .
within its scope
and skips the block if the variable is absent.
The first example above could be simplified as:
{{ with .Params.title }}<h4>{{ . }}</h4>{{ end }}
if
… else if
{{ if isset .Params "alt" }}
{{ index .Params "alt" }}
{{ else if isset .Params "caption" }}
{{ index .Params "caption" }}
{{ end }}
One of the most powerful components of Go templates is the ability to stack actions one after another. This is done by using pipes. Borrowed from Unix pipes, the concept is simple: each pipeline’s output becomes the input of the following pipe.
Because of the very simple syntax of Go templates, the pipe is essential to being able to chain together function calls. One limitation of the pipes is that they can only work with a single value and that value becomes the last parameter of the next pipeline.
A few simple examples should help convey how to use the pipe.
shuffle
The following two examples are functionally the same:
{{ shuffle (seq 1 5) }}
{{ (seq 1 5) | shuffle }}
index
The following accesses the page parameter called “disqus_url” and escapes the HTML. This example also uses the index
function, which is built into Go templates:
{{ index .Params "disqus_url" | html }}
or
with isset
{{ if or (or (isset .Params "title") (isset .Params "caption")) (isset .Params "attr") }}
Stuff Here
{{ end }}
Could be rewritten as
{{ if isset .Params "caption" | or isset .Params "title" | or isset .Params "attr" }}
Stuff Here
{{ end }}
By default, Go Templates remove HTML comments from output. This has the unfortunate side effect of removing Internet Explorer conditional comments. As a workaround, use something like this:
{{ "<!--[if lt IE 9]>" | safeHTML }}
<script src="html5shiv.js"></script>
{{ "<![endif]-->" | safeHTML }}
Alternatively, you can use the backtick (`
) to quote the IE conditional comments, avoiding the tedious task of escaping every double quotes ("
) inside, as demonstrated in the examples in the Go text/template documentation:
{{ `<!--[if lt IE 7]><html class="no-js lt-ie9 lt-ie8 lt-ie7"><![endif]-->` | safeHTML }}
The most easily overlooked concept to understand about Go templates is that {{ . }}
always refers to the current context. In the top level of your template, this will be the data set made available to it. Inside of an iteration, however, it will have the value of the current item in the loop; i.e., {{ . }}
will no longer refer to the data available to the entire page. If you need to access page-level data (e.g., page params set in front matter) from within the loop, you will likely want to do one of the following:
The following shows how to define a variable independent of the context.
{{< code file=“tags-range-with-page-variable.html” >}}
{{ $title := .Site.Title }}
{{% note %}}
Notice how once we have entered the loop (i.e. range
), the value of {{ . }}
has changed. We have defined a variable outside of the loop ({{$title}}
) that we’ve assigned a value so that we have access to the value from within the loop as well.
{{% /note %}}
$.
to Access the Global Context$
has special significance in your templates. $
is set to the starting value of .
(“the dot”) by default. This is a documented feature of Go text/template. This means you have access to the global context from anywhere. Here is an equivalent example of the preceding code block but now using $
to grab .Site.Title
from the global context:
{{< code file=“range-through-tags-w-global.html” >}}
{{% warning “Don’t Redefine the Dot” %}}
The built-in magic of $
would cease to work if someone were to mischievously redefine the special character; e.g. {{ $ := .Site }}
. Don’t do it. You may, of course, recover from this mischief by using {{ $ := . }}
in a global context to reset $
to its default value.
{{% /warning %}}
Go 1.6 includes the ability to trim the whitespace from either side of a Go tag by including a hyphen (-
) and space immediately beside the corresponding {{
or }}
delimiter.
For instance, the following Go template will include the newlines and horizontal tab in its HTML output:
<div>
{{ .Title }}
</div>
Which will output:
<div>
Hello, World!
</div>
Leveraging the -
in the following example will remove the extra white space surrounding the .Title
variable and remove the newline:
<div>
{{- .Title -}}
</div>
Which then outputs:
<div>Hello, World!</div>
Go considers the following characters whitespace:
Hugo provides the option of passing values to your template layer through your site configuration (i.e. for site-wide values) or through the metadata of each specific piece of content (i.e. the front matter). You can define any values of any type and use them however you want in your templates, as long as the values are supported by the front matter format specified via metaDataFormat
in your configuration file.
Page
) ParametersYou can provide variables to be used by templates in individual content’s front matter.
An example of this is used in the Hugo docs. Most of the pages benefit from having the table of contents provided, but sometimes the table of contents doesn’t make a lot of sense. We’ve defined a notoc
variable in our front matter that will prevent a table of contents from rendering when specifically set to true
.
Here is the example front matter:
---
title: Roadmap
lastmod: 2017-03-05
date: 2013-11-18
notoc: true
---
Here is an example of corresponding code that could be used inside a toc.html
partial template:
{{< code file=“layouts/partials/toc.html” download=“toc.html” >}}
{{ if not .Params.notoc }}
We want the default behavior to be for pages to include a TOC unless otherwise specified. This template checks to make sure that the notoc:
field in this page’s front matter is not true
.
You can arbitrarily define as many site-level parameters as you want in your site’s configuration file. These parameters are globally available in your templates.
For instance, you might declare the following:
{{< code file=“config.yaml” >}}
params:
copyrighthtml: “Copyright © 2017 John Doe. All Rights Reserved.”
twitteruser: “spf13”
sidebarrecentlimit: 5
{{< /code >}}
Within a footer layout, you might then declare a <footer>
that is only rendered if the copyrighthtml
parameter is provided. If it is provided, you will then need to declare the string is safe to use via the safeHTML
function so that the HTML entity is not escaped again. This would let you easily update just your top-level config file each January 1st, instead of hunting through your templates.
{{if .Site.Params.copyrighthtml}}<footer>
<div class="text-center">{{.Site.Params.CopyrightHTML | safeHTML}}</div>
</footer>{{end}}
An alternative way of writing the “if
” and then referencing the same value is to use with
instead. with
rebinds the context (.
) within its scope and skips the block if the variable is absent:
{{< code file=“layouts/partials/twitter.html” >}}
{{with .Site.Params.twitteruser}}
Finally, you can pull “magic constants” out of your layouts as well. The following uses the first
function, as well as the .RelPermalink
page variable and the .Site.Pages
site variable.
<nav>
<h1>Recent Posts</h1>
<ul>
{{- range first .Site.Params.SidebarRecentLimit .Site.Pages -}}
<li><a href="{{.RelPermalink}}">{{.Title}}</a></li>
{{- end -}}
</ul>
</nav>
Go allows you to do more than what’s shown here. Using Hugo’s where
function and Go built-ins, we can list only the items from content/events/
whose date (set in a content file’s front matter) is in the future. The following is an example partial template:
{{< code file=“layouts/partials/upcoming-events.html” download=“upcoming-events.html” >}}
Before creating your templates, it’s important to know how Hugo looks for files within your project’s directory structure.
Hugo uses a prioritized list called the lookup order as it traverses your layouts
folder in your Hugo project looking for the appropriate template to render your content.
The template lookup order is an inverted cascade: if template A isn’t present or specified, Hugo will look to template B. If template B isn’t present or specified, Hugo will look for template C…and so on until it reaches the _default/
directory for your project or theme. In many ways, the lookup order is similar to the programming concept of a switch statement without fallthrough.
The power of the lookup order is that it enables you to craft specific layouts and keep your templating DRY.
{{% note %}}
Most Hugo websites will only need the default template files at the end of the lookup order (i.e. _default/*.html
).
{{% /note %}}
The respective lookup order for each of Hugo’s templates has been defined throughout the Hugo docs:
The lookup order is best illustrated through examples. The following shows you the process Hugo uses for finding the appropriate template to render your single page templates, but the concept holds true for all templates in Hugo.
mytheme
(specified in the project’s configuration)..
├── content
│ ├── events
│ │ ├── _index.md
│ │ └── my-first-event.md
│ └── posts
│ ├── my-first-post.md
│ └── my-second-post.md
├── layouts
│ ├── _default
│ │ └── single.html
│ ├── posts
│ │ └── single.html
│ └── reviews
│ └── reviewarticle.html
└── themes
└── mytheme
└── layouts
├── _default
│ ├── list.html
│ └── single.html
└── posts
├── list.html
└── single.html
Now we can look at the front matter for the three content (i.e..md
) files.
{{% note %}}
Only three of the four markdown files in the above project are subject to the single page lookup order. _index.md
is a specific kind
in Hugo. Whereas my-first-post.md
, my-second-post.md
, and my-first-event.md
are all of kind page
, all _index.md
files in a Hugo project are used to add content and front matter to list pages. In this example, events/_index.md
will render according to its section template and respective lookup order.
{{% /note %}}
my-first-post.md
{{< /code >}}
When building your site, Hugo will go through the lookup order until it finds what it needs for my-first-post.md
:
/layouts/UNSPECIFIED/UNSPECIFIED.html
/layouts/posts/UNSPECIFIED.html
/layouts/UNSPECIFIED/single.html
/layouts/posts/single.html
/layouts/_default/single.html
/themes/<THEME>/layouts/UNSPECIFIED/UNSPECIFIED.html
/themes/<THEME>/layouts/posts/UNSPECIFIED.html
/themes/<THEME>/layouts/UNSPECIFIED/single.html
/themes/<THEME>/layouts/posts/single.html
/themes/<THEME>/layouts/_default/single.html
Notice the term UNSPECIFIED
rather than UNDEFINED
. If you don’t tell Hugo the specific type and layout, it makes assumptions based on sane defaults. my-first-post.md
does not specify a content type
in its front matter. Therefore, Hugo assumes the content type
and section
(i.e. posts
, which is defined by file location) are one in the same. (Read more on sections.)
my-first-post.md
also does not specify a layout
in its front matter. Therefore, Hugo assumes that my-first-post.md
, which is of type page
and a single piece of content, should default to the next occurrence of a single.html
template in the lookup (#4).
my-second-post.md
{{< /code >}}
Here is the way Hugo traverses the single-page lookup order for my-second-post.md
:
/layouts/review/reviewarticle.html
/layouts/posts/reviewarticle.html
/layouts/review/single.html
/layouts/posts/single.html
/layouts/_default/single.html
/themes/<THEME>/layouts/review/reviewarticle.html
/themes/<THEME>/layouts/posts/reviewarticle.html
/themes/<THEME>/layouts/review/single.html
/themes/<THEME>/layouts/posts/single.html
/themes/<THEME>/layouts/_default/single.html
The front matter in my-second-post.md
specifies the content type
(i.e. review
) as well as the layout
(i.e. reviewarticle
). Hugo finds the layout it needs at the top level of the lookup (#1) and does not continue to search through the other templates.
{{% note “Type and not Types” %}}
Notice that the directory for the template for my-second-post.md
is review
and not reviews
. This is because type is always singular when defined in front matter.
{{% /note%}}
my-first-event.md
{{< /code >}}
Here is the way Hugo traverses the single-page lookup order for my-first-event.md
:
/layouts/UNSPECIFIED/UNSPECIFIED.html
/layouts/events/UNSPECIFIED.html
/layouts/UNSPECIFIED/single.html
/layouts/events/single.html
/layouts/_default/single.html
/themes/<THEME>/layouts/UNSPECIFIED/UNSPECIFIED.html
/themes/<THEME>/layouts/events/UNSPECIFIED.html
/themes/<THEME>/layouts/UNSPECIFIED/single.html
/themes/<THEME>/layouts/events/single.html
/themes/<THEME>/layouts/_default/single.html
{{% note %}}
my-first-event.md
is significant because it demonstrates the role of the lookup order in Hugo themes. Both the root project directory and the mytheme
themes directory have a file at _default/single.html
. Understanding this order allows you to customize Hugo themes by creating template files with identical names in your project directory that step in front of theme template files in the lookup. This allows you to customize the look and feel of your website while maintaining compatibility with the theme’s upstream.
{{% /note %}}
This page describes how to properly configure your site with the media types and output formats, as well as where to create your templates for your custom outputs.
A media type (also known as MIME type and content type) is a two-part identifier for file formats and format contents transmitted on the Internet.
This is the full set of built-in media types in Hugo:
{{< datatable “media” “types” “type” “suffix” >}}
Note:
text/html
to asp
.Suffix
is the value that will be used for URLs and filenames for that media type in Hugo.Type
is the identifier that must be used when defining new/custom Output Formats
(see below).To add or modify a media type, define it in a mediaTypes
section in your site configuration, either for all sites or for a given language.
Example in config.toml
:
[mediaTypes]
[mediaTypes."text/enriched"]
suffix = "enr"
[mediaTypes."text/html"]
suffix = "asp"
The above example adds one new media type, text/enriched
, and changes the suffix for the built-in text/html
media type.
Given a media type and some additional configuration, you get an Output Format
:
This is the full set of Hugo’s built-in output formats:
{{< datatable “output” “formats” “name” “mediaType” “path” “baseName” “rel” “protocol” “isPlainText” “isHTML” “noUgly”>}}
AMP
vs. HTML
. AMP
has the value amp
for Path
so it doesn’t overwrite the HTML
version; e.g. we can now have both /index.html
and /amp/index.html
.MediaType
must match the Type
of an already defined media type.AMP
pages in a different path.To add or modify an output format, define it in an outputFormats
section in your site’s configuration file, either for all sites or for a given language.
[outputFormats.MyEnrichedFormat]
mediaType = "text/enriched"
baseName = "myindex"
isPlainText = true
protocol = "bep://"
The above example is fictional, but if used for the homepage on a site with baseURL
http://example.org
, it will produce a plain text homepage with the URL bep://example.org/myindex.enr
.
The following is the full list of configuration options for output formats and their default values:
name
mediaType
Type
of a defined media type.path
baseName
index
.rel
rel
values in link
tags. Default: alternate
.protocol
baseURL
for this output format.isPlainText
false
.isHTML
HTML
-type formats; e.g., page aliases.noUgly
uglyURLs
is set to true
in your site. Default: false
.notAlternative
AlternativeOutputFormats
format listing on Page
(e.g., with CSS
). Note that we use the term alternative and not alternate here, as it does not necessarily replace the other format. Default: false
.A Page
in Hugo can be rendered to multiple representations on the file system. By default, all pages will render as HTML
with some of them also as RSS
(homepage, sections, etc.).
This can be changed by defining an outputs
list of output formats in either the Page
front matter or in the site configuration (either for all sites or per language).
Example from site config.toml
:
[outputs]
home = ["HTML", "AMP", "RSS"]
page = ["HTML"]
Example from site config.yml
:
outputs:
home: ["HTML", "AMP", "RSS"]
page: ["HTML"]
Page
Kind
(i.e, page
, home
, section
, taxonomy
, or taxonomyTerm
).Name
of a defined Output Format
.Kind
without a definition will default to HTML
.Page
in the front matter of content files.The following is an example of YAML
front matter in a content file that defines output formats for the rendered Page
:
---
date: "2016-03-19"
outputs:
- html
- amp
- json
---
Each Page
has both an .OutputFormats
(all formats, including the current) and an .AlternativeOutputFormats
variable, the latter of which is useful for creating a link rel
list in your site’s <head>
:
{{ range .AlternativeOutputFormats -}}
<link rel="{{ .Rel }}" type="{{ .MediaType.Type }}" href="{{ .Permalink | safeURL }}">
{{ end -}}
Note that .Permalink
and .RelPermalink
on Page
will return the first output format defined for that page (usually HTML
if nothing else is defined).
This is how you link to a given output format:
{{ with .OutputFormats.Get "json" -}}
<a href="{{ .Permalink }}">{{ .Name }}</a>
{{- end }}
From content files, you can use the ref
or relref
shortcodes:
[Neat]({{</* ref "blog/neat.md" "amp" */>}})
[Who]({{</* relref "about.md#who" "amp" */>}})
A new output format needs a corresponding template in order to render anything useful.
{{% note %}}
The key distinction for Hugo versions 0.20 and newer is that Hugo looks at an output format’s Name
and MediaType’s Suffix
when choosing the template used to render a given Page
.
{{% /note %}}
The following table shows examples of different output formats, the suffix used, and Hugo’s respective template lookup order. All of the examples in the table can:
{{< datatable “output” “layouts” “Example” “OutputFormat” “Suffix” “Template Lookup Order” >}}
Hugo will now also detect the media type and output format of partials, if possible, and use that information to decide if the partial should be parsed as a plain text template or not.
Hugo will look for the name given, so you can name it whatever you want. But if you want it treated as plain text, you should use the file suffix and, if needed, the name of the Output Format. The pattern is as follows:
[partial name].[OutputFormat].[suffix]
The partial below is a plain text template (Outpuf Format is CSV
, and since this is the only output format with the suffix csv
, we don’t need to include the Output Format’s Name
):
{{ partial "mytextpartial.csv" . }}
The block
keyword allows you to define the outer shell of your pages’ one or more master template(s) and then fill in or override portions as necessary.
The lookup order for base templates is as follows:
/layouts/section/<TYPE>-baseof.html
/themes/<THEME>/layouts/section/<TYPE>-baseof.html
/layouts/<TYPE>/baseof.html
/themes/<THEME>/layouts/<TYPE>/baseof.html
/layouts/section/baseof.html
/themes/<THEME>/layouts/section/baseof.html
/layouts/_default/post-baseof.html
/themes/<THEME>/layouts/_default/post-baseof.html
/layouts/_default/baseof.html
/themes/<THEME>/layouts/_default/baseof.html
Variables are denoted by capitalized text set within <>
. Note that Hugo’s default behavior is for type
to inherit from section
unless otherwise specified.
As an example, let’s assume your site is using a theme called “mytheme” when rendering the section list for a post
section. Hugo picks layout/section/post.html
as the template for rendering the section. The {{define}}
block in this template tells Hugo that the template is an extension of a base template.
Here is the lookup order for the post
base template:
/layouts/section/post-baseof.html
/themes/mytheme/layouts/section/post-baseof.html
/layouts/post/baseof.html
/themes/mytheme/layouts/post/baseof.html
/layouts/section/baseof.html
/themes/mytheme/layouts/section/baseof.html
/layouts/_default/post-baseof.html
/themes/mytheme/layouts/_default/post-baseof.html
/layouts/_default/baseof.html
/themes/mytheme/layouts/_default/baseof.html
The following defines a simple base template at _default/baseof.html
. As a default template, it is the shell from which all your pages will be rendered unless you specify another *baseof.html
closer to the beginning of the lookup order.
{{< code file=“layouts/_default/baseof.html” download=“baseof.html” >}}
From the above base template, you can define a default list template. The default list template will inherit all of the code defined above and can then implement its own "main"
block from:
{{< code file=“layouts/_default/list.html” download=“list.html” >}}
{{ define “main” }}
This replaces the contents of our (basically empty) “main” block with something useful for the list template. In this case, we didn’t define a "title"
block, so the contents from our base template remain unchanged in lists.
{{% warning %}}
Code that you put outside the block definitions can break your layout. This even includes HTML comments. For example:
<!-- Seemingly harmless HTML comment..that will break your layout at build -->
{{ define "main" }}
...your code here
{{ end }}
See this thread from the Hugo discussion forums.
{{% /warning %}}
The following shows how you can override both the "main"
and "title"
block areas from the base template with code unique to your default single page template:
{{< code file=“layouts/_default/single.html” download=“single.html” >}}
{{ define “title” }}
{{ .Title }} – {{ .Site.Title }}
{{ end }}
{{ define “main” }}
A list page template is a template used to render multiple pieces of content in a single HTML page. The exception to this rule is the homepage, which is still a list but has its own dedicated template.
Hugo uses the term list in its truest sense; i.e. a sequential arrangement of material, especially in alphabetical or numerical order. Hugo uses list templates on any output HTML page where content is traditionally listed:
The idea of a list page comes from the hierarchical mental model of the web and is best demonstrated visually:
Since section lists and taxonomy lists (N.B., not taxonomy terms lists) are both lists with regards to their templates, both have the same terminating default of _default/list.html
or themes/<THEME>/layouts/_default/list.html
in their lookup order. In addition, both section lists and taxonomy lists have their own default list templates in _default
:
layouts/_default/section.html
layouts/_default/list.html
layouts/_default/taxonomy.html
themes/<THEME>/layouts/_default/taxonomy.html
Since v0.18, everything in Hugo is a Page
. This means list pages and the homepage can have associated content files (i.e. _index.md
) that contain page metadata (i.e., front matter) and content.
This new model allows you to include list-specific front matter via .Params
and also means that list templates (e.g., layouts/_default/list.html
) have access to all page variables.
{{% note %}}
It is important to note that all _index.md
content files will render according to a list template and not according to a single page template.
{{% /note %}}
The following is an example of a typical Hugo project directory’s content:
.
...
├── content
| ├── post
| | ├── _index.md
| | ├── post-01.md
| | └── post-02.md
| └── quote
| | ├── quote-01.md
| | └── quote-02.md
...
Using the above example, let’s assume you have the following in content/post/_index.md
:
I decided to start learning Golang in March 2017.
Follow my journey through this new blog.
{{< /code >}}
You can now access this _index.md
’s’ content in your list template:
{{< code file=“layouts/_default/list.html” download=“list.html” >}}
{{ define “main” }}
This above will output the following HTML:
{{< code file=“example.com/post/index.html” copy=“false” >}}
I decided to start learning Golang in March 2017.
Follow my journey through this new blog.
_index.md
You do not have to create an _index.md
file for every list page (i.e. section, taxonomy, taxonomy terms, etc) or the homepage. If Hugo does not find an _index.md
within the respective content section when rendering a list template, the page will be created but with no {{.Content}}
and only the default values for .Title
etc.
Using this same layouts/_default/list.html
template and applying it to the the quotes
section above will render the following output. Note that quotes
does not have an _index.md
file to pull from:
{{< code file=“example.com/quote/index.html” copy=“false” >}}
{{% note %}}
The default behavior of Hugo is to pluralize list titles; hence the inflection of the quote
section to “Quotes” when called with the .Title
page variable. You can change this via the pluralizeListTitles
directive in your site configuration.
{{% /note %}}
This list template has been modified slightly from a template originally used in spf13.com. It makes use of partial templates for the chrome of the rendered page rather than using a base template The examples that follow also use the content view templates li.html
or summary.html
.
{{< code file=“layouts/section/post.html” >}}
{{ partial “header.html” . }}
{{ partial “subheader.html” . }}
{{< code file=“layouts/_default/taxonomies.html” download=“taxonomies.html” >}}
{{ define “main” }}
Hugo lists render the content based on metadata you provide in front matter. In addition to sane defaults, Hugo also ships with multiple methods to make quick work of ordering content inside list templates:
{{< code file=“layouts/partials/default-order.html” >}}
{{< code file=“layouts/partials/by-weight.html” >}}
{{< code file=“layouts/partials/by-date.html” >}}
{{< code file=“layouts/partials/by-publish-date.html” >}}
{{< code file=“layouts/partials/by-expiry-date.html” >}}
{{< code file=“layouts/partials/by-last-mod.html” >}}
{{< code file=“layouts/partials/by-length.html” >}}
{{< code file=“layouts/partials/by-title.html” >}}
{{< code file=“layouts/partials/by-link-title.html” >}}
Order based on the specified front matter parameter. Content that does not have the specified front matter field will use the site’s .Site.Params
default. If the parameter is not found at all in some entries, those entries will appear together at the end of the ordering.
{{< code file=“layouts/partials/by-rating.html” >}}
{{ range (.Data.Pages.ByParam “rating”) }}
{{ end }}
{{< /code >}}
If the targeted front matter field is nested beneath another field, you can access the field using dot notation.
{{< code file=“layouts/partials/by-nested-param.html” >}}
{{ range (.Data.Pages.ByParam “author.last_name”) }}
{{ end }}
{{< /code >}}
Reversing order can be applied to any of the above methods. The following uses ByDate
as an example:
{{< code file=“layouts/partials/by-date-reverse.html” >}}
Hugo provides some functions for grouping pages by Section, Type, Date, etc.
{{< code file=“layouts/partials/by-page-field.html” >}}
{{ range .Data.Pages.GroupBy “Section” }}
In the above example, you may want {{.Title}}
to point the title
field you have added to your _index.md
file instead. You can access this value using the .GetPage
function:
{{< code file=“layouts/partials/by-page-field.html” >}}
{{ range .Data.Pages.GroupBy “Section” }}
{{ with $.Site.GetPage “section” .Key }}
{{< code file=“layouts/partials/by-page-date.html” >}}
{{ range .Data.Pages.GroupByDate “2006-01” }}
{{< code file=“layouts/partials/by-page-publish-date.html” >}}
{{ range .Data.Pages.GroupByPublishDate “2006-01” }}
{{< code file=“layouts/partials/by-page-param.html” >}}
{{ range .Data.Pages.GroupByParam “param_key” }}
The following template takes grouping by date
a step further and uses Golang’s layout string. See the Format
function for more examples of how to use Golang’s layout string to format dates in Hugo.
{{< code file=“layouts/partials/by-page-param-as-date.html” >}}
{{ range .Data.Pages.GroupByParamDate “param_key” “2006-01” }}
Ordering of groups is performed by keys in alphanumeric order (A–Z, 1–100) and in reverse chronological order (i.e., with the newest first) for dates.
While these are logical defaults, they are not always the desired order. There are two different syntaxes to change Hugo’s default ordering for groups, both of which work the same way.
{{ range (.Data.Pages.GroupBy "Section").Reverse }}
{{ range (.Data.Pages.GroupByDate "2006-01").Reverse }}
{{ range .Data.Pages.GroupByDate "2006-01" "asc" }}
{{ range .Data.Pages.GroupBy "Section" "desc" }}
Because Grouping returns a {{.Key}}
and a slice of pages, all of the ordering methods listed above are available.
Here is the ordering for the example that follows:
date
field in front matter.title
.{{< code file=“layouts/partials/by-group-by-page.html” >}}
{{ range .Data.Pages.GroupByDate “2006-01” “asc” }}
Sometimes you only want to list a subset of the available content. A common is to only display “Posts” on blog’s homepage. You can accomplish this with the where
function.
where
where
works in a similar manner to the where
keyword in SQL. It selects all elements of the array or slice that match the provided field and value. where
takes three arguments:
array
or slice of maps or structs
key
or field name
match value
{{< code file=“layouts/_default/.html” >}}
{{ range where .Data.Pages “Section” “post” }}
{{ .Content }}
{{ end }}
{{< /code >}}
You can see more examples in the functions documentation for where
.
first
first
works in a similar manner to the limit
keyword in SQL. It reduces the array to only the first N
elements. It takes the array and number of elements as input. first
takes two arguments:
array
or slice of maps or structs
number of elements
{{< code file=“layout/_default/section.html” >}}
{{ range first 10 .Data.Pages }}
{{ .Render “summary” }}
{{ end }}
{{< /code >}}
first
and where
TogetherUsing first
and where
together can be very powerful:
{{< code file=“first-and-where-together.html” >}}
{{ range first 5 (where .Data.Pages “Section” “post”).ByTitle }}
{{ .Content }}
{{ end }}
{{< /code >}}
In Hugo, A list template is any template that will be used to render multiple pieces of content in a single HTML page.
This list template is used for spf13.com. It makes use of partial templates. All examples use a view called either “li” or “summary.”
{{< code file=“layouts/section/post.html” >}}
{{ partial “header.html” . }}
{{ partial “subheader.html” . }}
{{< code file=“layouts/_default/taxonomies.html” download=“taxonomies.html” >}}
{{ define “main” }}
Hugo lists render the content based on metadata provided in the front matter…
Here are a variety of different ways you can order the content items in
your list templates:
{{< code file=“layouts/partials/order-default.html” >}}
{{< code file=“layouts/partials/by-weight.html” >}}
{{ range .Data.Pages.ByWeight }}
{{< code file=“layouts/partials/by-date.html” >}}
{{ range .Data.Pages.ByDate }}
{{< code file=“layouts/partials/by-publish-date.html” >}}
{{ range .Data.Pages.ByPublishDate }}
{{< code file=“layouts/partials/by-expiry-date.html” >}}
{{ range .Data.Pages.ByExpiryDate }}
{{< code file=“layouts/partials/by-last-mod.html” >}}
{{ range .Data.Pages.ByLastmod }}
{{< code file=“layouts/partials/by-length.html” >}}
{{ range .Data.Pages.ByLength }}
{{< code file=“layouts/partials/by-title.html” >}}
{{ range .Data.Pages.ByTitle }}
{{< code file=“layouts/partials/by-link-title.html” >}}
{{ range .Data.Pages.ByLinkTitle }}
Order based on the specified front matter parameter. Content that does not have the specified front matter field will use the site’s .Site.Params
default. If the parameter is not found at all in some entries, those entries will appear together at the end of the ordering.
The below example sorts a list of posts by their rating.
{{< code file=“layouts/partials/by-rating.html” >}}
{{ range (.Data.Pages.ByParam “rating”) }}
{{ end }}
{{< /code >}}
If the front matter field of interest is nested beneath another field, you can
also get it:
{{< code file=“layouts/partials/by-nested-param.html” >}}
{{ range (.Data.Pages.ByParam “author.last_name”) }}
{{ end }}
{{< /code >}}
Reversing order can be applied to any of the above methods. The following uses ByDate
as an example:
{{< code file=“layouts/partials/by-date-reverse.html” >}}
{{ range .Data.Pages.ByDate.Reverse }}
Hugo provides some functions for grouping pages by Section, Type, Date, etc.
{{< code file=“layouts/partials/by-page-field.html” >}}
{{ range .Data.Pages.GroupBy “Section” }}
{{< code file=“layouts/partials/by-page-date.html” >}}
{{ range .Data.Pages.GroupByDate “2006-01” }}
{{< code file=“layouts/partials/by-page-publish-date.html” >}}
{{ range .Data.Pages.GroupByPublishDate “2006-01” }}
{{< code file=“layouts/partials/by-page-param.html” >}}
{{ range .Data.Pages.GroupByParam “param_key” }}
{{< code file=“layouts/partials/by-page-param-as-date.html” >}}
{{ range .Data.Pages.GroupByParamDate “param_key” “2006-01” }}
The ordering of the groups is performed by keys in alphanumeric order (A–Z, 1–100) and in reverse chronological order (newest first) for dates.
While these are logical defaults, they are not always the desired order. There are two different syntaxes to change the order, both of which work the same way. You can use your preferred syntax.
{{ range (.Data.Pages.GroupBy "Section").Reverse }}
{{ range (.Data.Pages.GroupByDate "2006-01").Reverse }}
{{ range .Data.Pages.GroupByDate "2006-01" "asc" }}
{{ range .Data.Pages.GroupBy "Section" "desc" }}
Because Grouping returns a {{.Key}}
and a slice of pages, all of the ordering methods listed above are available.
In the following example, groups are ordered chronologically and then content
within each group is ordered alphabetically by title.
{{< code file=“layouts/partials/by-group-by-page.html” >}}
{{ range .Data.Pages.GroupByDate “2006-01” “asc” }}
Sometimes you only want to list a subset of the available content. A common request is to only display “Posts” on the homepage. You can accomplish this with the where
function.
where
where
works in a similar manner to the where
keyword in SQL. It selects all elements of the array or slice that match the provided field and value. where
takes three arguments:
array
or a slice of maps or structs
key
or field name
match value
{{< code file=“layouts/_default/.html” >}}
{{ range where .Data.Pages “Section” “post” }}
{{ .Content }}
{{ end }}
{{< /code >}}
first
first
works in a similar manner to the limit
keyword in SQL. It reduces the array to only the first N
elements. It takes the array and number of elements as input. first
takes two arguments:
array
or slice of maps or structs
number of elements
{{< code file=“layout/_default/section.html” >}}
{{ range first 10 .Data.Pages }}
{{ .Render “summary” }}
{{ end }}
{{< /code >}}
first
and where
TogetherUsing first
and where
together can be very powerful:
{{< code file=“first-and-where-together.html” >}}
{{ range first 5 (where .Data.Pages “Section” “post”) }}
{{ .Content }}
{{ end }}
{{< /code >}}
Homepage is a Page
and therefore has all the page variables and site variables available for use.
{{% note “The Only Required Template” %}}
The homepage template is the only required template for building a site and therefore useful when bootstrapping a new site and template. It is also the only required template if you are developing a single-page website.
{{% /note %}}
The lookup order for the homepage template is as follows:
/layouts/index.html
/layouts/_default/list.html
/themes/<THEME>/layouts/index.html
/themes/<THEME>/layouts/_default/list.html
The homepage, similar to other list pages in Hugo, accepts content and front matter from an _index.md
file. This file should live at the root of your content
folder (i.e., content/_index.md
). You can then add body copy and metadata to your homepage the way you would any other content file.
See the homepage template below or Content Organization for more information on the role of _index.md
in adding content and front matter to list pages.
.Data.Pages
on the HomepageIn addition to the standard page variables, the homepage template has access to all site content via .Data.Pages
.
The following is an example of a homepage template that uses partial, base templates, and a content file at content/_index.md
to populate the {{.Title}}
and {{Content}}
page variables.
{{< code file=“layouts/index.html” download=“index.html” >}}
{{ define “main” }}
To effectively leverage section page templates, you should first understand Hugo’s content organization and, specifically, the purpose of _index.md
for adding content and front matter to section and other list pages.
The lookup order for section templates is as follows:
/layouts/section/<SECTION>.html
/layouts/<SECTION>/list.html
/layouts/_default/section.html
/layouts/_default/list.html
/themes/<THEME>/layouts/section/<SECTION>.html
/themes/<THEME>/layouts/<SECTION>/list.html
/themes/<THEME>/layouts/_default/section.html
/themes/<THEME>/layouts/_default/list.html
.Site.GetPage
with SectionsEvery Page
in Hugo has a .Kind
attribute. Kind
can easily be combined with the where
function in your templates to create kind-specific lists of content. This method is ideal for creating lists, but there are times where you may want to fetch just the index page of a single section via the section’s path.
The .GetPage
function looks up an index page of a given Kind
and path
.
{{% note %}}
.GetPage
is not currently supported to grab single content files but may be supported in the future.
{{% /note %}}
You can call .Site.GetPage
with two arguments: kind
and kind value
.
These are the valid values for ‘kind’:
home
section
taxonomy
taxonomyTerm
{{< code file=“layouts/_default/section.html” download=“section.html” >}}
{{ define “main” }}
.Site.GetPage
The .Site.GetPage
example that follows assumes the following project directory structure:
.
└── content
├── blog
│ ├── _index.md # "title: My Hugo Blog" in the front matter
│ ├── post-1.md
│ ├── post-2.md
│ └── post-3.md
└── events #Note there is no _index.md file in "events"
├── event-1.md
└── event-2.md
.Site.GetPage
will return nil
if no _index.md
page is found. Therefore, if content/blog/_index.md
does not exist, the template will output the section name:
<h1>{{ with .Site.GetPage "section" "blog" }}{{ .Title }}{{ end }}</h1>
Since blog
has a section index page with front matter at content/blog/_index.md
, the above code will return the following result:
<h1>My Hugo Blog</h1>
If we try the same code with the events
section, however, Hugo will default to the section title because there is no content/events/_index.md
from which to pull content and front matter:
<h1>{{ with .Site.GetPage "section" "events" }}{{ .Title }}{{ end }}</h1>
Which then returns the following:
<h1>Events</h1>
Hugo includes support for user-defined groupings of content called taxonomies. Taxonomies are classifications that demonstrate logical relationships between content. See Taxonomies under Content Management if you are unfamiliar with how Hugo leverages this powerful feature.
Hugo provides multiple ways to use taxonomies throughout your project templates:
Taxonomy list page templates are lists and therefore have all the variables and methods available to list pages.
A taxonomy will be rendered at /PLURAL
/TERM
/ (e.g., http://spf13.com/topics/golang/) according to the following lookup order:
/layouts/taxonomy/<SINGULAR>.html
/layouts/_default/taxonomy.html
/layouts/_default/list.html
/themes/<THEME>/layouts/taxonomy/<SINGULAR>.html
/themes/<THEME>/layouts/_default/taxonomy.html
/themes/<THEME>/layouts/_default/list.html
A taxonomy terms page will be rendered at example.com/<PLURALTAXONOMYNAME>
/ (e.g., http://spf13.com/topics/) according to the following lookup order:
/layouts/taxonomy/<SINGULAR>.terms.html
/layouts/_default/terms.html
/themes/<THEME>/layouts/taxonomy/<SINGULAR>.terms.html
/themes/<THEME>/layouts/_default/terms.html
{{% warning “The Taxonomy Terms Template has a Unique Lookup Order” %}}
If Hugo does not find a terms template in layout/
or /themes/<THEME>/layouts/
, Hugo will not render a taxonomy terms page.
{{% /warning %}}
Hugo makes a set of values and methods available on the various Taxonomy structures.
A Taxonomy is a mapstring
.
Since Maps are unordered, an OrderedTaxonomy is a special structure that has a defined order.
[]struct {
Name string
WeightedPages WeightedPages
}
Each element of the slice has:
WeightedPages is simply a slice of WeightedPage.
type WeightedPages []WeightedPage
Taxonomies can be ordered by either alphabetical key or by the number of content pieces assigned to that key.
<ul>
{{ $data := .Data }}
{{ range $key, $value := .Data.Taxonomy.Alphabetical }}
<li><a href="{{ $.Site.LanguagePrefix }}/{{ $data.Plural }}/{{ $value.Name | urlize }}"> {{ $value.Name }} </a> {{ $value.Count }} </li>
{{ end }}
</ul>
<ul>
{{ $data := .Data }}
{{ range $key, $value := .Data.Taxonomy.ByCount }}
<li><a href="{{ $.Site.LanguagePrefix }}/{{ $data.Plural }}/{{ $value.Name | urlize }}"> {{ $value.Name }} </a> {{ $value.Count }} </li>
{{ end }}
</ul>
Hugo uses both date
and weight
to order content within taxonomies.
Each piece of content in Hugo can optionally be assigned a date. It can also be assigned a weight for each taxonomy it is assigned to.
When iterating over content within taxonomies, the default sort is the same as that used for section and list pages first by weight then by date. This means that if the weights for two pieces of content are the same, than the more recent content will be displayed first. The default weight for any piece of content is 0.
Content can be assigned weight for each taxonomy that it’s assigned to.
+++
tags = [ "a", "b", "c" ]
tags_weight = 22
categories = ["d"]
title = "foo"
categories_weight = 44
+++
Front Matter with weighted tags and categories
The convention is taxonomyname_weight
.
In the above example, this piece of content has a weight of 22 which applies to the sorting when rendering the pages assigned to the “a”, “b” and “c” values of the ‘tag’ taxonomy.
It has also been assigned the weight of 44 when rendering the ‘d’ category.
With this the same piece of content can appear in different positions in different taxonomies.
Currently taxonomies only support the default ordering of content which is weight -> date.
There are two different templates that the use of taxonomies will require you to provide.
Both templates are covered in detail in the templates section.
A list template is any template that will be used to render multiple pieces of content in a single html page. This template will be used to generate all the automatically created taxonomy pages.
A taxonomy terms template is a template used to
generate the list of terms for a given template.
There are four common ways you can display the data in your
taxonomies in addition to the automatic taxonomy pages created by hugo
using the list templates:
Within your content templates, you may wish to display the taxonomies that piece of content is assigned to.
Because we are leveraging the front matter system to define taxonomies for content, the taxonomies assigned to each content piece are located in the usual place (i.e., .Params.<TAXONOMYPLURAL>
).
<ul id="tags">
{{ range .Params.tags }}
<li><a href="{{ "/tags/" | relLangURL }}{{ . | urlize }}">{{ . }}</a> </li>
{{ end }}
</ul>
If you want to list taxonomies inline, you will have to take care of optional plural endings in the title (if multiple taxonomies), as well as commas. Let’s say we have a taxonomy “directors” such as directors: "JoelCoen","EthanCoen"
in the TOML-format front matter.
To list such taxonomies, use the following:
{{ if .Params.directors }}
<strong>Director{{ if gt (len .Params.directors) 1 }}s{{ end }}:</strong>
{{ range $index, $director := .Params.directors }}{{ if gt $index 0 }}, {{ end }}<a href="{{ "directors/" | relURL }}{{ . | urlize }}">{{ . }}</a>{{ end }}
{{ end }}
Alternatively, you may use the delimit template function as a shortcut if the taxonomies should just be listed with a separator. See {{< gh 2143 >}} on GitHub for discussion.
If you are using a taxonomy for something like a series of posts, you can list individual pages associated with the same taxonomy. This is also a quick and dirty method for showing related content:
<ul>
{{ range .Site.Taxonomies.series.golang }}
<li><a href="{{ .Page.RelPermalink }}">{{ .Page.Title }}</a></li>
{{ end }}
</ul>
This would be very useful in a sidebar as “featured content”. You could even have different sections of “featured content” by assigning different terms to the content.
<section id="menu">
<ul>
{{ range $key, $taxonomy := .Site.Taxonomies.featured }}
<li> {{ $key }} </li>
<ul>
{{ range $taxonomy.Pages }}
<li hugo-nav="{{ .RelPermalink}}"><a href="{{ .Permalink}}"> {{ .LinkTitle }} </a> </li>
{{ end }}
</ul>
{{ end }}
</ul>
</section>
If you wish to display the list of all keys for your site’s taxonomy, you can retrieve them from the .Site
variable available on every page.
This may take the form of a tag cloud, a menu, or simply a list.
The following example displays all terms in a site’s tags taxonomy:
<ul id="all-tags">
{{ range $name, $taxonomy := .Site.Taxonomies.tags }}
<li><a href="{{ "/tags/" | relLangURL }}{{ $name | urlize }}">{{ $name }}</a></li>
{{ end }}
</ul>
This example will list all taxonomies and their terms, as well as all the content assigned to each of the terms.
{{< code file=“layouts/partials/all-taxonomies.html” download=“all-taxonomies.html” download=“all-taxonomies.html” >}}
.Site.GetPage
for TaxonomiesBecause taxonomies are lists, the .GetPage
function can be used to get all the pages associated with a particular taxonomy term using a terse syntax. The following ranges over the full list of tags on your site and links to each of the individual taxonomy pages for each term without having to use the more fragile URL construction of the “List All Site Tags” example above:
{{< code file=“links-to-all-tags” >}}
{{< /code >}}You can specify a content’s type
and layout
in a single content file’s front matter. However, you cannot specify section
because this is determined based on file location (see content section).
Hugo assumes your content section and content type are the same unless you tell Hugo otherwise by providing a type
directly in the front matter of a content file. This is why #1 and #3 come before #2 and #4, respectively, in the following lookup order. Values in angle brackets (<>
) are variable.
/layouts/<TYPE>/<LAYOUT>.html
/layouts/<SECTION>>/<LAYOUT>.html
/layouts/<TYPE>/single.html
/layouts/<SECTION>/single.html
/layouts/_default/single.html
/themes/<THEME>/layouts/<TYPE>/<LAYOUT>.html
/themes/<THEME>/layouts/<SECTION>/<LAYOUT>.html
/themes/<THEME>/layouts/<TYPE>/single.html
/themes/<THEME>/layouts/<SECTION>/single.html
/themes/<THEME>/layouts/_default/single.html
Content pages are of the type page
and will therefore have all the page variables and site variables available to use in their templates.
post/single.html
This single page template makes use of Hugo base templates, the .Format
function for dates, the .WordCount
page variable, and ranges through the single content’s specific taxonomies. [with
]
{{< code file=“layouts/post/single.html” download=“single.html” >}}
{{ define “main” }}
To easily generate new instances of a content type (e.g., new .md
files in a section like project/
) with preconfigured front matter, use content archetypes.
These alternative content views are especially useful in list templates.
The following are common use cases for content views:
To create a new view, create a template in each of your different content type directories with the view name. The following example contains an “li” view and a “summary” view for the post
and project
content types. As you can see, these sit next to the single content view template, single.html. You can even provide a specific view for a given type and continue to use the
_default/single.html` for the primary view.
▾ layouts/
▾ post/
li.html
single.html
summary.html
▾ project/
li.html
single.html
summary.html
Hugo also has support for a default content template to be used in the event that a specific content view template has not been provided for that type. Content views can also be defined in the _default
directory and will work the same as list and single templates who eventually trickle down to the _default
directory as a matter of the lookup order.
▾ layouts/
▾ _default/
li.html
single.html
summary.html
The following is the lookup order for content views:
/layouts/<TYPE>/<VIEW>.html
/layouts/_default/<VIEW>.html
/themes/<THEME>/layouts/<TYPE>/<VIEW>.html
/themes/<THEME>/layouts/_default/<VIEW>.html
The following example demonstrates how to use content views inside of your list templates.
list.html
In this example, .Render
is passed into the template to call the render function. .Render
is a special function that instructs content to render itself with the view template provided as the first argument. In this case, the template is going to render the summary.html
view that follows:
{{< code file=“layouts/_default/list.html” download=“list.html” >}}
summary.html
Hugo will pass the entire page object to the following summary.html
view template. (See Page Variables for a complete list.)
{{< code file=“layouts/_default/summary.html” download=“summary.html” >}}
li.html
Continuing on the previous example, we can change our render function to use a smaller li.html
view by changing the argument in the call to the .Render
function (i.e., {{ .Render "li" }}
).
{{< code file=“layouts/_default/li.html” download=“li.html” >}}
taxonomylists
Hugo supports loading data from YAML, JSON, and TOML files located in the data
directory in the root of your Hugo project.
The data
folder is where you can store additional data for Hugo to use when generating your site. Data files aren’t used to generate standalone pages; rather, they’re meant to be supplemental to content files. This feature can extend the content in case your front matter fields grow out of control. Or perhaps you want to show a larger dataset in a template (see example below). In both cases, it’s a good idea to outsource the data in their own files.
These files must be YAML, JSON, or TOML files (using the .yml
, .yaml
, .json
, or .toml
extension). The data will be accessible as a map
in the .Site.Data
variable.
Data Files can also be used in Hugo themes but note that theme data files follow the same logic as other template files in the Hugo lookup order (i.e., given two files with the same name and relative path, the file in the root project data
directory will override the file in the themes/<THEME>/data
directory).
Therefore, theme authors should take care to not include data files that could be easily overwritten by a user who decides to customize a theme. For theme-specific data items that shouldn’t be overridden, it can be wise to prefix the folder structure with a namespace; e.g. mytheme/data/<THEME>/somekey/...
. To check if any such duplicate exists, run hugo with the -v
flag.
The keys in the map created with data templates from data files will be a dot-chained set of path
, filename
, and key
in file (if applicable).
This is best explained with an example:
Jaco Pastorius was a great bass player, but his solo discography is short enough to use as an example. John Patitucci is another bass giant.
The example below is a bit contrived, but it illustrates the flexibility of data Files. This example uses TOML as its file format with the two following data files:
data/jazz/bass/jacopastorius.toml
data/jazz/bass/johnpatitucci.toml
jacopastorius.toml
contains the content below. johnpatitucci.toml
contains a similar list:
discography = [
"1974 – Modern American Music … Period! The Criteria Sessions",
"1974 – Jaco",
"1976 - Jaco Pastorius",
"1981 - Word of Mouth",
"1981 - The Birthday Concert (released in 1995)",
"1982 - Twins I & II (released in 1999)",
"1983 - Invitation",
"1986 - Broadway Blues (released in 1998)",
"1986 - Honestly Solo Live (released in 1990)",
"1986 - Live In Italy (released in 1991)",
"1986 - Heavy'n Jazz (released in 1992)",
"1991 - Live In New York City, Volumes 1-7.",
"1999 - Rare Collection (compilation)",
"2003 - Punk Jazz: The Jaco Pastorius Anthology (compilation)",
"2007 - The Essential Jaco Pastorius (compilation)"
]
The list of bass players can be accessed via .Site.Data.jazz.bass
, a single bass player by adding the filename without the suffix, e.g. .Site.Data.jazz.bass.jacopastorius
.
You can now render the list of recordings for all the bass players in a template:
{{ range $.Site.Data.jazz.bass }}
{{ partial "artist.html" . }}
{{ end }}
And then in the partial/artist.html
:
<ul>
{{ range .discography }}
<li>{{ . }}</li>
{{ end }}
</ul>
Discover a new favorite bass player? Just add another .toml
file in the same directory.
Assume you have the following YAML structure in your User0123.yml
data file located directly in data/
:
Name: User0123
"Short Description": "He is a **jolly good** fellow."
Achievements:
- "Can create a Key, Value list from Data File"
- "Learns Hugo"
- "Reads documentation"
You can use the following code to render the Short Description
in your layout::
<div>Short Description of {{.Site.Data.User0123.Name}}: <p>{{ index .Site.Data.User0123 "Short Description" | markdownify }}</p></div>
Note the use of the markdownify
template function. This will send the description through the Blackfriday Markdown rendering engine.
In addition to the data files feature, Hugo also a “data-driven content” feature, which lets you load any JSON or CSV file from nearly any resource.
Data-driven content currently consists of two functions, getJSON
and getCSV
, which are available in all template files.
In your template, call the functions like this:
{{ $dataJ := getJSON "url" }}
{{ $dataC := getCSV "separator" "url" }}
If you use a prefix or postfix for the URL, the functions accept variadic arguments:
{{ $dataJ := getJSON "url prefix" "arg1" "arg2" "arg n" }}
{{ $dataC := getCSV "separator" "url prefix" "arg1" "arg2" "arg n" }}
The separator for getCSV
must be put in the first position and can only be one character long.
All passed arguments will be joined to the final URL:
{{ $urlPre := "https://api.github.com" }}
{{ $gistJ := getJSON $urlPre "/users/GITHUB_USERNAME/gists" }}
This will resolve internally to the following:
{{ $gistJ := getJSON "https://api.github.com/users/GITHUB_USERNAME/gists" }}
Finally, you can range over an array. This example will output the
first 5 gists for a GitHub user:
<ul>
{{ $urlPre := "https://api.github.com" }}
{{ $gistJ := getJSON $urlPre "/users/GITHUB_USERNAME/gists" }}
{{ range first 5 $gistJ }}
{{ if .public }}
<li><a href="{{ .html_url }}" target="_blank">{{ .description }}</a></li>
{{ end }}
{{ end }}
</ul>
For getCSV
, the one-character-long separator must be placed in the first position followed by the URL. The following is an example of creating an HTML table in a partial template from a published CSV:
{{< code file=“layouts/partials/get-csv.html” >}}
{{ url := "http://a-big-corp.com/finance/employee-salaries.csv" }}Name | Position | Salary |
---|---|---|
{{ index $r 0 }} | {{ index $r 1 }} | {{ index $r 2 }} |
The expression {{index $r number}}
must be used to output the nth-column from the current row.
Each downloaded URL will be cached in the default folder $TMPDIR/hugo_cache/
. The variable $TMPDIR
will be resolved to your system-dependent temporary directory.
With the command-line flag --cacheDir
, you can specify any folder on your system as a caching directory.
You can also set cacheDir
in the main configuration file.
If you don’t like caching at all, you can fully disable caching with the command line flag --ignoreCache
.
Currently, you can only use those authentication methods that can be put into an URL. OAuth and other authentication methods are not implemented.
To load local files with getJSON
and getCSV
, the source files must reside within Hugo’s working directory. The file extension does not matter, but the content does.
It applies the same output logic as above in Calling the Functions with a URL.
There is no chance to trigger a LiveReload when the content of a URL changes. However, when a local file changes (i.e., data/*
and themes/<THEME>/data/*
), a LiveReload will be triggered. Symlinks are not supported. Note too that because downloading of data takes a while, Hugo stops processing your Markdown files until the data download has completed.
{{% warning “URL Data and LiveReload” %}}
If you change any local file and the LiveReload is triggered, Hugo will read the data-driven (URL) content from the cache. If you have disabled the cache (i.e., by running the server with hugo server --ignoreCache
), Hugo will re-download the content every time LiveReload triggers. This can create huge traffic. You may reach API limits quickly.
{{% /warning %}}
Partial templates—like single page templates and list page templates—have a specific lookup order. However, partials are simpler in that Hugo will only check in two places:
layouts/partials/*<PARTIALNAME>.html
themes/<THEME>/layouts/partials/*<PARTIALNAME>.html
This allows a theme’s end user to copy a partial’s contents into a file of the same name for further customization.
All partials for your Hugo project are located in a single layouts/partials
directory. For better organization, you can create multiple subdirectories within partials
as well:
.
└── layouts
└── partials
├── footer
│ ├── scripts.html
│ └── site-footer.html
├── head
│ ├── favicons.html
│ ├── metadata.html
│ ├── prerender.html
│ └── twitter.html
└── header
├── site-header.html
└── site-nav.html
All partials are called within your templates using the following pattern:
{{ partial "<PATH>/<PARTIAL>.html" . }}
{{% note %}}
One of the most common mistakes with new Hugo users is failing to pass a context to the partial call. In the pattern above, note how “the dot” (.
) is required as the second argument to give the partial context. You can read more about “the dot” in the Hugo templating introduction.
{{% /note %}}
As shown in the above example directory structure, you can nest your directories within partials
for better source organization. You only need to call the nested partial’s path relative to the partials
directory:
{{ partial "header/site-header.html" . }}
{{ partial "footer/scripts.html" . }}
{{% note %}}
Before v0.12, Hugo used the template
call to include partial templates. When using Hugo v0.12 and newer, be sure to use the {{ partial "<PATH>/<PARTIAL>.html" . }}
syntax. The old approach will still work but has fewer benefits.
{{% /note %}}
The second argument in a partial call is the variable being passed down. The above examples are passing the .
, which tells the template receiving the partial to apply the current context.
This means the partial will only be able to access those variables. The partial is isolated and has no access to the outer scope. From within the partial, $.Var
is equivalent to .Var
.
The partialCached
template function can offer significant performance gains for complex templates that don’t need to be re-rendered on every invocation. The simplest usage is as follows:
{{ partialCached "footer.html" . }}
You can also pass additional parameters to partialCached
to create variants of the cached partial.
For example, you can tell Hugo to only render the partial footer.html
once per section:
{{ partialCached "footer.html" . .Section }}
If you need to pass additional parameters to create unique variants, you can pass as many variant parameters as you need:
{{ partialCached "footer.html" . .Params.country .Params.province }}
Note that the variant parameters are not made available to the underlying partial template. They are only use to create a unique cache key.
header.html
The following header.html
partial template is used for spf13.com:
{{< code file=“layouts/partials/header.html” download=“header.html” >}}
{{ partial "meta.html" . }}
<base href="{{ .Site.BaseURL }}">
<title> {{ .Title }} : spf13.com </title>
<link rel="canonical" href="{{ .Permalink }}">
{{ if .RSSLink }}<link href="{{ .RSSLink }}" rel="alternate" type="application/rss+xml" title="{{ .Title }}" />{{ end }}
{{ partial "head_includes.html" . }}
{{< /code >}}
{{% note %}}
The header.html
example partial was built before the introduction of block templates to Hugo. Read more on base templates and blocks for defining the outer chrome or shell of your master templates (i.e., your site’s head, header, and footer). You can even combine blocks and partials for added flexibility.
{{% /note %}}
footer.html
The following footer.html
partial template is used for spf13.com:
{{< code file=“layouts/partials/footer.html” download=“footer.html” >}}
{{< /code >}}themes: /themes/
Shortcodes are a means to consolidate templating into small, reusable snippets that you can embed directly inside of your content. In this sense, you can think of shortcodes as the intermediary between page and list templates and basic content files.
{{% note %}}
Hugo also ships with built-in shortcodes for common use cases. (See Content Management: Shortcodes.)
{{% /note %}}
Hugo’s built-in shortcodes cover many common, but not all, use cases. Luckily, Hugo provides the ability to easily create custom shortcodes to meet your website’s needs.
To create a shortcode, place an HTML template in the layouts/shortcodes
directory of your source organization. Consider the file name carefully since the shortcode name will mirror that of the file but without the .html
extension. For example, layouts/shortcodes/myshortcode.html
will be called with either {{</* myshortcode /*/>}}
or {{%/* myshortcode /*/%}}
depending on the type of parameters you choose.
Shortcode templates have a simple lookup order:
/layouts/shortcodes/<SHORTCODE>.html
/themes/<THEME>/layouts/shortcodes/<SHORTCODE>.html
You can create shortcodes using the following types of parameters:
In shortcodes with positional parameters, the order of the parameters is important. If a shortcode has a single required value (e.g., the youtube
shortcode below), positional parameters work very well and require less typing from content authors.
For more complex layouts with multiple or optional parameters, named parameters work best. While less terse, named parameters require less memorization from a content author and can be added in a shortcode declaration in any order.
Allowing both types of parameters (i.e., a “flexible” shortcode) is useful for complex layouts where you want to set default values that can be easily overridden by users.
All shortcode parameters can be accessed via the .Get
method. Whether you pass a key (i.e., string) or a number to the .Get
method depends on whether you are accessing a named or positional parameter, respectively.
To access a parameter by name, use the .Get
method followed by the named parameter as a quoted string:
{{ .Get "class" }}
To access a parameter by position, use the .Get
followed by a numeric position, keeping in mind that positional parameters are zero-indexed:
{{ .Get 0 }}
with
is great when the output depends on a parameter being set:
{{ with .Get "class"}} class="{{.}}"{{ end }}
.Get
can also be used to check if a parameter has been provided. This is
most helpful when the condition depends on either of the values, or both:
{{ or .Get "title" | .Get "alt" | if }} alt="{{ with .Get "alt"}}{{.}}{{else}}{{.Get "title"}}{{end}}"{{ end }}
.Inner
If a closing shortcode is used, the .Inner
variable will be populated with all of the content between the opening and closing shortcodes. If a closing shortcode is required, you can check the length of .Inner
as an indicator of its existence.
A shortcode with content declared via the .Inner
variable can also be declared without the inline content and without the closing shortcode by using the self-closing syntax:
{{</* innershortcode /*/>}}
.Params
The .Params
variable in shortcodes contains the list parameters passed to shortcode for more complicated use cases. You can also access higher-scoped parameters with the following logic:
$.Params
$.Page.Params
shortcode_color
field in a content’s front matter could be accessed via $.Page.Params.shortcode_color
).$.Page.Site.Params
.IsNameParams
The .IsNamedParams
variable checks whether the shortcode declaration uses named parameters and returns a boolean value.
For example, you could create an image
shortcode that can take either a src
named parameter or the first positional parameter, depending on the preference of the content’s author. Let’s assume the image
shortcode is called as follows:
{{</* image src="images/my-image.jpg"*/>}}
You could then include the following as part of your shortcode templating:
{{ if .IsNamedParams }}
<img src="{{.Get "src" alt="">
{{ else }}
<img src="{{.Get 0}}" alt="">
{{ end }}.
See the example Vimeo shortcode below for .IsNamedParams
in action.
{{% warning %}}
While you can create shortcode templates that accept both positional and named parameters, you cannot declare shortcodes in content with a mix of parameter types. Therefore, a shortcode declared like {{</* image src="images/my-image.jpg" "This is my alt text" */>}}
will return an error.
{{% /warning %}}
You can also use the variable .Page
to access all the normal page variables.
A shortcodes can also be nested. In a nested shortcode, you can access the parent shortcode context with .Parent
variable. This can be very useful for inheritance of common shortcode parameters from the root.
The following are examples of the different types of shortcodes you can create via shortcode template files in /layouts/shortcodes
.
year
Let’s assume you would like to keep mentions of your copyright year current in your content files without having to continually review your markdown. Your goal is to be able to call the shortcode as follows:
{{</* year */>}}
{{< code file=“/layouts/shortcodes/year.html” >}}
{{ .Page.Now.Year }}
{{< /code >}}
youtube
Embedded videos are a common addition to markdown content that can quickly become unsightly. The following is the code used by Hugo′sbuilt−inYouTubeshortcode
{{</* youtube 09jf3ow9jfw */>}}
Would load the template at /layouts/shortcodes/youtube.html
:
{{< code file=“/layouts/shortcodes/youtube.html” >}}
{{< /code >}}{{< code file=“youtube-embed.html” copy=“false” >}}
{{< /code >}}image
Let’s say you want to create your own img
shortcode rather than use Hugo’s built-in figure
shortcode. Your goal is to be able to call the shortcode as follows in your content files:
{{< code file=“content-image.md” >}}
{{</* img src=“/media/spf13.jpg” title=“Steve Francia” */>}}
{{< /code >}}
You have created the shortcode at /layouts/shortcodes/img.html
, which loads the following shortcode template:
{{< code file=“/layouts/shortcodes/img.html” >}}
{{ .Get "caption" }} {{ with .Get "attrlink"}} {{ end }} {{ .Get "attr" }} {{ if .Get "attrlink"}} {{ end }}
{{ end }}Would be rendered as:
{{< code file=“img-output.html” copy=“false” >}}
vimeo
{{</* vimeo 49718712 */>}}
{{</* vimeo id="49718712" class="flex-video" */>}}
Would load the template found at /layouts/shortcodes/vimeo.html
:
{{< code file=“/layouts/shortcodes/vimeo.html” >}}
{{ if .IsNamedParams }}
Would be rendered as:
{{< code file=“vimeo-iframes.html” copy=“false” >}}
highlight
The following is taken from highlight
, which is a built-in shortcode that ships with Hugo.
{{< code file=“highlight-example.md” >}}
{{</* highlight html */>}}
The template for the highlight
shortcode uses the following code, which is already included in Hugo:
{{ .Get 0 | highlight .Inner }}
The rendered output of the HTML example code block will be as follows:
{{< code file=“syntax-highlighted.html” copy=“false” >}}
<html>
<body> This HTML </body>
</html>
{{% note %}}
The preceding shortcode makes use of a Hugo-specific template function called highlight
, which uses Pygments to add syntax highlighting to the example HTML code block. See the developer tools page on syntax highlighting for more information.
{{% /note %}}
Hugo’s .Parent
shortcode variable returns a boolean value depending on whether the shortcode in question is called within the context of a parent shortcode. This provides an inheritance model for common shortcode parameters.
The following example is contrived but demonstrates the concept. Assume you have a gallery
shortcode that expects one named class
parameter:
{{< code file=“layouts/shortcodes/gallery.html” >}}
You also have an image
shortcode with a single named src
parameter that you want to call inside of gallery
and other shortcodes so that the parent defines the context of each image
:
{{< code file=“layouts/shortcodes/image.html” >}}
{{- src := .Get “src” -}}
{{- with .Parent -}}
<img src=“{{src}}” class=“{{.Get “class”}}-image”>
{{- else -}}
{{- end }}
{{< /code >}}
You can then call your shortcode in your content as follows:
{{</* gallery class="content-gallery" */>}}
{{</* img src="/images/one.jpg" */>}}
{{</* img src="/images/two.jpg" */>}}
{{</* /gallery */>}}
{{</* img src="/images/three.jpg" */>}}
This will output the following HTML. Note how the first two image
shortcodes inherit the class
value of content-gallery
set with the call to the parent gallery
, whereas the third image
only uses src
:
<div class="content-gallery">
<img src="/images/one.jpg" class="content-gallery-image">
<img src="/images/two.jpg" class="content-gallery-image">
</div>
<img src="/images/three.jpg">
More shortcode examples can be found in the shortcodes directory for spf13.com and the shortcodes directory for the Hugo docs.
youtubeshortcode
With Hugo’s readDir
and readFile
template functions, you can traverse your website’s files on your server.
readDir
The readDir
function returns an array of os.FileInfo
. It takes the file’s path
as a single string argument. This path can be to any directory of your website (i.e., as found on your server’s file system).
Whether the path is absolute or relative does not matter because—at least for readDir
—the root of your website (typically ./public/
) in effect becomes both:
readDir
Example: List Directory FilesThis shortcode creates a link to each of the files in a directory—display as the file’s basename—along with the file’s size in bytes.
{{< code file=“layouts/shortcodes/directoryindex.html” download=“directoryindex.html” >}}
{{< readfile file=“/themes/gohugoioTheme/layouts/shortcodes/directoryindex.html” >}}
{{< /code >}}
You can then call the shortcode as follows inside of your content’s markup:
{{</* directoryindex path="/static/css" pathURL="/css" */>}}
The above shortcode is part of the code for the Hugo docs. Here it lists this site’s CSS files:
{{< directoryindex path=“/themes/gohugoioTheme/static/dist” pathURL=“/css” >}}
{{% note “Slashes are Important” %}}
The initial slash /
in pathURL
is important in the directoryindex
shortcode. Otherwise, pathURL
becomes relative to the current web page.
{{% /note %}}
readFile
The readfile
function reads a file from disk and converts it into a string to be manipulated by other Hugo functions or added as-is. readFile
takes the file, including path, as an argument passed to the function.
To use the readFile
function in your templates, make sure the path is relative to your Hugo project’s root directory:
{{ readFile "/content/templates/local-file-templates" }}
readFile
Example: Add a Project File to ContentAs readFile
is a function, it is only available to you in your templates and not your content. However, we can create a simple shortcode template that calls readFile
, passes the first argument through the function, and then allows an optional second argument to send the file through the Blackfriday markdown processor. The pattern for adding this shortcode to your content will be as follows:
{{</* readfile file="/path/to/local/file.txt" markdown="true" */>}}
{{% warning %}}
If you are going to create custom shortcodes with readFile
for a theme, note that usage of the shortcode will refer to the project root and not your themes
directory.
{{% /warning %}}
Here is the templating for our new readfile
shortcode:
{{< code file=“layouts/shortcodes/readfile.html” download=“readfile.html” >}}
{{< readfile file=“/themes/gohugoioTheme/layouts/shortcodes/readfile.html”>}}
{{< /code >}}
This readfile
shortcode is also part of the Hugo docs. So is testing.txt
, which we will call in this example by passing it into our new readfile
shortcode as follows:
{{</* readfile file="/content/readfiles/testing.txt" */>}}
The output “string” for this shortcode declaration will be the following:
{{< readfile file="/content/readfiles/testing.txt" >}}
However, if we want Hugo to pass this string through Blackfriday, we should add the markdown="true"
optional parameter:
{{</* readfile file="/content/readfiles/testing.txt" markdown="true" */>}}
And here is the result as called directly in the Hugo docs and rendered for display:
{{< readfile file=“/content/readfiles/testing.txt” markdown=“true”>}}
When using Hugo with GitHub Pages, you can provide your own template for a custom 404 error page by creating a 404.html template file in your /layouts
folder. When Hugo generates your site, the 404.html
file will be placed in the root.
404 pages will have all the regular page variables available to use in the templates.
In addition to the standard page variables, the 404 page has access to all site content accessible from .Data.Pages
.
▾ layouts/
404.html
This is a basic example of a 404.html template:
{{< code file=“layouts/404.html” download=“404.html” >}}
{{ define “main”}}
Your 404.html file can be set to load automatically when a visitor enters a mistaken URL path, dependent upon the web serving environment you are using. For example:
ErrorDocument 404 /404.html
in an .htaccess
file in the root of your site.error_page 404 /404.html;
in your nginx.conf
file.errors { 404 /404.html }
. Details herepagevars: /variables/page/
Hugo makes no assumptions about how your rendered HTML will be
structured. Instead, it provides all of the functions you will need to be
able to build your menu however you want.
The following is an example:
{{< code file=“layouts/partials/sidebar.html” download=“sidebar.html” >}}
{{< /code >}}{{% note “absLangURL
and relLangURL
” %}}
Use the absLangUrl
or relLangUrl
functions if your theme makes use of the multilingual feature. In contrast to absURL
and relURL
, these two functions add the correct language prefix to the url.
{{% /note %}}
To enable this menu, configure sectionPagesMenu
in your site config
:
sectionPagesMenu = "main"
The menu name can be anything, but take a note of what it is.
This will create a menu with all the sections as menu items and all the sections’ pages as “shadow-members”. The shadow implies that the pages isn’t represented by a menu-item themselves, but this enables you to create a top-level menu like this:
<nav class="sidebar-nav">
{{ $currentPage := . }}
{{ range .Site.Menus.main }}
<a class="sidebar-nav-item{{if or ($currentPage.IsMenuCurrent "main" .) ($currentPage.HasMenuCurrent "main" .) }} active{{end}}" href="{{.URL}}">{{ .Name }}</a>
{{ end }}
</nav>
In the above, the menu item is marked as active if on the current section’s list page or on a page in that section.
The above is all that’s needed. But if you want custom menu items, e.g. changing weight or name, you can define them manually in the site config, i.e. config.toml
:
[[menu.main]]
name = "This is the blog section"
weight = -110
identifier = "blog"
url = "/blog/"
{{% note %}}
The identifier
must match the section name.
{{% /note %}}
The real power of Hugo pagination shines when combined with the where
function and its SQL-like operators: first
, last
, and after
. You can even order the content the way you’ve become used to with Hugo.
Pagination can be configured in your site configuration:
Paginate
10
. This setting can be overridden within the template.PaginatePath
page
. Allows you to set a different path for your pagination pages.Setting Paginate
to a positive value will split the list pages for the homepage, sections and taxonomies into chunks of that size. But note that the generation of the pagination pages for sections, taxonomies and homepage is lazy — the pages will not be created if not referenced by a .Paginator
(see below).
PaginatePath
is used to adapt the URL
to the pages in the paginator (the default setting will produce URLs on the form /page/1/
.
{{% warning %}}
.Paginator
is provided to help you build a pager menu. This feature is currently only supported on homepage and list pages (i.e., taxonomies and section lists).
{{% /warning %}}
There are two ways to configure and use a .Paginator
:
.Paginator.Pages
from a template. It will contain the pages for that page..Paginate
, e.g. {{ range (.Paginate ( first 50 .Data.Pages.ByTitle )).Pages }}
.For a given Page, it’s one of the options above. The .Paginator
is static and cannot change once created.
The global page size setting (Paginate
) can be overridden by providing a positive integer as the last argument. The examples below will give five items per page:
{{ range (.Paginator 5).Pages }}
{{ $paginator := .Paginate (where .Data.Pages "Type" "post") 5 }}
It is also possible to use the GroupBy
functions in combination with pagination:
{{ range (.Paginate (.Data.Pages.GroupByDate "2006")).PageGroups }}
The .Paginator
contains enough information to build a paginator interface.
The easiest way to add this to your pages is to include the built-in template (with Bootstrap
-compatible styles):
{{ template "_internal/pagination.html" . }}
{{% note “When to Create .Paginator
” %}}
If you use any filters or ordering functions to create your .Paginator
and you want the navigation buttons to be shown before the page listing, you must create the .Paginator
before it’s used.
{{% /note %}}
The following example shows how to create .Paginator
before its used:
{{ $paginator := .Paginate (where .Data.Pages "Type" "post") }}
{{ template "_internal/pagination.html" . }}
{{ range $paginator.Pages }}
{{ .Title }}
{{ end }}
Without the where
filter, the above example is even simpler:
{{ template "_internal/pagination.html" . }}
{{ range .Paginator.Pages }}
{{ .Title }}
{{ end }}
If you want to build custom navigation, you can do so using the .Paginator
object, which includes the following properties:
PageNumber
URL
:
The relative URL to the current pager
Pages
:
The pages in the current pager
NumberOfElements
HasPrev
Prev
HasNext
Next
First
Last
Pagers
PageSize
TotalPages
TotalNumberOfElements
The pages are built on the following form (BLANK
means no value):
[SECTION/TAXONOMY/BLANK]/index.html
[SECTION/TAXONOMY/BLANK]/page/1/index.html => redirect to [SECTION/TAXONOMY/BLANK]/index.html
[SECTION/TAXONOMY/BLANK]/page/2/index.html
....
where: /functions/where/
You can use a single RSS template to generate all of your RSS feeds or create a specific template for each individual feed.
/layouts/section/<section>.rss.xml
/layouts/_default/rss.xml
/themes/<theme>/layouts/section/<section>.rss.xml
/themes/<theme>/layouts/_default/rss.xml
{{% note “Hugo Ships with an RSS Template” %}}
Hugo ships with its own RSS 2.0 template. The embedded template will be sufficient for most use cases.
{{% /note %}}
RSS pages are of the type Page
and have all the page variables available to use in the templates.
A section’s RSS will be rendered at /<SECTION>/index.xml
(e.g., http://spf13.com/project/index.xml).
Hugo provides the ability for you to define any RSS type you wish and can have different RSS files for each section and taxonomy.
/layouts/rss.xml
/layouts/_default/rss.xml
/layouts/section/<SECTION>.rss.xml
/layouts/_default/rss.xml
/themes/<THEME>/layouts/section/<SECTION>.rss.xml
/themes/<THEME>/layouts/_default/rss.xml
/layouts/taxonomy/<SINGULAR>.rss.xml
/layouts/_default/rss.xml
/themes/<THEME>/layouts/taxonomy/<SINGULAR>.rss.xml
/themes/<THEME>/layouts/_default/rss.xml
By default, Hugo will create an unlimited number of RSS entries. You can limit the number of articles included in the built-in RSS templates by assigning a numeric value to rssLimit:
field in your project’s config
file.
The following values will also be included in the RSS output if specified in your site’s configuration:
languageCode = "en-us"
copyright = "This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License."
[author]
name = "My Name Here"
This is the default RSS template that ships with Hugo. It adheres to the RSS 2.0 Specification.
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>{{ with .Title }}{{.}} on {{ end }}{{ .Site.Title }}</title>
<link>{{ .Permalink }}</link>
<description>Recent content {{ with .Title }}in {{.}} {{ end }}on {{ .Site.Title }}</description>
<generator>Hugo -- gohugo.io</generator>{{ with .Site.LanguageCode }}
<language>{{.}}</language>{{end}}{{ with .Site.Author.email }}
<managingEditor>{{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}</managingEditor>{{end}}{{ with .Site.Author.email }}
<webMaster>{{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}</webMaster>{{end}}{{ with .Site.Copyright }}
<copyright>{{.}}</copyright>{{end}}{{ if not .Date.IsZero }}
<lastBuildDate>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}</lastBuildDate>{{ end }}
<atom:link href="{{.URL}}" rel="self" type="application/rss+xml" />
{{ range first 15 .Data.Pages }}
<item>
<title>{{ .Title }}</title>
<link>{{ .Permalink }}</link>
<pubDate>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}</pubDate>
{{ with .Site.Author.email }}<author>{{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}</author>{{end}}
<guid>{{ .Permalink }}</guid>
<description>{{ .Content | html }}</description>
</item>
{{ end }}
</channel>
</rss>
{{% warning “XML Header” %}}
Hugo will automatically add the following header line to this file on render. Please do not include this in the template as it’s not valid HTML.
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
{{% /warning %}}
<head>
In your header.html
template, you can specify your RSS feed in your <head></head>
tag like this:
{{ if .RSSLink }}
<link href="{{ .RSSLink }}" rel="alternate" type="application/rss+xml" title="{{ .Site.Title }}" />
<link href="{{ .RSSLink }}" rel="feed" type="application/rss+xml" title="{{ .Site.Title }}" />
{{ end }}
…with the auto-discovery link specified by the line with rel="alternate"
.
The .RSSLink
will render the appropriate RSS feed URL for the section, whether it’s everything, posts in a section, or a taxonomy.
If you reference your RSS link, be sure to specify the MIME type with type="application/rss+xml"
.
<a href="{{ .URL }}" type="application/rss+xml" target="_blank">{{ .SomeText }}</a>
A single Sitemap template is used to generate the sitemap.xml
file.
Hugo automatically comes with this template file. No work is needed on
the users’ part unless they want to customize sitemap.xml
.
A sitemap is a Page
and therefore has all the page variables available to use in this template along with Sitemap-specific ones:
.Sitemap.ChangeFreq
.Sitemap.Priority
.Sitemap.Filename
If provided, Hugo will use /layouts/sitemap.xml
instead of the internal sitemap.xml
template that ships with Hugo.
This template respects the version 0.9 of the Sitemap Protocol.
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
{{ range .Data.Pages }}
<url>
<loc>{{ .Permalink }}</loc>{{ if not .Lastmod.IsZero }}
<lastmod>{{ safeHTML ( .Lastmod.Format "2006-01-02T15:04:05-07:00" ) }}</lastmod>{{ end }}{{ with .Sitemap.ChangeFreq }}
<changefreq>{{ . }}</changefreq>{{ end }}{{ if ge .Sitemap.Priority 0.0 }}
<priority>{{ .Sitemap.Priority }}</priority>{{ end }}
</url>
{{ end }}
</urlset>
{{% note %}}
Hugo will automatically add the following header line to this file
on render. Please don’t include this in the template as it’s not valid HTML.
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
{{% /note %}}
sitemap.xml
Defaults for <changefreq>
, <priority>
and filename
values can be set in the site’s config file, e.g.:
[sitemap]
changefreq = "monthly"
priority = 0.5
filename = "sitemap.xml"
The same fields can be specified in an individual content file’s front matter in order to override the value assigned to that piece of content at render time.
pagevars: /variables/page/
To create your robots.txt as a template, first set the enableRobotsTXT
value to true
in your configuration file. By default, this option generates a robots.txt with the following content, which tells search engines that they are allowed to crawl everything:
User-agent: *
The lookup order for the robots.txt
template is as follows:
/layouts/robots.txt
/themes/<THEME>/layout/robots.txt
{{% note %}}
If you do not want Hugo to create a default robots.txt
or leverage the robots.txt
template, you can hand code your own and place the file in static
. Remember that everything in the static directory is copied over as-is when Hugo builds your site.
{{% /note %}}
The following is an example robots.txt
layout:
{{< code file=“layouts/robots.txt” download=“robots.txt” >}}
User-agent: *
{{range .Data.Pages}}
Disallow: {{.RelPermalink}}
{{end}}
{{< /code >}}
This template disallows all the pages of the site by creating one Disallow
entry for each page.
robots
{{% warning %}}
While the following internal templates are called similar to partials, they do not observe the partial template lookup order.
{{% /warning %}}
Hugo ships with internal templates for Google Analytics tracking, including both synchronous and asynchronous tracking codes.
Provide your tracking id in your configuration file:
googleAnalytics = "UA-123-45"
googleAnalytics: "UA-123-45"
You can then include the Google Analytics internal template:
{{ template "_internal/google_analytics.html" . }}
{{ template "_internal/google_analytics_async.html" . }}
Hugo also ships with an internal template for Disqus comments, a popular commenting system for both static and dynamic websites. In order to effectively use Disqus, you will need to secure a Disqus “shortname” by signingupforthefreeservice
To use Hugo’s Disqus template, you first need to set a single value in your site’s config.toml
or config.yml
:
disqusShortname = "yourdiscussshortname"
disqusShortname: "yourdiscussshortname"
You also have the option to set the following in the front matter for a given piece of content:
disqus_identifier
disqus_title
disqus_url
To add Disqus, include the following line in templates where you want your comments to appear:
{{ template "_internal/disqus.html" . }}
Users have noticed that enabling Disqus comments when running the Hugo web server on localhost
(i.e. via hugo server
) causes the creation of unwanted discussions on the associated Disqus account.
You can create the following layouts/partials/disqus.html
:
{{< code file=“layouts/partials/disqus.html” download=“disqus.html” >}}
The if
statement skips the initialization of the Disqus comment injection when you are running on localhost
.
You can then render your custom Disqus partial template as follows:
{{ partial "disqus.html" . }}
_internal/_default/robots.txt
_internal/_default/rss.xml
_internal/_default/sitemap.xml
_internal/_default/sitemapindex.xml
_internal/disqus.html
_internal/google_news.html
_internal/google_analytics.html
_internal/google_analytics_async.html
_internal/opengraph.html
_internal/pagination.html
_internal/schema.html
_internal/twitter_cards.html
For template documentation, follow the links from the Ace project.
list.ace
= include partials/foo.html .
{{ partial "foo" . }}
One noticeable difference between Ace and the other templating engines in Hugo is Ace’s inheritance support through base and inner templates.
In Hugo, the Ace base template will be chosen with the same rule set as for Gobasetemplates
.:
index.ace
./blog:
single.ace
baseof.ace
./_default:
baseof.ace list.ace single.ace single-baseof.ace
{{% note %}}
Note that the html
suffix is needed even if the filename is suffixed ace
. This does not work from inside a theme (issue #763).
{{% /note %}}
Some examples for the layout files above:
./index.ace
+ ./_default/baseof.ace
blog
section: ./blog/single.ace
+ ./blog/baseof.ace
./_default/single.ace
+ ./_default/single-baseof.ace
./_default/list.ace
+ ./_default/baseof.ace
{{% note %}}
In most cases, one baseof.ace
in _default
will suffice. An Ace template without a reference to a base section (e.g., = content
) will be handled as a standalone template.
{{% /note %}}
For Amber template documentation, follow the links from the Amber project.
list.amber
import ../partials/test.html
import ../partials/test_a.amber
Gobasetemplates
Here are some snippets you can add to your template to answer some common questions.
These snippets use the printf
function available in all Go templates. This function is an alias to the Go function, fmt.Printf.
You can use the template syntax, $.
, to get the top-level template context from anywhere in your template. This will print out all the values under, .Site
.
{{ printf "%#v" $.Site }}
This will print out the value of .Permalink
:
{{ printf "%#v" .Permalink }}
This will print out a list of all the variables scoped to the current context
(.
, aka “thedot”
{{ printf "%#v" . }}
When developing a homepage, what does one of the pages you’re looping through look like?
{{ range .Data.Pages }}
{{/* The context, ".", is now each one of the pages as it goes through the loop */}}
{{ printf "%#v" . }}
{{ end }}
{{% note “.Data.Pages
on the Homepage” %}}
.Data.Pages
on the homepage is equivalent to .Site.Pages
.
{{% /note %}}
Check that you are passing variables in the partial
function:
{{ partial "header" }}
This example will render the header partial, but the header partial will not have access to any contextual variables. You need to pass variables explicitly. For example, note the addition of “thedot”
{{ partial "header" . }}
The dot (.
) is considered fundamental to understanding Hugo templating. For more information, see IntroductiontoHugoTemplating
tempintro
Go templates are lightweight but extensible. Go itself supplies built-in functions, including comparison operators and other basic tools. These are listed in the Go template documentation. Hugo has added additional functions to the basic template logic.
An alternative way of writing an if
statement and then referencing the same value is to use with
instead. with
rebinds the context (.
) within its scope and skips the block if the variable is absent or unset.
The following example checks for a user-defined site variable called twitteruser
. If the key-value is not set, the following will render nothing:
{{< code file=“layouts/partials/twitter.html” >}}
{{with .Site.Params.twitteruser}}
{{end}}
{{< /code >}}
where
filters an array to only the elements containing a matching value for a given field.
{{ range where .Data.Pages "Section" "post" }}
{{ .Content }}
{{ end }}
It can be used by dot-chaining the second argument to refer to a nested element of a value.
+++
series: golang
+++
{{ range where .Site.Pages "Params.series" "golang" }}
{{ .Content }}
{{ end }}
It can also be used with the logical operators !=
, >=
, in
, etc. Without an operator, where
compares a given field with a matching value equivalent to =
.
{{ range where .Data.Pages "Section" "!=" "post" }}
{{ .Content }}
{{ end }}
The following logical operators are vailable with where
:
=
, ==
, eq
true
if a given field value equals a matching value!=
, <>
, ne
true
if a given field value doesn’t equal a matching value>=
, ge
true
if a given field value is greater than or equal to a matching value>
, gt
true
if a given field value is greater than a matching value<=
, le
true
if a given field value is lesser than or equal to a matching value<
, lt
true
if a given field value is lesser than a matching valuein
true
if a given field value is included in a matching value; a matching value must be an array or a slicenot in
true
if a given field value isn’t included in a matching value; a matching value must be an array or a sliceintersect
true
if a given field value that is a slice/array of strings or integers contains elements in common with the matching value; it follows the same rules as the intersect
function.where
with intersect
{{ range where .Site.Pages ".Params.tags" "intersect" .Params.tags }}
{{ if ne .Permalink $.Permalink }}
{{ .Render "summary" }}
{{ end }}
{{ end }}
You can also put the returned value of the where
clauses into a variable:
{{< code file=“where-intersect-variables.html” >}}
{{ v1 := where .Site.Pages “Params.a” “v1” }}
{{v2 := where .Site.Pages “Params.b” “v2” }}
{{ filtered:=v1 | intersect v2 }}
{{ rangefiltered }}
{{ end }}
{{< /code >}}
where
with first
The following grabs the first five content files in post
using the default ordering for lists (i.e., weight => date
):
{{< code file=“where-with-first.html” >}}
{{ range first 5 (where .Data.Pages “Section” “post”) }}
{{ .Content }}
{{ end }}
{{< /code >}}
where
ClausesYou can also nest where
clauses to drill down on lists of content by more than one parameter. The following first grabs all pages in the “blog” section and then ranges through the result of the first where
clause and finds all pages that are not featured:
{{ range where (where .Data.Pages "Section" "blog" ) ".Params.featured" "!=" "true" }}
Filtering only works for set fields. To check whether a field is set or exists, you can use the operand nil
.
This can be useful to filter a small amount of pages from a large pool. Instead of set field on all pages, you can set field on required pages only.
Only the following operators are available for nil
=
, ==
, eq
: True if the given field is not set.!=
, <>
, ne
: True if the given field is set.{{ range where .Data.Pages ".Params.specialpost" "!=" nil }}
{{ .Content }}
{{ end }}
The following examples pull from a content file with the following front matter:
{{< code file=“content/blog/greatest-city.md” copy=“false”>}}
+++
title = “The World’s Greatest City”
location = “Chicago IL”
tags = “pizza”,“beer”,“hotdogs”
The following might be used as a partial within a single page template:
{{< code file=“layouts/partials/content-header.html” download=“content-header.html” >}}
The preceding partial would then output to the rendered page as follows, assuming the page is being built with Hugo’s default pretty URLs.
{{< output file=“/blog/greatest-city/index.html” >}}
Note that upper
can be applied in your templates in more than one way:
{{ upper "BatMan" }} → "BATMAN"
{{ "BatMan" | upper }} → "BATMAN"
This very simple one-liner uses now.Unix
to calculate the amount of time that has passed between the .LastMod
for the current page and the last build of the current page.
{{< code file=“time-passed.html” >}}
{{ div (sub now.Unix .Lastmod.Unix) 86400 }}
{{< /code >}}
Since both values are integers, they can be subtracted and then divided by the number of seconds in a day (i.e., 60 * 60 * 24 == 86400
).
{{% note %}}
Hugo’s output is static. For the example above to be realistic, the site needs to be built every day.
{{% /note %}}
{{ uniq (slice 1 2 3 2) }}
{{ slice 1 2 3 2 | uniq }}
<!-- both return [1 2 3] -->
Given two arrays (or slices) A and B, this function will return a new array that contains the elements or objects that belong to either A or to B or to both. The elements supported are strings, integers, and floats (only float64).
{{ union (slice 1 2 3) (slice 3 4 5) }}
<!-- returns [1 2 3 4 5] -->
{{ union (slice 1 2 3) nil }}
<!-- returns [1 2 3] -->
{{ union nil (slice 1 2 3) }}
<!-- returns [1 2 3] -->
{{ union nil nil }}
<!-- returns an error because both arrays/slices have to be of the same type -->
This is also very useful to use as OR
filters when combined with where:
{{ $pages := where .Site.RegularPages "Type" "not in" (slice "page" "about") }}
{{ $pages := $pages | union (where .Site.RegularPages "Params.pinned" true) }}
{{ $pages := $pages | intersect (where .Site.RegularPages "Params.images" "!=" nil) }}
The above fetches regular pages not of page
or about
type unless they are pinned. And finally, we exclude all pages with no images
set in Page params.
See intersect for AND
.
Since Go templates are HTML-aware, truncate
will intelligently handle normal strings vs HTML strings:
{{ "<em>Keep my HTML</em>" | safeHTML | truncate 10 }}` → <em>Keep my …</em>`
{{% note %}}
If you have a raw string that contains HTML tags you want to remain treated as HTML, you will need to convert the string to HTML using the safeHTML
template function before sending the value to truncate. Otherwise, the HTML tags will be escaped when passed through the truncate
function.
{{% /note %}}
{{ trim "++Batman--" "+-" }} → "Batman"
trim
requires the second argument, which tells the function specifically what to remove from the first argument. There is no default value for the second argument, so the following usage will not work:
{{ trim .Inner}}
Instead, the following example tells trim
to remove extra new lines from the content contained in the shortcode .Inner
variable:
{{ trim .Inner "\n" }}
{{% note %}}
Go templates also provide a simple method for trimming whitespace from either side of a Go tag by including a hyphen (-
).
{{% /note %}}
{{title "BatMan"}}` → "Batman"
time
converts a timestamp string into a time.Time
structure so you can access its fields:
{{ time "2016-05-28" }} → "2016-05-28T00:00:00Z"
{{ (time "2016-05-28").YearDay }} → 149
{{ mul 1000 (time "2016-05-28T10:30:00.00+10:00").Unix }} → 1464395400000, or Unix time in milliseconds
time
to get Month IndexThe following example takes a UNIX timestamp—set as utimestamp: "1489276800"
in a content’s front matter—converts the timestamp (string) to an integer using the int
function, and then uses printf
to convert the Month
property of time
into an index.
The following example may be useful when setting up multilingual sites:
{{< code file=“unix-to-month-integer.html” >}}
{{time := time (int .Params.addDate)}}
=>time = 1489276800
{{time.Month}}
=> “March”
{{$monthindex := printf “%d” $time.Month }}
=>monthindex = 3
{{< /code >}}
It normally takes two parameters: start
and length
. It can also take one parameter: start
, i.e. length
is omitted, in which case the substring starting from start until the end of the string will be returned.
To extract characters from the end of the string, use a negative start number.
In addition, borrowing from the extended behavior described at http://php.net substr, if length
is given and is negative, that number of characters will be omitted from the end of string.
{{substr "BatMan" 0 -3}} → "Bat"
{{substr "BatMan" 3 3}} → "Man"
{{string "BatMan"}}
→ “BatMan”{{split "tag1,tag2,tag3" "," }}
→ “tag1”“tag2”“tag3”A sorted array of map values will be returned with the keys eliminated. There are two optional arguments: sortByField
and sortAsc
. If left blank, sort will sort by keys (for maps) in ascending order as its default behavior.
+++
#tags: [ "tag3", "tag1", "tag2" ]
+++
// Site config
+++
[params.authors]
[params.authors.Derek]
"firstName" = "Derek"
"lastName" = "Perkins"
[params.authors.Joe]
"firstName" = "Joe"
"lastName" = "Bergevin"
[params.authors.Tanner]
"firstName" = "Tanner"
"lastName" = "Linsley"
+++
// Use default sort options - sort by key / ascending
Tags: {{ range sort .Params.tags }}{{ . }} {{ end }}
→ Outputs Tags: tag1 tag2 tag3
// Sort by value / descending
Tags: {{ range sort .Params.tags "value" "desc" }}{{ . }} {{ end }}
→ Outputs Tags: tag3 tag2 tag1
// Use default sort options - sort by value / descending
Authors: {{ range sort .Site.Params.authors }}{{ .firstName }} {{ end }}
→ Outputs Authors: Derek Joe Tanner
// Use default sort options - sort by value / descending
Authors: {{ range sort .Site.Params.authors "lastName" "desc" }}{{ .lastName }} {{ end }}
→ Outputs Authors: Perkins Linsley Bergevin
For example, 1 and 4 creates a slice including elements 1 through 3.
The end
index can be omitted; it defaults to the string’s length.
{{slicestr "BatMan" 3}}
→ “Man”{{slicestr "BatMan" 0 3}}
→ “Bat”One use case is the concatenation of elements in combination with the delimit
function:
{{< code file=“slice.html” >}}
{{ delimit (slice “foo” “bar” “buzz”) ", " }}
{{< /code >}}
{{ "cats" | singularize }}
→ “cat”
See also the .Data.Singular
taxonomy variable for singularizing taxonomy names.
{{< code file=“shuffle-input.html” >}}
This example would return the following:
{{< output file=“shuffle-output.html” >}}
This example also makes use of the slice and seq functions.
sha1
hashes the given input and returns its SHA1 checksum.
{{ sha1 "Hello world, gophers!" }}
<!-- returns the string "c8b5b0e33d408246e30f53e32b8f7627a7a649d4" -->
sha256
hashes the given input and returns its SHA256 checksum.
{{ sha256 "Hello world, gophers!" }}
<!-- returns the string "6ec43b78da9669f50e4e422575c54bf87536954ccd58280219c393f2ce352b46" -->
It’s named and used in the model of GNU’s seq.
3 → 1, 2, 3
1 2 4 → 1, 3
-3 → -1, -2, -3
1 4 → 1, 2, 3, 4
1 -2 → 1, 0, -1, -2
seq
with range
and after
You can use seq
in combination with range
and after
. The following will return 19 elements:
{{ range after 1 (seq 20)}}
{{ end }}
However, when ranging with an index, the following may be less confusing in that $indexStartingAt1
and $num
will return 1,2,3 ... 20
:
{{ range $index, $num := (seq 20) }}
$indexStartingAt1 := (add $index 1)
{{ end }}
In most cases you can do well without Scratch
, but there are some use cases that aren’t solvable with Go’s templates without Scratch
’s help, due to scoping issues.
Scratch
is added to both Page
and Shortcode
– with following methods:
Set
and Add
takes a key
and the value
to add.Get
returns the value
for the key
given.SetInMap
takes a key
, mapKey
and value
GetSortedMapValues
returns array of values from key
sorted by mapKey
Set
and SetInMap
can store values of any type.
For single values, Add
accepts values that support Go’s +
operator. If the first Add
for a key is an array or slice, the following adds will be appended to that list.
The scope of the backing data is global for the given Page
or Shortcode
, and spans partial and shortcode includes.
Note that .Scratch
from a shortcode will return the shortcode’s Scratch
, which in most cases is what you want. If you want to store it in the page scroped Scratch, then use .Page.Scratch
.
The usage is best illustrated with some samples:
{{ $.Scratch.Add "a1" 12 }}
{{ $.Scratch.Get "a1" }} {{/* => 12 */}}
{{ $.Scratch.Add "a1" 1 }}
{{ $.Scratch.Get "a1" }} // {{/* => 13 */}}
{{ $.Scratch.Add "a2" "AB" }}
{{ $.Scratch.Get "a2" }} {{/* => AB */}}
{{ $.Scratch.Add "a2" "CD" }}
{{ $.Scratch.Get "a2" }} {{/* => ABCD */}}
{{ $.Scratch.Add "l1" (slice "A" "B") }}
{{ $.Scratch.Get "l1" }} {{/* => [A B] */}}
{{ $.Scratch.Add "l1" (slice "C" "D") }}
{{ $.Scratch.Get "l1" }} {{/* => [A B C D] */}}
{{ $.Scratch.Set "v1" 123 }}
{{ $.Scratch.Get "v1" }} {{/* => 123 */}}
{{ $.Scratch.SetInMap "a3" "b" "XX" }}
{{ $.Scratch.SetInMap "a3" "a" "AA" }}
{{ $.Scratch.SetInMap "a3" "c" "CC" }}
{{ $.Scratch.SetInMap "a3" "b" "BB" }}
{{ $.Scratch.GetSortedMapValues "a3" }} {{/* => []interface {}{"AA", "BB", "CC"} */}}
{{% note %}}
The examples above uses the special $
variable, which refers to the top-level node. This is the behavior you most likely want, and will help remove some confusion when using Scratch
inside page range loops – and you start inadvertently calling the wrong Scratch
. But there may be use cases for {{ .Scratch.Add "key" "some value" }}
.
{{% /note %}}
safeURL
declares the provided string as a “safe” URL or URL substring (see RFC 3986). A URL like javascript:checkThatFormNotEditedBeforeLeavingPage()
from a trusted source should go in the page, but by default dynamic javascript:
URLs are filtered out since they are a frequently exploited injection vector.
Without safeURL
, only the URI schemes http:
, https:
and mailto:
are considered safe by Go templates. If any other URI schemes (e.g., irc:
and javascript:
) are detected, the whole URL will be replaced with #ZgotmplZ
. This is to “defang” any potential attack in the URL by rendering it useless.
The following examples use a site config.toml
with the following menu entry:
{{< code file=“config.toml” copy=“false” >}}
[menu.main
The following is an example of a sidebar partial that may be used in conjunction with the preceding front matter example:
{{< code file=“layouts/partials/bad-url-sidebar-menu.html” copy=“false” >}}
This partial would produce the following HTML output:
{{< output file=“bad-url-sidebar-menu-output.html” >}}
{{< /output >}}The odd output can be remedied by adding | safeURL
to our .Title
page variable:
{{< code file=“layouts/partials/correct-url-sidebar-menu.html” copy=“false” >}}
{{< /code >}}With the .URL
page variable piped through safeURL
, we get the desired output:
{{< output file=“correct-url-sidebar-menu-output.html” >}}
{{< /output >}}In this context, safe means the string encapsulates a known safe EcmaScript5 Expression (e.g., (x + y * z())
).
Template authors are responsible for ensuring that typed expressions do not break the intended precedence and that there is no statement/expression ambiguity as when passing an expression like { foo:bar() }\n′foo′
, which is both a valid expression and a valid program with a very different meaning.
Example: Given hash = "619c16f"
defined in the front matter of your .md
file:
<script>var form_{{ .Params.hash | safeJS }};…</script>
→ <script>var form_619c16f;…</script>
<script>var form_{{ .Params.hash }};…</script>
→ <script>var form_"619c16f";…</script>
Example: Given a site-wide config.toml
that contains this menu entry:
[[menu.main]]
name = "IRC: #golang at freenode"
url = "irc://irc.freenode.net/#golang"
<a href="{{ .URL }}">
→ <a href="#ZgotmplZ">
<a {{ printf "href=%q" .URL | safeHTMLAttr }}>
→ <a href="irc://irc.freenode.net/#golang">
It should not be used for HTML from a third-party, or HTML with unclosed tags or comments.
Given a site-wide config.toml
with the following copyright
value:
copyright = "© 2015 Jane Doe. <a href=\"http://creativecommons.org/licenses/by/4.0/\">Some rights reserved</a>."
{{ .Site.Copyright | safeHTML }}
in a template would then output:
© 2015 Jane Doe. <a href="http://creativecommons.org/licenses/by/4.0/">Some rights reserved</a>.
However, without the safeHTML
function, html/template assumes .Site.Copyright
to be unsafe and therefore escapes all HTML tags and renders the whole string as plain text:
<p>© 2015 Jane Doe. <a href="http://creativecommons.org/licenses by/4.0/">Some rights reserved</a>.</p>
In this context, safe means CSS content that matches any of the following:
p { color: purple }
.ahref= "https:".foo#bar
.color: red; margin: 2px
.rgba(0, 0, 255, 127)
.Example: Given style = "color: red;"
defined in the front matter of your .md
file:
<p style="{{ .Params.style | safeCSS }}">…</p>
→ <p style="color: red;">…</p>
<p style="{{ .Params.style }}">…</p>
→ <p style="ZgotmplZ">…</p>
{{% note “ZgotmplZ” %}}
“ZgotmplZ” is a special value that indicates that unsafe content reached a CSS or URL context.
{{% /note %}}
{{ replaceRE "^https?://([^/]+).*" "$1" "http://gohugo.io/docs" }}` → "gohugo.io"
{{ "http://gohugo.io/docs" | replaceRE "^https?://([^/]+).*" "$1" }}` → "gohugo.io"
{{% note %}}
Hugo uses Golang’s Regular Expression package, which is the same general syntax used by Perl, Python, and other languages but with a few minor differences for those coming from a background in PCRE. For a full syntax listing, see the GitHub wiki for re2.
If you are just learning RegEx, or at least Golang’s flavor, you can practice pattern matching in the browser at https://regex101.com/.
{{% /note %}}
`{{ replace "Batman and Robin" "Robin" "Catwoman" }}`
→ "Batman and Catwoman"
The view is an alternative layout and should be a file name that points to a template in one of the locations specified in the documentation for Content Views.
This function is only available when applied to a single piece of content within a list context.
This example could render a piece of content using the content view located at /layouts/_default/summary.html
:
{{ range .Data.Pages }}
{{ .Render "summary"}}
{{ end }}
Both absURL
and relURL
consider the configured value of baseURL
in your site’s config
file. Given a baseURL
set to http://example.com/hugo/
:
{{ "mystyle.css" | absURL }} → "http://example.com/hugo/mystyle.css"
{{ "mystyle.css" | relURL }} → "/hugo/mystyle.css"
{{ "http://gohugo.io/" | relURL }} → "http://gohugo.io/"
{{ "http://gohugo.io/" | absURL }} → "http://gohugo.io/"
The last two examples may look strange but can be very useful. For example, the following shows how to use absURL
in JSON-LD structured data for SEO where some of your images for a piece of content may or may not be hosted locally:
{{< code file=“layouts/partials/schemaorg-metadata.html” download=“schemaorg-metadata.html” >}}
{{< /code >}}
The above uses the apply function and also exposes how the Go template parser JSON-encodes objects inside <script>
tags. See the safeJS template function for examples of how to tell Hugo not to escape strings inside of such tags.
{{% note “Ending Slash” %}}
absURL
and relURL
are smart about missing slashes, but they will not add a closing slash to a URL if it is not present.
{{% /note %}}
ref
and relRef
look up a content page by relative path (relref
) or logical name (ref
) to return the permalink. Both functions require a Page
object (usually satisfied with a “.
”):
{{ relref . "about.md" }}
These functions are used in two of Hugo’s built-in shortcodes. You can see basic usage examples of both ref
and relref
in the shortcode documentation.
For an extensive explanation of how to leverage ref
and relref
for content management, see Cross References.
absLangURL
and relLangURL
functions are similar to their absURL
and relURL
relatives but will add the correct language prefix when the site is configured with more than one language. (See Configuring Multilingual.)
So for a site baseURL
set to http://example.com/hugo/
and the current language is en
:
{{ "blog/" | absLangURL }} → "http://example.com/hugo/en/blog/"
{{ "blog/" | relLangURL }} → "/hugo/en/blog/"
ref
and relRef
look up a content page by relative path (relref
) or logical name (ref
) to return the permalink. Both functions require a Page
object (usually satisfied with a “.
”):
{{ relref . "about.md" }}
These functions are used in two of Hugo’s built-in shortcodes. You can see basic usage examples of both ref
and relref
in the shortcode documentation.
For an extensive explanation of how to leverage ref
and relref
for content management, see Cross References.
Note that the filename must be relative to the current project working directory.
So, if you have a file with the name README.txt
in the root of your project with the content Hugo Rocks!
:
{{readFile "README.txt"}} → "Hugo Rocks!"
For more information on using readDir
and readFile
in your templates, see Local File Templates.
If your current project working directory has a single file named README.txt
:
{{ range (readDir ".") }}{{ .Name }}{{ end }} → "README.txt"
For more information on using readDir
and readFile
in your templates, see Local File Templates.
Just like in the Go programming language, Go and Hugo templates make heavy use of range
to iterate over a map, array or slice.
range
is fundamental to templating in Hugo. (See the Introduction to Hugo Templates for more examples.
querify
takes a set of key-value pairs and returns a query string that can be appended to a URL. E.g.
The following example creates a link to a search results page on Google.
<a href="https://www.google.com?{{ (querify "q" "test" "page" 3) | safeURL }}">Search</a>
This example renders the following HTML:
<a href="https://www.google.com?page=3&q=test">Search</a>
See the go doc for additional information.
{{ i18n ( printf "combined_%s" $var ) }}
{{ printf "formatted %.2f" 3.1416 }}
{{ "cat" | pluralize }} → "cats"
{{ "<b>BatMan</b>" | plainify }} → "BatMan"
See also the .PlainWords
, .Plain
, and .RawContent
page variables.
The partialCached
template function can offer significant performance gains for complex templates that don’t need to be re-rendered on every invocation. Here is the simplest usage:
{{ partialCached "footer.html" . }}
You can also pass additional parameters to partialCached
to create variants of the cached partial. For example, if you have a complex partial that should be identical when rendered for pages within the same section, you could use a variant based upon section so that the partial is only rendered once per section:
{{< code file=“partial-cached-example.html” >}}
{{ partialCached “footer.html” . .Section }}
{{< /code >}}
If you need to pass additional parameters to create unique variants, you can pass as many variant parameters as you need:
{{ partialCached "footer.html" . .Params.country .Params.province }}
Note that the variant parameters are not made available to the underlying partial template. They are only use to create a unique cache key.
In Hugo, you can declare site-wide params (i.e. in your configuration), as well as params for individual pages.
A common use case is to have a general value for the site and a more specific value for some of the pages (e.g., an image).
You can use the .Param
method to call these values into your template. The following will first look for an image
param in a specific content’s front matter. If not found, Hugo will look for an image
param in your site’s configuration:
$.Param "image"
{{% note %}}
The Param
method may not consider empty strings in a content’s front matter as “not found.” If you are setting preconfigured front matter fields to empty strings using Hugo’s archetypes, it may be best to use the default
function instead of Param
. See the related issue on GitHub.
{{% /note %}}
See time.Time
.
For example, building your site on June 24, 2017 with the following templating:
<div>
<small>© {{ now.Format "2006"}}</small>
</div>
Which will produce the following:
<div>
<small>© 2017</small>
</div>
The above example uses the .Format
function, which page includes a full listing of date formatting using Golang’s layout string.
{{% note %}}
Older Hugo themes may use the deprecated .Now
(uppercase). Be sure to use the lowercase .now
in your templating.
{{% /note %}}
{{ if ne .Section "blog" }}current{{ end }}
{{ md5 "Hello world, gophers!" }}
<!-- returns the string "b3029f756f98f79e7f1b7f1d1f0dd53b" -->
This can be useful if you want to use Gravatar for generating a unique avatar:
<img src="https://www.gravatar.com/avatar/{{ md5 "your@email.com" }}?s=100&d=identicon">
There are 6 basic mathematical operators that can be used in Hugo templates:
Function | Description | Example |
---|---|---|
add |
Adds two integers. | {{add 1 2}} → 3 |
div |
Divides two integers. | {{div 6 3}} → 2 |
mod |
Modulus of two integers. | {{mod 15 3}} → 0 |
modBool |
Boolean of modulus of two integers. Evaluates to true if = 0. |
{{modBool 15 3}} → true |
mul |
Multiplies two integers. | {{mul 2 3}} → 6 |
sub |
Subtracts two integers. | {{sub 3 2}} → 1 |
add
with StringsYou can also use the add
function with strings. You may like this functionality in many use cases, including creating new variables by combining page- or site-level variables with other strings.
For example, social media sharing with Twitter Cards requires the following meta
link in your site’s <head>
to display Twitter’s “SummaryCardwithLargeImage”
<meta name="twitter:image" content="http://example.com/images/my-twitter-image.jpg">
Let’s assume you have an image
field in the front matter of each of your content files:
---
title: My Post
image: my-post-image.jpg
---
You can then concatenate the image
value (string) with the path to your images
directory in static
and leverage a URL-related templating function for increased flexibility:
{{< code file=“partials/head/twitter-card.html” >}}
{{$socialimage := add “images/” .Params.image}}
{{< /code >}}
{{% note %}}
The add
example above makes use of the absURL
function. absURL
and its relative companion relURL
is the recommended way to construct URLs in Hugo.
{{% /note %}}
twtsummary
{{ .Title | markdownify }}
{{ if lt 5 10 }}true{{ end }}
{{lower "BatMan"}} → "batman"
len
is a built-in function in Golang that returns the length of a variable according to its type. From the Golang documentation:
Array: the number of elements in v.
Pointer to array: the number of elements in *v (even if v is nil).
Slice, or map: the number of elements in v; if v is nil, len(v) is zero.
String: the number of bytes in v.
Channel: the number of elements queued (unread) in the channel buffer; if v is nil, len(v) is zero.
len
is also considered a fundamental function for Hugo templating.
len
Example 1: Longer HeadingsYou may want to append a class to a heading according to the length of the string therein. The following templating checks to see if the title’s length is greater than 80 characters and, if so, adds a long-title
class to the <h1>
:
{{< code file=“check-title-length.html” >}}
len
Example 2: Counting Pages with where
The following templating uses [where
]
len
to figure out the total number of content pages in a posts
section:
{{< code file=“how-many-posts.html” >}}
{{ posts := (where .Site.RegularPages “Section” “==” “post”) }}
{{postCount := len $posts }}
{{< /code >}}
Note the use of .RegularPages
, a site variable that counts all regular content pages but not the _index.md
pages used to add front matter and content to list templates.
{{ if le 5 10 }}true{{ end }}
{{ range last 10 .Data.Pages }}
{{ .Render "summary" }}
{{ end }}
{{ dict "title" .Title "content" .Plain | jsonify }}
See also the .PlainWords
, .Plain
, and .RawContent
page variables.
Takes either a slice, array, or channel and an index or a map and a key as input.
{{ if isset .Params "project_url" }} {{ index .Params "project_url" }}{{ end }}
{{% warning %}}
All site-level configuration keys are stored as lower case. Therefore, a myParam
key-value set in your site configuration file needs to be accessed with {{if isset .Site.Params "myparam"}}
and not with {{if isset .Site.Params "myParam"}}
. Note that you can still access the same config key with .Site.Params.myParam
or .Site.Params.myparam
, for example, when using with
.
{{% /warning %}}
Used in menu templates.
The elements supported are strings, integers, and floats (only float64).
A useful example of intersect
functionality is a “related posts” block. isset
allows us to create a list of links to other posts that have tags that intersect with the tags in the current post.
The following is an example of a “related posts” partial template that could be added to a single page template:
{{< code file=“layouts/partials/related-posts.html” download=“related-posts.html” >}}
This is also very useful to use as AND
filters when combined with where:
{{ $pages := where .Site.RegularPages "Type" "not in" (slice "page" "about") }}
{{ $pages := $pages | union (where .Site.RegularPages "Params.pinned" true) }}
{{ $pages := $pages | intersect (where .Site.RegularPages "Params.images" "!=" nil) }}
The above fetches regular pages not of page
or about
type unless they are pinned. And finally, we exclude all pages with no images
set in Page params.
See union for OR
.
Useful for turning strings into numbers.
{{ int "123" }} → 123
From the Godocs:
Returns the result of indexing its first argument by the following arguments. Thus “index x 1 2 3” is, in Go syntax, x13. Each indexed item must be a map, slice, or array.
In Go templates, you can’t access array, slice, or map elements directly the same way you would in Go. For example, $.Site.Data.authors[.Params.authorkey]
isn’t supported syntax.
Instead, you have to use index
, a function that handles the lookup for you.
Assume you want to add a location = ""
field to your front matter for every article written in content/vacations/
. You want to use this field to populate information about the location at the bottom of the article in your single.html
template. You also have a directory in data/locations/
that looks like the following:
.
└── data
└── locations
├── abilene.toml
├── chicago.toml
├── oslo.toml
└── provo.toml
Here is an example of the data inside data/locations/oslo.toml
:
website = "https://www.oslo.kommune.no"
pop_city = 658390
pop_metro = 1717900
The example we will use will be an article on Oslo, which front matter should set to exactly the same name as the corresponding file name in data/locations/
:
title = "My Norwegian Vacation"
location = "oslo"
The content of oslo.toml
can be accessed from your template using the following node path: .Site.Data.locations.oslo
. However, the specific file you need is going to change according to the front matter.
This is where the index
function is needed. index
takes 2 parameters in this use case:
{{ index .Site.Data.locations “oslo” }}
The variable for .Params.location
is a string and can therefore replace oslo
in the example above:
{{ index .Site.Data.authors .Params.author }}
=> map[website:https://www.oslo.kommune.no pop_city:658390 pop_metro:1717900]
Now the call will return the specific file according to the location specified in the content’s front matter, but you will likely want to write specific properties to the template. You can do this by continuing down the node path via dot notation (.
):
{{ (index .Site.Data.locations .Params.location).pop_city }}
=> 658390
The elements supported are strings, integers and floats, although only float64 will match as expected.
In addition, in
can also check if a substring exists in a string.
{{ if in .Params.tags "Git" }}Follow me on GitHub!{{ end }}
{{ if in "this string contains a substring" "substring" }}Substring found!{{ end }}
{{ with (imageConfig "favicon.ico") }}
favicon.ico: {{.Width}} x {{.Height}}
{{ end }}
This translates a piece of content based on your i18n/en-US.yaml
(and similar) files. You can use the go-i18n tools to manage your translations. The translations can exist in both the theme and at the root of your repository.
{{ i18n "translation_id" }}
{{% note “Alias T
” %}}
T
is an alias to i18n
. E.g. {{ T "translation_id" }}
.
{{% /note %}}
For more information about string translations, see Translation of Strings in Multilingual Mode.
If the input is either an int64 value or the string representation of an integer, humanize returns the number with the proper ordinal appended.
{{humanize "my-first-post"}} → "My first post"
{{humanize "myCamelPost"}} → "My camel post"
{{humanize "52"}} → "52nd"
{{humanize 103}} → "103rd"
htmlUnescape
returns the given string with HTML escape codes un-escaped.
Remember to pass the output of this to safeHTML
if fully un-escaped characters are desired. Otherwise, the output will be escaped again as normal.
{{ htmlUnescape "Hugo & Caddy > Wordpress & Apache" }} → "Hugo & Caddy > Wordpress & Apache"
In the result &
becomes &
and so on. It escapes only: <
, >
, &
, '
and "
.
{{ htmlEscape "Hugo & Caddy > Wordpress & Apache" }} → "Hugo & Caddy > Wordpress & Apache"
highlight
is used in Hugo’s built-in highlight
shortcode.
See Installing Hugo for more information on Pygments or Syntax Highlighting for more options on how to add syntax highlighting to your code blocks with Hugo.
Used in menu templates.
Used in menu templates.
{{ if gt 10 5 }}true{{ end }}
Takes a string containing the name of the variable as input. Returns
an empty string if the variable is not set, otherwise returns the
value of the variable.
{{ getenv "HOME" }}
{{% note %}}
In Unix-like environments, the variable must also be exported in order to be seen by hugo
.
{{% /note %}}
.Get
is specifically used when creating your own shortcode template.
{{ if ge 10 5 }}true{{ end }}
.Format
will format date values defined in your front matter and can be used as a property on the following page variables:
.PublishDate
.Date
.LastMod
Assuming a key-value of date: 2017-03-03
in a content file’s front matter, your can run the date through .Format
followed by a layout string for your desired output at build time:
{{ .PublishDate.Format "January 2, 2006" }} => March 3, 2017
For formatting any string representations of dates defined in your front matter, see the dateFormat
function, which will still leverage the Golang layout string explained below but uses a slightly different syntax.
Hugo templates format your dates via layout strings that point to a specific reference time:
Mon Jan 2 15:04:05 MST 2006
While this may seem arbitrary, the numerical value of MST
is 07
, thus making the layout string a sequence of numbers.
Here is a visual explanation taken directly from the Go docs:
Jan 2 15:04:05 2006 MST
=> 1 2 3 4 5 6 -7
The following examples show the layout string followed by the rendered output.
The examples were rendered and tested in CST and all point to the same field in a content file’s front matter:
date: 2017-03-03T14:15:59-06:00
.Date
(i.e. called via page variable)2017-03-03 14:15:59 -0600 CST
"Monday, January 2, 2006"
Friday, March 3, 2017
"Mon Jan 2 2006"
Fri Mar 3 2017
"January 2nd"
March 3rd
"January 2006"
March 2017
"2006-01-02"
2017-03-03
"Monday"
Friday
"02 Jan 06 15:04 MST"
(RFC822)03 Mar 17 14:15 CST
"02 Jan 06 15:04 -0700"
(RFC822Z)03 Mar 17 14:15 -0600
"Mon, 02 Jan 2006 15:04:05 MST"
(RFC1123)Fri, 03 Mar 2017 14:15:59 CST
"Mon, 02 Jan 2006 15:04:05 -0700"
(RFC339)Fri, 03 Mar 2017 14:15:59 -0600
Spelled-out cardinal numbers (e.g. “one”, “two”, and “three”) and ordinal abbreviations (i.e., with shorted suffixes like “1st”, “2nd”, and “3rd”) are not currently supported:
{{.Date.Format "Jan 2nd 2006"}}
Hugo assumes you want to append nd
as a string to the day of the month and outputs the following:
Mar 3nd 2017
.Local
and .UTC
In conjunction with the dateFormat
function, you can also convert your dates to UTC
or to local timezones:
{{ dateFormat "02 Jan 06 15:04 MST" .Date.UTC }}
03 Mar 17 20:15 UTC
{{ dateFormat "02 Jan 06 15:04 MST" .Date.Local }}
03 Mar 17 14:15 CST
{{ range first 10 .Data.Pages }}
{{ .Render "summary" }}
{{ end }}
By default all matches will be included. The number of matches can be limitted with an optional third parameter.
The example below returns a list of all second level headers (<h2>
) in the content:
{{ findRE "<h2.*?>(.|\n)*?</h2>" .Content }}
You can limit the number of matches in the list with a third parameter. The following example shows how to limit the returned value to just one match (or none, if there are no matched substrings):
{{ findRE "<h2.*?>(.|\n)*?</h2>" .Content 1 }}
<!-- returns ["<h2 id="#foo">Foo</h2>"] -->
{{% note %}}
Hugo uses Golang’s Regular Expression package, which is the same general syntax used by Perl, Python, and other languages but with a few minor differences for those coming from a background in PCRE. For a full syntax listing, see the GitHub wiki for re2.
If you are just learning RegEx, or at least Golang’s flavor, you can practice pattern matching in the browser at https://regex101.com/.
{{% /note %}}
{{ if eq .Section "blog" }}current{{ end }}
emoji
runs a passed string through the Emoji emoticons processor.
See the Emoji cheat sheet for available emoticons.
The emojify
function can be called in your templates but not directly in your content files by default. For emojis in content files, set enableEmoji
to true
in your site’s configuration. Then you can write emoji shorthand directly into your content files; e.g. I :
heart
: Hugo!
:
I ❤️ Hugo!
{{ echoParam .Params "project_url" }}
dict
is especially useful for passing more than one value to a partial template.
dict
with Embedded SVGsThe partial below creates a SVG and expects fill
height
and width
from the caller:
{{< code file=“layouts/partials/svgs/external-links.svg” download=“external-links.svg” >}}
{{< /code >}}
These values can be stored in one object with dict
and passed to the partial:
{{< code file=“layouts/_default/list.html” >}}
{{ partial “svg/link-ext.svg” (dict “fill” “#01589B” “size” 10 “width” 20 ) }}
{{< /code >}}
delimit
called in your template takes the form of
{{ delimit array/slice/map delimiter optionallastdelimiter}}
delimit
loops through any array, slice, or map and returns a string of all the values separated by a delimiter, the second argument in the function call. There is an optional third parameter that lets you choose a different delimiter to go between the last two values in the loop.
To maintain a consistent output order, maps will be sorted by keys and only a slice of the values will be returned.
The examples of delimit
that follow all use the same front matter:
{{< code file=“delimit-example-front-matter.toml” nocopy=“true” >}}
+++
title: I love Delimit
#tags: “tag1”,“tag2”,“tag3”
{{< code file=“delimit-page-tags-input.html” >}}
Tags: {{ delimit .Params.tags ", " }}
{{< /code >}}{{< output file=“delimit-page-tags-output.html” >}}
Tags: tag1, tag2, tag3
{{< /output >}}Here is the same example but with the optional “last” delimiter:
{{< code file=“delimit-page-tags-final-and-input.html” >}}
Tags: {{ delimit .Params.tags ", " ", and " }}
{{< /code >}}
{{< output file=“delimit-page-tags-final-and-output.html” >}}
Tags: tag1, tag2, and tag3
{{< /output >}}default
checks whether a given value is set and returns a default value if it is not. Set in this context means different things depending on date type:
default
function examples reference the following content page:
{{< /code >}}
default
can be written in more than one way:
{{ index .Params "font" | default "Roboto" }}
{{ default "Roboto" (index .Params "font") }}
Both of the above default
function calls return Roboto
.
A default
value, however, does not need to be hard coded like the previous example. The default
value can be a variable or pulled directly from the front matter using dot notation:
{{< code file=“variable-as-default-value.html” nocopy=“true” >}}
{{$old := .Params.oldparam }}
{{ .Params.newparam | default $old }}
{{< /code >}}Which would return:
<p>The default function helps make your templating DRYer.</p>
And then using dot notation
{{< code file=“dot-notation-default-value.html” >}}
Which would return
{{< output file=“dot-notation-default-return-value.html” >}}
The following have equivalent return values but are far less terse. This demonstrates the utility of default
:
Using if
:
{{< code file=“if-instead-of-default.html” nocopy=“true” >}}
Using with
:
{{< code file=“with-instead-of-default.html” nocopy=“true” >}}
dateFormat
converts the textual representation of the datetime
into the specified format or returns it as a Go time.Time
type value. These are formatted with the layout string.
{{ dateFormat "Monday, Jan 2, 2006" "2015-01-21" }} → "Wednesday, Jan 21, 2015"
{{% warning %}}
As of v0.19 of Hugo, the dateFormat
function is not supported as part of Hugo’s multilingual feature.
{{% /warning %}}
See the Format
function for a more complete list of date formatting options in your templates.
The template function works similar to the .WordCount page variable.
{{ "Hugo is a static site generator." | countwords }}
<!-- outputs a content length of 6 words. -->
In contrast with countwords
function, which counts every word in a string, the countrunes
function determines the number of runes in the content and excludes any whitespace. This has specific utility if you are dealing with CJK-like languages.
{{ "Hello, 世界" | countrunes }}
<!-- outputs a content length of 8 runes. -->
Useful in a pipeline to remove newlines added by other processing (e.g., markdownify
).
{{chomp "<p>Blockhead</p>\n"}} → "<p>Blockhead</p>"
An example:
{{< code file=“base64-input.html” >}}
Hello world = {{ "Hello world" | base64Encode }}
SGVsbG8gd29ybGQ = {{ "SGVsbG8gd29ybGQ=" | base64Decode }}
{{< /code >}}{{< output file=“base-64-output.html” >}}
Hello world = SGVsbG8gd29ybGQ=
SGVsbG8gd29ybGQ = Hello world
{{< /output >}}You can also pass other data types as arguments to the template function which tries to convert them. The following will convert 42 from an integer to a string because both base64Encode
and base64Decode
always return a string.
{{ 42 | base64Encode | base64Decode }}
=> "42" rather than 42
base64
with APIsUsing base64 to decode and encode becomes really powerful if we have to handle
responses from APIs.
{{ $resp := getJSON "https://api.github.com/repos/gohugoio/hugo/readme" }}
{{ $resp.content | base64Decode | markdownify }}
The response of the GitHub API contains the base64-encoded version of the README.md in the Hugo repository. Now we can decode it and parse the Markdown. The final output will look similar to the rendered version on GitHub.
{{< todo >}}
{{< /todo >}}
apply
expects at least three parameters, depending on the function being applied.
"."
standing in for each element of the sequence the function is to be applied against.Here is an example of a content file with name:
as a front matter field:
+++
names: [ "Derek Perkins", "Joe Bergevin", "Tanner Linsley" ]
+++
You can then use apply
as follows:
{{ apply .Params.names "urlize" "." }}
Which will result as follows:
"derek-perkins", "joe-bergevin", "tanner-linsley"
This is roughly equivalent to using the following with range
{{ range .Params.names }}{{ . | urlize }}{{ end }}
However, it isn’t possible to provide the output of a range to the delimit
function, so you need to apply
it.
If you have post-tag-list.html
and post-tag-link.html
as partials, you could use the following snippets, respectively:
{{< code file=“layouts/partial/post-tag-list.html” copy=“false” >}}
{{ with .Params.tags }}
{{< code file=“layouts/partial/post-tag-link.html” copy=“false” >}}
{{ . }}
{{< /code >}}
This works, but the complexity of post-tag-list.html
is fairly high. The Hugo template needs to perform special behavior for the case where there’s only one tag, and it has to treat the last tag as special. Additionally, the tag list will be rendered something like Tags: tag1 , tag2 , tag3
because of the way that the HTML is generated and then interpreted by a browser.
This first version of layouts/partials/post-tag-list.html
separates all of the operations for ease of reading. The combined and DRYer version is shown next:
{{ with .Params.tags }}
<div class="tags-list">
Tags:
{{ $sort := sort . }}
{{ $links := apply $sort "partial" "post-tag-link" "." }}
{{ $clean := apply $links "chomp" "." }}
{{ delimit $clean ", " }}
</div>
{{ end }}
Now in the completed version, you can sort the tags, convert the tags to links with layouts/partials/post-tag-link.html
, chomp off stray newlines, and join the tags together in a delimited list for presentation. Here is an even DRYer version of the preceding example:
{{< code file=“layouts/partials/post-tag-list.html” download=“post-tag-list.html” >}}
{{ with .Params.tags }}
{{% note %}}
apply
does not work when receiving the sequence as an argument through a pipeline.
{{% /note %}}
The following shows after
being used in conjunction with the slice
function:
{{ $data := slice "one" "two" "three" "four" }}
{{ range after 2 $data }}
{{ . }}
{{ end }}
→ ["three", "four"]
after
with first
: 2nd–4th Most Recent ArticlesYou can use after
in combination with the first
function and Hugo’s powerful sorting methods. Let’s assume you have a list page at example.com/articles
. You have 10 articles, but you want your templating for the list/section page to show only two rows:
publishdate
in the content files’ front matter).{{< code file=“layouts/section/articles.html” download=“articles.html” >}}
{{ define “main” }}
{{.Description}}
{{ end }}{{.Description}}
The AddDate
function takes three arguments in logical order of years
, months
, and days
.
Let’s assume you have a file at data/tweets.toml
that contains a list of Tweets to display on your site’s homepage. The file is filled with [tweet
blocks; e.g.—
[[tweet]]
name = "Steve Francia"
twitter_handle = "@spf13"
quote = "I'm creator of Hugo. #metadocreference"
link = "https://twitter.com/spf13"
date = "2017-01-07T00:00:00Z"
Let’s assume you want to grab Tweets from the last two years and present them in a random order. In conjunction with the where
and now
functions, you can limit our range to the last two years via now.AddDate -2 0 0
, which represents a point in time 2 years, 0 days, and 0 hours before the time of your last site build.
{{< code file=“partials/templates/random-tweets.html” download=“tweets.html” >}}
{{ range where $.Site.Data.tweets.tweet “date” “ge” (now.AddDate -2 0 0) | shuffle }}
{{ .quote | safeHTML }}
— {{ .name }} ({{ .twitter_handle }})
{{ dateFormat “January 2, 2006” .date }}
Both absURL
and relURL
consider the configured value of baseURL
in your site’s config
file. Given a baseURL
set to http://example.com/hugo/
:
{{ "mystyle.css" | absURL }} → "http://example.com/hugo/mystyle.css"
{{ "mystyle.css" | relURL }} → "/hugo/mystyle.css"
{{ "http://gohugo.io/" | relURL }} → "http://gohugo.io/"
{{ "http://gohugo.io/" | absURL }} → "http://gohugo.io/"
The last two examples may look strange but can be very useful. For example, the following shows how to use absURL
in JSON-LD structured data (SEO), where some of your images for a piece of content may or may not be hosted locally:
{{< code file=“layouts/partials/schemaorg-metadata.html” download=“schemaorg-metadata.html” >}}
{{< /code >}}
The above uses the apply function and also exposes how the Go template parser JSON-encodes objects inside <script>
tags. See the safeJS template function for examples of how to tell Hugo not to escape strings inside of such tags.
{{% note “Ending Slash” %}}
absURL
and relURL
are smart about missing slashes, but they will not add a closing slash to a URL if it is not present.
{{% /note %}}
Both absLangURL
and relLangURL
are similar to their absURL
and relURL
relatives but will add the correct language prefix when the site is configured with more than one language.
So for a site baseURL
set to http://example.com/hugo/
and the current language is en
:
{{ "blog/" | absLangURL }} → "http://example.com/hugo/en/blog/"
{{ "blog/" | relLangURL }} → "/hugo/en/blog/"
The default options value is - . ,
.
Numbers greater than or equal to 5 are rounded up. For example, if precision is set to 0
, 1.5
becomes 2
, and 1.4
becomes 1
.
{{ lang.NumFmt "," "." "-" 2 12345.6789 }} → 12.345,68
{{ lang.NumFmt "." "" "-" 6 -12345.6789 }} → -12345.678900
{{ lang.NumFmt "." "," "-" 0 -12345.6789 }} → -12,346
{{ -98765.4321 | lang.NumFmt "." "," "-" 2 }} → -98,765.43
Every Page
has a Kind
attribute that shows what kind of page it is. While this attribute can be used to list pages of a certain kind
using where
, often it can be useful to fetch a single page by its path.
.GetPage
looks up a page of a given Kind
and path
.
{{ with .Site.GetPage "section" "blog" }}{{ .Title }}{{ end }}
This method wil return nil
when no page could be found, so the above will not print anything if the blog section isn’t found.
For a regular page:
{{ with .Site.GetPage "page" "blog" "my-post.md" }}{{ .Title }}{{ end }}
Note that the path can also be supplied like this:
{{ with .Site.GetPage "page" "blog/my-post.md" }}{{ .Title }}{{ end }}
The valid page kinds are: page, home, section, taxonomy and taxonomyTerm.
.GetPage
ExampleThis code snippet—in the form of a partial template—allows you to do the following:
tags
taxonomy.$t
{{< code file=“grab-top-two-tags.html” >}}
{{< /code >}}Hugo’s templates are context aware and make a large number of values available to you as you’re creating views for your website.
The following is a list of site-level (aka “global”) variables. Many of these variables are defined in your site’s configuration file, whereas others are built into Hugo’s core for convenient usage in your templates.
.Site.AllPages
.Site.Author
.Site.BaseURL
.Site.BuildDrafts
false
) to indicate whether to build drafts as defined in the site configuration..Site.Copyright
.Site.Data
.Site.DisqusShortname
.Site.Files
.Site.GoogleAnalytics
.Site.IsMultiLingual
.Site.Language.Lang
en
)..Site.Language.LanguageName
English
)..Site.Language.Weight
.Site.Languages
list..Site.Language
.Site.LanguageCode
.Site.LanguagePrefix
.Site.Languages
.Site.LastChange
date
variable in the front matter of your content pages..Site.Menus
.Site.Pages
.Site.Permalinks
.Site.RegularPages
.Site.RegularPages
is equivalent to where .Site.Pages "Kind" "page"
..Site.RSSLink
.Site.Sections
.Site.Taxonomies
.Site.Indexes
since v0.11. Also see section Taxonomies elsewhere..Site.Title
.Site.Params
Variable.Site.Params
is a container holding the values from the params
section of your site configuration.
.Site.Params
The following config.toml
defines a site-wide param for description
:
baseURL = "http://yoursite.example.com/"
[params]
description = "Tesla's Awesome Hugo Site"
author = "Nikola Tesla"
You can use .Site.Params
in a partial template to call the default site description:
{{< code file=“layouts/partials/head.html” >}}
{{< /code >}}
config: /getting-started/configuration/
Shortcodes have access to parameters delimited in the shortcode declaration via .Get
, page- and site-level variables, and also the following shortcode-specific fields:
.Parent
.IsNamedParams
true
when the shortcode in question uses named rather than positional parameters.Inner
The following is a list of page-level variables. Many of these will be defined in the front matter, derived from file location, or extracted from the content itself.
{{% note “.Scratch
” %}}
See .Scratch
for page-scoped, writable variables.
{{% /note %}}
.AlternativeOutputFormats
link rel
list in your site’s <head>
. (See Output Formats.).Content
.Data
.Date
.Date
pulls from the date
field in a content’s front matter. See also .ExpiryDate
, .PublishDate
, and .Lastmod
..Description
.Draft
true
if the content is marked as a draft in the front matter..ExpiryDate
.ExpiryDate
pulls from the expirydate
field in a content’s front matter. See also .PublishDate
, .Date
, and .Lastmod
..FuzzyWordCount
.Hugo
.IsHome
true
in the context of the homepage..IsNode
false
for regular content pages..IsPage
true
for regular content pages..IsTranslated
true
if there are translations to display..Keywords
.Kind
page
, home
, section
, taxonomy
, or taxonomyTerm
. Note that there are also RSS
, sitemap
, robotsTXT
, and 404
kinds, but these are only available during the rendering of each of these respective page’s kind and therefore not available in any of the Pages
collections..Lang
.Language
config
..Lastmod
.Lastmod
pulls from the lastmod
field in a content’s front matter. If lastmod
is not set, Hugo will default to the date
field. See also .ExpiryDate
, .Date
, and .PublishDate
..LinkTitle
linktitle
from the front matter before title
..Next
publishdate
field in front matter)..NextInSection
publishdate
field in front matter)..OutputFormats
.Get
function to grab a specific format. (See Output Formats.).Pages
nil
for regular content pages. .Pages
is an alias for .Data.Pages
..Permalink
.Plain
.PlainWords
string
using Go’s strings.Fields
to split .Plain
into a slice..Prev
publishdate
in front matter)..PrevInSection
publishdate
in front matter). For example, {{if .PrevInSection}}{{.PrevInSection.Permalink}}{{end}}
..PublishDate
.Publishdate
pulls from the publishdate
field in a content’s front matter. See also .ExpiryDate
, .Date
, and .Lastmod
..RSSLink
.RawContent
.ReadingTime
.Ref
.Ref "sample.md"
). .Ref
does not handle in-page fragments correctly. See Cross References..RelPermalink
.RelRef
RelRef "sample.md"
). .RelRef
does not handle in-page fragments correctly. See Cross References..Section
.Site
.Summary
<!--more-->
at the appropriate place in the content page. See Content Summaries for more details..TableOfContents
.Title
.Translations
.Truncated
true
if the .Summary
is truncated. Useful for showing a “Read more…” link only when necessary. See Summaries for more information..Type
post
)..URL
url
set directly in front matter overrides the default relative URL for the rendered page..UniqueID
.Weight
.WordCount
Any other value defined in the front matter in a content file, including taxonomies, will be made available as part of the .Params
variable.
---
title: My First Post
date: date: 2017-02-20T15:26:23-06:00
categories: [one]
#tags: [two,three,four]
With the above front matter, the tags
and categories
taxonomies are accessible via the following:
.Params.tags
.Params.categories
{{% note “Casing of Params” %}}
Page-level .Params
are only accessible in lowercase.
{{% /note %}}
The .Params
variable is particularly useful for the introduction of user-defined front matter fields in content files. For example, a Hugo website on book reviews could have the following front matter in /content/review/book01.md
:
---
...
affiliatelink: "http://www.my-book-link.here"
recommendedby: "My Mother"
...
---
These fields would then be accessible to the /themes/yourtheme/layouts/review/single.html
template through .Params.affiliatelink
and .Params.recommendedby
, respectively.
Two common situations where this type of front matter field could be introduced is as a value of a certain attribute like href=""
or by itself to be displayed as text to the website’s visitors.
{{< code file=“/themes/yourtheme/layouts/review/single.html” >}}
It was recommended by {{ .Params.recommendedby }}.
{{< /code >}}This template would render as follows, assuming you’ve set uglyURLs
to false
in your site config
:
{{< output file=“yourbaseurl/review/book01/index.html” >}}
It was recommended by my Mother.
{{< /output >}}{{% note %}}
See Archetypes for consistency of Params
across pieces of content.
{{% /note %}}
.Param
MethodIn Hugo, you can declare params in individual pages and globally for your entire website. A common use case is to have a general value for the site param and a more specific value for some of the pages (i.e., a header image):
{{ $.Param "header_image" }}
The .Param
method provides a way to resolve a single value according to it’s definition in a page parameter (i.e. in the content’s front matter) or a site parameter (i.e., in your config
).
When front matter contains nested fields like the following:
---
author:
given_name: John
family_name: Feminella
display_name: John Feminella
---
.Param
can access these fields by concatenating the field names together with a dot:
{{ $.Param "author.display_name" }}
If your front matter contains a top-level key that is ambiguous with a nested key, as in the following case:
---
favorites.flavor: vanilla
favorites:
flavor: chocolate
---
The top-level key will be preferred. Therefore, the following method, when applied to the previous example, will print vanilla
and not chocolate
:
{{ $.Param "favorites.flavor" }}
=> vanilla
Taxonomytermspages
Page
and have the following additional variables.
For example, the following fields would be available in layouts/_defaults/terms.html
, depending on how you organize your taxonomytemplates
.Data.Singular
tags =>
tag`).Data.Plural
tags => tags
).Data.Pages
.Data.Terms
.Data.Terms.Alphabetical
.Data.Terms.ByCount
Note that .Data.Terms.Alphabetical
and .Data.Terms.ByCount
can also be reversed:
.Data.Terms.Alphabetical.Reverse
.Data.Terms.ByCount.Reverse
.Site.Taxonomies
Outside of Taxonomy TemplatesThe .Site.Taxonomies
variable holds all the taxonomies defined site-wide. .Site.Taxonomies
is a map of the taxonomy name to a list of its values (e.g., `“tags” -> “tag1”,“tag2”,“tag3”
.Taxonomy
VariableThe .Taxonomy
variable, available, for example, as .Site.Taxonomies.tags
, contains the list of tags (values) and, for each tag, their corresponding content pages.
.Site.Taxonomies
The following partial template will list all your site’s taxonomies, each of their keys, and all the content assigned to each of the keys. For more examples of how to order and render your taxonomies, see TaxonomyTemplates
{{< code file=“all-taxonomies-keys-and-pages.html” download=“all-taxonomies-keys-and-pages.html” >}}
taxonomytemplates
{{% note “Rendering Local Files” %}}
For information on creating shortcodes and templates that tap into Hugo’s file-related feature set, see Local File Templates.
{{% /note %}}
The .File
object contains the following fields:
.File.Path
content/posts/foo.en.md
).File.LogicalName
foo.en.md
).File.TranslationBaseName
foo
).File.BaseFileName
foo.en
).File.Ext
md
); this can also be called using .File.Extension
as well. Note that it is only the extension without .
..File.Lang
en
).File.Dir
content/posts/dir1/dir2/
, the relative directory path of the content file will be returned (e.g., posts/dir1/dir2/
)Multilingual: /content-management/multilingual/
The menutemplate
.URL
.Name
.Menu
.Identifier
.Pre
.Post
.Weight
.Parent
.Children
menutemplate
It contains the following fields:
.Hugo.Generator
<meta>
tag for the version of Hugo that generated the site. .Hugo.Generator
outputs a complete HTML tag; e.g. <meta name="generator" content="Hugo 0.18" />
.Hugo.Version
0.13-DEV
.Hugo.CommitHash
0e8bed9ccffba0df554728b46c5bbf6d78ae5247
.Hugo.BuildDate
2002-10-02T10:00:00-05:00
{{% note “Use the Hugo Generator Tag” %}}
We highly recommend using .Hugo.Generator
in your website’s <head>
. .Hugo.Generator
is included by default in all themes hosted on themes.gohugo.io. The generator tag allows the Hugo team to track the usage and popularity of Hugo.
{{% /note %}}
{{% note “.GitInfo
Performance Considerations” %}}
Hugo’s Git integrations should be fairly performant but can increase your build time. This will depend on the size of your Git history.
{{% /note %}}
.GitInfo
PrerequisitesPATH
..GitInfo
feature must be enabled in your Hugo project by passing --enableGitInfo
flag on the command line or by setting enableGitInfo
to true
in your site’s configuration file..GitInfo
ObjectThe GitInfo
object contains the following fields:
.AbbreviatedHash
866cbcc
).AuthorName
.mailmap
.AuthorEmail
.mailmap
.AuthorDate
.Hash
866cbccdab588b9908887ffd3b4f2667e94090c3
).Subject
tpl: Add custom index function
)A sitemap is a Page
and therefore has all the page variables available to use sitemap templates. They also have the following sitemap-specific variables available to them:
.Sitemap.ChangeFreq
.Sitemap.Priority
.Sitemap.Filename
pagevars: /variables/page/
The following list contains auto-generated and up-to-date (thanks to Cobra) documentation for all the CLI commands in Hugo.
Print the version number of Hugo
All software has versions. This is Hugo’s.
hugo version [flags]
-h, --help help for version
--config string config file (default is path/config.yaml|json|toml)
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--quiet build in quiet mode
-v, --verbose verbose output
--verboseLog verbose logging
Undraft resets the content’s draft status
Undraft resets the content’s draft status
and updates the date to the current date and time.
If the content’s draft status is ‘False’, nothing is done.
hugo undraft path/to/content [flags]
-h, --help help for undraft
--config string config file (default is path/config.yaml|json|toml)
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--quiet build in quiet mode
-v, --verbose verbose output
--verboseLog verbose logging
A high performance webserver
Hugo provides its own webserver which builds and serves the site.
While hugo server is high performance, it is a webserver with limited options.
Many run it in production, but the standard behavior is for people to use it
in development and use a more full featured server such as Nginx or Caddy.
‘hugo server’ will avoid writing the rendered and served content to disk,
preferring to store it in memory.
By default hugo will also watch your files for any changes you make and
automatically rebuild the site. It will then live reload any open browser pages
and push the latest content to them. As most Hugo sites are built in a fraction
of a second, you will be able to save and see your changes nearly instantly.
hugo server [flags]
--appendPort append port to baseURL (default true)
-b, --baseURL string hostname (and path) to the root, e.g. http://spf13.com/
--bind string interface to which the server will bind (default "127.0.0.1")
-D, --buildDrafts include content marked as draft
-E, --buildExpired include expired content
-F, --buildFuture include content with publishdate in the future
--cacheDir string filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache/
--canonifyURLs if true, all relative URLs will be canonicalized using baseURL
--cleanDestinationDir remove files from destination not found in static directories
-c, --contentDir string filesystem path to content directory
-d, --destination string filesystem path to write files to
--disable404 do not render 404 page
--disableKinds stringSlice disable different kind of pages (home, RSS etc.)
--disableLiveReload watch without enabling live browser reload on rebuild
--disableRSS do not build RSS files
--disableSitemap do not build Sitemap file
--enableGitInfo add Git revision, date and author info to the pages
--forceSyncStatic copy all files when static is changed.
-h, --help help for server
--i18n-warnings print missing translations
--ignoreCache ignores the cache directory
-l, --layoutDir string filesystem path to layout directory
--meminterval string interval to poll memory usage (requires --memstats), valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". (default "100ms")
--memstats string log memory usage to this file
--navigateToChanged navigate to changed content file on live browser reload
--noChmod don't sync permission mode of files
--noTimes don't sync modification time of files
--pluralizeListTitles pluralize titles in lists using inflect (default true)
-p, --port int port on which the server will listen (default 1313)
--preserveTaxonomyNames preserve taxonomy names as written ("Gérard Depardieu" vs "gerard-depardieu")
--renderToDisk render to Destination path (default is render to memory & serve from there)
-s, --source string filesystem path to read files relative from
--stepAnalysis display memory and timing of different steps of the program
-t, --theme string theme to use (located in /themes/THEMENAME/)
--themesDir string filesystem path to themes directory
--uglyURLs if true, use /filename.html instead of /filename/
-w, --watch watch filesystem for changes and recreate as needed (default true)
--config string config file (default is path/config.yaml|json|toml)
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--quiet build in quiet mode
-v, --verbose verbose output
--verboseLog verbose logging
Create a new theme
Create a new theme (skeleton) called name
hugo new theme [name] [flags]
-h, --help help for theme
--config string config file (default is path/config.yaml|json|toml)
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
-v, --verbose verbose output
--verboseLog verbose logging
Create a new site (skeleton)
Create a new site in the provided directory.
The new site will have the correct structure, but no content or theme yet.
Use hugo new contentPath
to create new content.
hugo new site [path] [flags]
--force init inside non-empty directory
-f, --format string config & frontmatter format (default "toml")
-h, --help help for site
--config string config file (default is path/config.yaml|json|toml)
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
-v, --verbose verbose output
--verboseLog verbose logging
Create new content for your site
Create a new content file and automatically set the date and title.
It will guess which kind of file to create based on the path provided.
You can also specify the kind with -k KIND
.
If archetypes are provided in your theme or site, they will be used.
hugo new [path] [flags]
--editor string edit new content with this editor, if provided
-h, --help help for new
-k, --kind string content type to create
-s, --source string filesystem path to read files relative from
--config string config file (default is path/config.yaml|json|toml)
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--quiet build in quiet mode
-v, --verbose verbose output
--verboseLog verbose logging
List all posts dated in the future
List all of the posts in your content directory which will be
posted in the future.
hugo list future [flags]
-h, --help help for future
--config string config file (default is path/config.yaml|json|toml)
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
-v, --verbose verbose output
--verboseLog verbose logging
List all posts already expired
List all of the posts in your content directory which has already
expired.
hugo list expired [flags]
-h, --help help for expired
--config string config file (default is path/config.yaml|json|toml)
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
-v, --verbose verbose output
--verboseLog verbose logging
List all drafts
List all of the drafts in your content directory.
hugo list drafts [flags]
-h, --help help for drafts
--config string config file (default is path/config.yaml|json|toml)
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
-v, --verbose verbose output
--verboseLog verbose logging
Listing out various types of content
Listing out various types of content.
List requires a subcommand, e.g. hugo list drafts
.
-h, --help help for list
-s, --source string filesystem path to read files relative from
--config string config file (default is path/config.yaml|json|toml)
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--quiet build in quiet mode
-v, --verbose verbose output
--verboseLog verbose logging
hugo import from Jekyll
hugo import from Jekyll.
Import from Jekyll requires two paths, e.g. hugo import jekyll jekyll_root_path target_path
.
hugo import jekyll [flags]
--force allow import into non-empty target directory
-h, --help help for jekyll
--config string config file (default is path/config.yaml|json|toml)
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--quiet build in quiet mode
-v, --verbose verbose output
--verboseLog verbose logging
Import your site from others.
Import your site from other web site generators like Jekyll.
Import requires a subcommand, e.g. hugo import jekyll jekyll_root_path target_path
.
-h, --help help for import
--config string config file (default is path/config.yaml|json|toml)
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--quiet build in quiet mode
-v, --verbose verbose output
--verboseLog verbose logging
Generate man pages for the Hugo CLI
This command automatically generates up-to-date man pages of Hugo’s
command-line interface. By default, it creates the man page files
in the “man” directory under the current directory.
hugo gen man [flags]
--dir string the directory to write the man pages. (default "man/")
-h, --help help for man
--config string config file (default is path/config.yaml|json|toml)
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--quiet build in quiet mode
-v, --verbose verbose output
--verboseLog verbose logging
Generate Markdown documentation for the Hugo CLI.
Generate Markdown documentation for the Hugo CLI.
This command is, mostly, used to create up-to-date documentation
of Hugo’s command-line interface for http://gohugo.io/.
It creates one Markdown file per command with front matter suitable
for rendering in Hugo.
hugo gen doc [flags]
--dir string the directory to write the doc. (default "/tmp/hugodoc/")
-h, --help help for doc
--config string config file (default is path/config.yaml|json|toml)
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--quiet build in quiet mode
-v, --verbose verbose output
--verboseLog verbose logging
Generate shell autocompletion script for Hugo
Generates a shell autocompletion script for Hugo.
NOTE: The current version supports Bash only.
This should work for *nix systems with Bash installed.
By default, the file is written directly to /etc/bash_completion.d
for convenience, and the command may need superuser rights, e.g.:
$ sudo hugo gen autocomplete
Add --completionfile=/path/to/file
flag to set alternative
file-path and name.
Logout and in again to reload the completion scripts,
or just source them in directly:
$ . /etc/bash_completion
hugo gen autocomplete [flags]
--completionfile string autocompletion file (default "/etc/bash_completion.d/hugo.sh")
-h, --help help for autocomplete
--type string autocompletion type (currently only bash supported) (default "bash")
--config string config file (default is path/config.yaml|json|toml)
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--quiet build in quiet mode
-v, --verbose verbose output
--verboseLog verbose logging
A collection of several useful generators.
A collection of several useful generators.
-h, --help help for gen
--config string config file (default is path/config.yaml|json|toml)
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--quiet build in quiet mode
-v, --verbose verbose output
--verboseLog verbose logging
Print Hugo version and environment info
Print Hugo version and environment info. This is useful in Hugo bug reports.
hugo env [flags]
-h, --help help for env
--config string config file (default is path/config.yaml|json|toml)
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--quiet build in quiet mode
-v, --verbose verbose output
--verboseLog verbose logging
Convert front matter to YAML
toYAML converts all front matter in the content directory
to use YAML for the front matter.
hugo convert toYAML [flags]
-h, --help help for toYAML
--config string config file (default is path/config.yaml|json|toml)
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
-o, --output string filesystem path to write files to
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
--unsafe enable less safe operations, please backup first
-v, --verbose verbose output
--verboseLog verbose logging
Convert front matter to TOML
toTOML converts all front matter in the content directory
to use TOML for the front matter.
hugo convert toTOML [flags]
-h, --help help for toTOML
--config string config file (default is path/config.yaml|json|toml)
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
-o, --output string filesystem path to write files to
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
--unsafe enable less safe operations, please backup first
-v, --verbose verbose output
--verboseLog verbose logging
Convert front matter to JSON
toJSON converts all front matter in the content directory
to use JSON for the front matter.
hugo convert toJSON [flags]
-h, --help help for toJSON
--config string config file (default is path/config.yaml|json|toml)
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
-o, --output string filesystem path to write files to
--quiet build in quiet mode
-s, --source string filesystem path to read files relative from
--unsafe enable less safe operations, please backup first
-v, --verbose verbose output
--verboseLog verbose logging
Convert your content to different formats
Convert your content (e.g. front matter) to different formats.
See convert’s subcommands toJSON, toTOML and toYAML for more information.
-h, --help help for convert
-o, --output string filesystem path to write files to
-s, --source string filesystem path to read files relative from
--unsafe enable less safe operations, please backup first
--config string config file (default is path/config.yaml|json|toml)
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--quiet build in quiet mode
-v, --verbose verbose output
--verboseLog verbose logging
Print the site configuration
Print the site configuration, both default and custom settings.
hugo config [flags]
-h, --help help for config
--config string config file (default is path/config.yaml|json|toml)
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--quiet build in quiet mode
-v, --verbose verbose output
--verboseLog verbose logging
Check system ulimit settings
Hugo will inspect the current ulimit settings on the system.
This is primarily to ensure that Hugo can watch enough files on some OSs
hugo check ulimit [flags]
-h, --help help for ulimit
--config string config file (default is path/config.yaml|json|toml)
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--quiet build in quiet mode
-v, --verbose verbose output
--verboseLog verbose logging
Contains some verification checks
Contains some verification checks
-h, --help help for check
--config string config file (default is path/config.yaml|json|toml)
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--quiet build in quiet mode
-v, --verbose verbose output
--verboseLog verbose logging
Benchmark Hugo by building a site a number of times.
Hugo can build a site many times over and analyze the running process
creating a benchmark.
hugo benchmark [flags]
-b, --baseURL string hostname (and path) to the root, e.g. http://spf13.com/
-D, --buildDrafts include content marked as draft
-E, --buildExpired include expired content
-F, --buildFuture include content with publishdate in the future
--cacheDir string filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache/
--canonifyURLs if true, all relative URLs will be canonicalized using baseURL
--cleanDestinationDir remove files from destination not found in static directories
-c, --contentDir string filesystem path to content directory
-n, --count int number of times to build the site (default 13)
--cpuprofile string path/filename for the CPU profile file
-d, --destination string filesystem path to write files to
--disable404 do not render 404 page
--disableKinds stringSlice disable different kind of pages (home, RSS etc.)
--disableRSS do not build RSS files
--disableSitemap do not build Sitemap file
--enableGitInfo add Git revision, date and author info to the pages
--forceSyncStatic copy all files when static is changed.
-h, --help help for benchmark
--i18n-warnings print missing translations
--ignoreCache ignores the cache directory
-l, --layoutDir string filesystem path to layout directory
--memprofile string path/filename for the memory profile file
--noChmod don't sync permission mode of files
--noTimes don't sync modification time of files
--pluralizeListTitles pluralize titles in lists using inflect (default true)
--preserveTaxonomyNames preserve taxonomy names as written ("Gérard Depardieu" vs "gerard-depardieu")
--renderToMemory render to memory (only useful for benchmark testing)
-s, --source string filesystem path to read files relative from
--stepAnalysis display memory and timing of different steps of the program
-t, --theme string theme to use (located in /themes/THEMENAME/)
--themesDir string filesystem path to themes directory
--uglyURLs if true, use /filename.html instead of /filename/
--config string config file (default is path/config.yaml|json|toml)
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--quiet build in quiet mode
-v, --verbose verbose output
--verboseLog verbose logging
hugo builds your site
hugo 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/.
hugo [flags]
-b, --baseURL string hostname (and path) to the root, e.g. http://spf13.com/
-D, --buildDrafts include content marked as draft
-E, --buildExpired include expired content
-F, --buildFuture include content with publishdate in the future
--cacheDir string filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache/
--canonifyURLs if true, all relative URLs will be canonicalized using baseURL
--cleanDestinationDir remove files from destination not found in static directories
--config string config file (default is path/config.yaml|json|toml)
-c, --contentDir string filesystem path to content directory
-d, --destination string filesystem path to write files to
--disable404 do not render 404 page
--disableKinds stringSlice disable different kind of pages (home, RSS etc.)
--disableRSS do not build RSS files
--disableSitemap do not build Sitemap file
--enableGitInfo add Git revision, date and author info to the pages
--forceSyncStatic copy all files when static is changed.
-h, --help help for hugo
--i18n-warnings print missing translations
--ignoreCache ignores the cache directory
-l, --layoutDir string filesystem path to layout directory
--log enable Logging
--logFile string log File path (if set, logging enabled automatically)
--noChmod don't sync permission mode of files
--noTimes don't sync modification time of files
--pluralizeListTitles pluralize titles in lists using inflect (default true)
--preserveTaxonomyNames preserve taxonomy names as written ("Gérard Depardieu" vs "gerard-depardieu")
--quiet build in quiet mode
--renderToMemory render to memory (only useful for benchmark testing)
-s, --source string filesystem path to read files relative from
--stepAnalysis display memory and timing of different steps of the program
-t, --theme string theme to use (located in /themes/THEMENAME/)
--themesDir string filesystem path to themes directory
--uglyURLs if true, use /filename.html instead of /filename/
-v, --verbose verbose output
--verboseLog verbose logging
-w, --watch watch filesystem for changes and recreate as needed
The Troubleshooting section includes known issues, recent workarounds, and FAQs pulled from the Hugo Discussion Forum.
hugo new
Aborts with EOF errorI’m running into an issue where I cannot get archetypes working, when running
hugo new showcase/test.md
, for example, I see anEOF
error thrown by Hugo.When I run Hugo with v0.12 via
hugo new -v showcase/test.md
, I see the following output:INFO: 2015/01/04 Using config file: /private/tmp/test/config.toml INFO: 2015/01/04 attempting to create showcase/test.md of showcase INFO: 2015/01/04 curpath: /private/tmp/test/archetypes/showcase.md ERROR: 2015/01/04 EOF
Is there something that I am blatantly missing?
The solution is to add a final newline (i.e., EOL
) to the end of your default.md archetype file of your theme. You can do this by adding a carriage return after the closing +++
or ---
of your TOML or YAML front matter, respectively.
{{% note “Final EOL Unnecessary in v0.13+” %}}
As of v0.13, Hugo’s parser has been enhanced to accommodate archetype files without final EOL thanks to the great work by @tatsushid.
{{% /note %}}
One of my categories is named “Le-carré,” but the link ends up being generated like this:
categories/le-carr%C3%A9
And not working. Is there an easy fix for this that I’m overlooking?
Are you a macOS user? If so, you are likely a victim of HFS Plus file system’s insistence to store the “é” (U+00E9) character in Normal Form Decomposed (NFD) mode, i.e. as “e” + " ́" (U+0065 U+0301).
le-carr%C3%A9
is actually correct, %C3%A9
being the UTF-8 version of U+00E9 as expected by the web server. The problem is that OS X turns U+00E9
le-carr%C3%A9
no longer works. Instead, only le-carre%CC%81
ending with e%CC%81
would match that U+0065U+0301This is unique to OS X. The rest of the world does not do this, and most certainly not your web server which is most likely running Linux. This is not a Hugo-specific problem either. Other people have been bitten by this when they have accented characters in their HTML files.
Note that this problem is not specific to Latin scripts. Japanese Mac users often run into the same issue; e.g., with だ
decomposing into た
and ゙
. (Read the Japanese Perl users article).
Rsync 3.x to the rescue! From an answer posted on Server Fault:
You can use rsync’s
--iconv
option to convert between UTF-8 NFC & NFD, at least if you’re on a Mac. There is a specialutf-8-mac
character set that stands for UTF-8 NFD. So to copy files from your Mac to your web server, you’d need to run something like:
rsync -a --iconv=utf-8-mac,utf-8 localdir/ mywebserver:remotedir/
This will convert all the local filenames from UTF-8 NFD to UTF-8 NFC on the remote server. The files’ contents won’t be affected. - Server Fault
Please make sure you have the latest version of rsync 3.x installed. The rsync that ships with OS X is outdated. Even the version that comes packaged with 10.10 (Yosemite) is version 2.6.9 protocol version 29. The --iconv
flag is new in rsync 3.x.
One of Hugo’s greatest strengths is it’s passionate—and always evolving—developer community. With the exception of the highlight
shortcode mentioned in Syntax Highlighting, the tools and other projects featured in this section are offerings from both commercial services and open-source projects, many of which are developed by Hugo developers just like you.
See the popularity of Hugo compared with other static site generators.
This section highlights some projects around Hugo that are independently developed. These tools try to extend the functionality of our static site generator or help you to get started.
{{% note %}}
Do you know or maintain a similar project around Hugo? Feel free to open a pull request on GitHub if you think it should be added.
{{% /note %}}
Take a look at this list of migration tools if you currently use other logging tools like Jekyll or WordPress but intend to switch to Hugo instead. They’ll take care to export your content into Hugo-friendly formats.
Alternatively, you can use the new Jekyll import command.
Hugo can highlight source code in two different ways—either pre-processed server side from your content or to defer the processing to the client side, using a JavaScript library.
For the pre-processed approach, highlighting is performed by an external Python-based program called Pygments and is triggered via an embedded Hugo shortcode (see example below). If Pygments is absent from the path, it will silently simply pass the content along without highlighting.
The advantages of server-side syntax highlighting are that it doesn’t depend on a JavaScript library and, consequently, works very well when read from an RSS feed.
If you have never worked with Pygments before, here is a brief primer:
pip install Pygments
in order to install Pygments. Once installed, Pygments gives you a command pygmentize
. Make sure it sits in your PATH; otherwise, Hugo will not be able to find and use it.On Debian and Ubuntu systems, you may also install Pygments by running sudo apt-get install python3-pygments
.
Hugo gives you two options that you can set with the variable pygmentsuseclasses
(default false
) in your site configuration.
pygmentsuseclasses = false
(default). The color codes depend on your choice of the pygmentsstyle
(default = "monokai"
). You can explore the different color styles on pygments.org after inserting some example code.pygmentsuseclasses = true
, Hugo includes class names in your code instead of color codes. For class-names to be meaningful, you need to include a .css
file in your website representing your color scheme. You can either generate this .css
files according to the description from the Pygments documentation or download the one of the many pre-built color schemes from Pygment’s GitHub css repository.Highlighting is carried out via the built-in shortcode highlight
. highlight
takes exactly one required parameter for the programming language to be highlighted and requires a closing shortcode. Note that highlight
is not used for client-side javascript highlighting.
highlight
Shortcode Input{{< code file=“example-highlight-shortcode-input.md” >}}
{{</* highlight html */>}}
highlight
Shortcode Output{{< output file=“example-highlight-shortcode-output.html” >}}
<section id=“main”>
<div>
<h1 id=“title”>{{ .Title }}</h1>
{{ range .Data.Pages }}
{{ .Render “summary”}}
{{ end }}
</div>
</section>
{{< /output >}}
Options for controlling highlighting can be added in the second argument as a quoted, comma-separated key-value list. The example below will syntax highlight in go
with inline line numbers and line numbers 2 and 3 highlighted.
{{</* highlight go "linenos=inline,hl_lines=2 3" */>}}
var a string
var b string
var c string
var d string
{{</* / highlight */>}}
The highlight
shortcode includes the following supported keywords:
style
encoding
noclasses
hl_lines
linenos
Note that style
and noclasses
will override the similar setting in the global config.
The keywords in the highlight
shortcode mirror those of Pygments from the command line. See the Pygments documentation for more information.
It is also possible to add syntax highlighting with GitHub flavored code fences. To enable this, set the PygmentsCodeFences
to true
in Hugo’s configuration file;
{{% note “Disclaimers on Pygments” %}}
--ignoreCache
flag to true
.Alternatively, code highlighting can be applied to your code blocks in client-side JavaScript.
Client-side syntax highlighting is very simple to add. You’ll need to pick
a library and a corresponding theme. Some popular libraries are:
The advantages of client-side syntax highlighting are that it doesn’t cost anything when building your site, and some of the highlighting scripts available cover more languages than Pygments does.
This example uses the popular Highlight.js library, hosted by Yandex
In your ./layouts/partials/
(or ./layouts/chrome/
) folder, depending on your specific theme, there will be a snippet that will be included in every generated HTML page, such as header.html
or header.includes.html
. Simply add the css and js to initialize Highlight.js:
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.6.0/styles/default.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.6.0/highlight.min.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
Prism is another popular highlighter library and is used on some major sites.
The download section of the prism.js website is simple to use and affords you a high degree of customization to pick only the languages you’ll be using on your site.
Similar to Highlight.js, you simply load prism.css
in your <head>
via whatever Hugo partial template is creating that part of your pages:
...
<link href="/css/prism.css" rel="stylesheet" />
...
Add prism.js
near the bottom of your <body>
tag in whatever Hugo partial template is appropriate for your site or theme.
...
<script src="/js/prism.js"></script>
</body>
In this example, the local paths indicate that your downloaded copy of these files are being added to the site, typically under ./static/css/
and ./static/js/
, respectively.
To use client-side highlighting, most of these javascript libraries expect your code to be wrapped in semantically correct <code>
elements with language-specific class attributes. For example, a code block for HTML would have class="language-html"
.
The client-side highlighting script therefore looks for programming language classes according to this convention: language-go
, language-html
, language-css
, language-bash
, etc. If you look at the page’s source, you might see something like the following:
<pre>
<code class="language-css">
body {
font-family: "Noto Sans", sans-serif;
}
</code>
</pre>
If you are using markdown, your content pages needs to use the following syntax, with the name of the language to be highlighted entered directly after the first “fence.” A fenced code block can be noted by opening and closing triple tilde ~ or triple back ticks `:
{{< nohighlight >}}
body {
font-family: "Noto Sans", sans-serif;
}
{{< /nohighlight >}}
Here is the same example but with triple back ticks to denote the fenced code block:
{{< nohighlight >}}
body {
font-family: "Noto Sans", sans-serif;
}
{{< /nohighlight >}}
Passing the above examples through the highlighter script would yield the following markup:
{{< nohighlight >}}
<pre><code class=“language-css hljs”>;<span class=“hljs-selector-tag”>body</span> {
<span class=“hljs-attribute”>font-family</span>: <span class=“hljs-string”>“Noto Sans”</span>, sans-serif;
}
{{< /nohighlight >}}
In the case of the coding color scheme used by the Hugo docs, the resulting output would then look like the following to the website’s end users:
body {
font-family: "Noto Sans", sans-serif;
}
Please see individual libraries’ documentation for how to implement each of the JavaScript-based libraries.
Yandex
Know of a Hugo-related starter kit that isn’t mentioned here? Please add it to the list.
{{% note “Starter Kits are Not Maintained by the Hugo Team”%}}
The following starter kits are developed by active members of the Hugo community. If you find yourself having issues with any of the projects, it’s best to file an issue directly with the project’s maintainer(s).
{{% /note %}}
VictorHugo
caddy-hugo
is an add-on for Caddy that delivers a good UI to edit the content of your Hugo website.The Hugo community uses a wide range of preferred tools and has developed plug-ins for some of the most popular text editors to help automate parts of your workflow.
formats: /content-management/formats/
A static website with a dynamic search function? Yes. As alternatives to embeddable scripts from Google or other search engines, you can provide your visitors a custom search by indexing your content files directly.
And for all the other small things around Hugo:
Because Hugo renders static websites, you can host your new Hugo website virtually anywhere. The following represent only a few of the more popular hosting and automated deployment solutions used by the Hugo community.
Netlify provides continuous deployment services, global CDN, ultra-fast DNS, atomic deploys, instant cache invalidation, one-click SSL, a browser-based interface, a CLI, and many other features for managing your Hugo website.
Go to app.netlify.com and select your preferred signup method. This will likely be a hosted Git provider, although you also have the option to sign up with an email address.
The following examples use GitHub, but other git providers will follow a similar process.
Selecting GitHub will bring up a typical modal you’ve seen through other application that use GitHub for authentication. Select “Authorize application.”
You’re now already a Netlify member and should be brought to your new dashboard. Select “New site from git.”
Netlify will then start walking you through the steps necessary for continuous deployment. First, you’ll need to select your git provider again, but this time you are giving Netlify added permissions to your repositories.
And then again with the GitHub authorization modal:
Select the repo you want to use for continuous deployment. If you have a large number of repositories, you can filter through them in real time using repo search:
Once selected, you’ll be brought to a screen for basic setup. Here you can select the branch you wanted published, your build command, and your publish (i.e. deploy) directory. The publish directory should mirror that of what you’ve set in your site configuration, the default of which is public
. The following steps assume you are publishing from the master
branch.
Setting the build command to hugo
will build your site according to the current default Hugo version used by Netlify. You can see the full list of available Hugo versions in Netlify’s Docker file.
If you want to tell Netlify to build with a specific version, you can append an underscore followed by the version number to the build command:
hugo_0.19
Your simple configuration should now look similar to the following:
Selecting “Deploy site” will immediately take you to a terminal for your build:.
Once the build is finished—this should only take a few seconds–you should now see a “Hero Card” at the top of your screen letting you know the deployment is successful. The Hero Card is the first element that you see in most pages. It allows you to see a quick summary of the page and gives access to the most common/pertinent actions and information. You’ll see that the URL is automatically generated by Netlify. You can update the URL in “Settings.”
Now every time you push changes to your hosted git repository, Netlify will rebuild and redeploy your site.
The git clone
method for installing themes is not supported by Netlify. If you were to use git clone
, it would require you to recursively remove the .git
subdirectory from the theme folder and would therefore prevent compatibility with future versions of the theme.
A better approach is to install a theme as a proper git submodule. You can read the GitHub documentation for submodules or those found on Git’s website for more information, but the command is similar to that of git clone
:
cd themes
git submodule add https://github.com/<THEMECREATOR>/<THEMENAME>
You now have a live website served over https, distributed through CDN, and configured for continuous deployment. Dig deeper into the Netlify documentation:
Go to the Firebase console and create a new project (unless you already have a project). You will need to globally install firebase-tools
(node.js):
npm install -g firebase-tools
Log in to Firebase (setup on your local machine) using firebase login
, which opens a browser where you can select your account. Use firebase logout
in case you are already logged in but to the wrong account.
firebase login
In the root of your Hugo project, initialize the Firebase project with the firebase init
command:
firebase init
From here:
public
To deploy your Hugo site, execute the firebase deploy
command, and your site will be up in no time:
hugo && firebase deploy
You can generate a deploy token using
firebase login:ci
You can also set up your CI (e.g., with Wercker) and add the token to a private variable like $FIREBASE_DEPLOY_TOKEN
.
{{% note %}}
This is a private secret and it should not appear in a public repository. Make sure you understand your chosen CI and that it’s not visible to others.
{{% /note %}}
You can then add a step in your build to do the deployment using the token:
firebase deploy --token $FIREBASE_DEPLOY_TOKEN
GitHub provides free and fast static hosting over SSL for personal, organization, or project pages directly from a GitHub repository via its GitHub Pages service.
If you are working within an Organization account or want to set up a User website on GitHub and would like more information, refer to the GitHub Pages documentation.
{{% note %}}
Make sure your baseURL
key-value in your site configuration reflects the full URL of your GitHub pages repository if you’re using the default GH Pages URL (e.g., username.github.io/myprojectname/
) and not a custom domain.
{{% /note %}}
/docs
Folder on Master BranchAs described in the GitHub Pages documentation, you can deploy from a folder called docs/
on your master branch. To effectively use this feature with Hugo, you need to change the Hugo publish directory in your site’s config.toml
and config.yaml
, respectively:
publishDir: docs
publishDir = "docs"
After running hugo
, push your master branch to the remote repository and choose the docs/
folder as the website source of your repo. Do the following from within your GitHub project:
docs/
folder in the root of your project.{{% note %}}
The docs/
option is the simplest approach but requires you set a publish directory in your site configuration. You cannot currently configure GitHub pages to publish from another directory on master, and not everyone prefers the output site live concomitantly with source files in version control.
{{% /note %}}
gh-pages
BranchYou can also tell GitHub pages to treat your master
branch as the published site or point to a separate gh-pages
branch. The latter approach is a bit more complex but has some advantages:
docs/
option, it uses the default public
folder.gh-pages
BranchThese steps only need to be done once. Replace upstream
with the name of your remote; e.g., origin
:
First, add the public
folder to your .gitignore
file at the project root so that the directory is ignored on the master branch:
echo "public" >> .gitignore
gh-pages
BranchYou can now initialize your gh-pages
branch as an empty orphan branch:
git checkout --orphan gh-pages
git reset --hard
git commit --allow-empty -m "Initializing gh-pages branch"
git push upstream gh-pages
git checkout master
Now check out the gh-pages
branch into your public
folder using git’s worktree feature. Essentially, the worktree allows you to have multiple branches of the same local repository to be checked out in different directories:
rm -rf public
git worktree add -B gh-pages public upstream/gh-pages
Regenerate the site using the hugo
command and commit the generated files on the gh-pages
branch:
{{< code file=“commit-gh-pages-files.sh”>}}
hugo
cd public && git add --all && git commit -m “Publishing to gh-pages” && cd …
{{< /code >}}
If the changes in your local gh-pages
branch look alright, push them to the remote repo:
git push upstream gh-pages
gh-pages
as Your Publish BranchIn order to use your gh-pages
branch as your publishing branch, you’ll need to configure the repository within the GitHub UI. This will likely happen automatically once GitHub realizes you’ve created this branch. You can also set the branch manually from within your GitHub project:
After a short while, you’ll see the updated contents on your GitHub Pages site.
To automate these steps, you can create a script with the following contents:
{{< code file=“publish_to_ghpages.sh” >}}
#!/bin/sh
DIR=(dirname“0”)
cd $DIR/…
if [$(gitstatus−s)
echo “Deleting old publication”
rm -rf public
mkdir public
git worktree prune
rm -rf .git/worktrees/public/
echo “Checking out gh-pages branch into public”
git worktree add -B gh-pages public upstream/gh-pages
echo “Removing existing files”
rm -rf public/*
echo “Generating site”
hugo
echo “Updating gh-pages branch”
cd public && git add --all && git commit -m “Publishing to gh-pages (publish.sh)”
{{< /code >}}
This will abort if there are pending changes in the working directory and also makes sure that all previously existing output files are removed. Adjust the script to taste, e.g. to include the final push to the remote repository if you don’t need to take a look at the gh-pages branch before pushing. Or adding echo yourdomainname.com >> CNAME
if you set up for your gh-pages to use customize domain.
master
BranchTo use master
as your publishing branch, you’ll need your rendered website to live at the root of the GitHub repository. Steps should be similar to that of the gh-pages
branch, with the exception that you will create your GitHub repository with the public
directory as the root. Note that this does not provide the same benefits of the gh-pages
branch in keeping your source and output in separate, but version controlled, branches within the same repo.
You will also need to set master
as your publishable branch from within the GitHub UI:
As mentioned in this GitHub Help article, you can host a user/organization page in addition to project pages. Here are the key differences in GitHub Pages websites for Users and Organizations:
<USERNAME>.github.io
naming scheme for your GitHub repo.master
branch will be used to publish your GitHub Pages site.It becomes much simpler in this case: we’ll create two separate repos, one for Hugo’s content, and a git submodule with the public
folder’s content in it.
<YOUR-PROJECT>
git repository on GitHub. This repository will contain Hugo’s content and other source files.<USERNAME>.github.io
GitHub repository. This is the repository that will contain the fully rendered version of your Hugo website.git clone <YOUR-PROJECT-URL> && cd <YOUR-PROJECT>
hugo server
or hugo server -t <YOURTHEME>
) and open your browser to http://localhost:1313.rm -rf public
to completely remove the public
directory if theregit submodule add -b master git@github.com:<USERNAME>/<USERNAME>.github.io.git public
. This creates a git submodule. Now when you run the hugo
command to build your site to public
, the created public
directory will have a different remote origin (i.e. hosted GitHub repository). You can automate some of these steps with the following script.You’re almost done. You can also add a deploy.sh
script to automate the preceding steps for you. You can also make it executable with chmod +x deploy.sh
.
The following are the contents of the deploy.sh
script:
#!/bin/bash
echo -e "\033[0;32mDeploying updates to GitHub...\033[0m"
# Build the project.
hugo # if using a theme, replace with `hugo -t <YOURTHEME>`
# Go To Public folder
cd public
# Add changes to git.
git add .
# Commit changes.
msg="rebuilding site `date`"
if [ $# -eq 1 ]
then msg="$1"
fi
git commit -m "$msg"
# Push source and build repos.
git push origin master
# Come Back up to the Project Root
cd ..
You can then run ./deploy.sh "Your optional commit message"
to send changes to <USERNAME>.github.io
. Note that you likely will want to commit changes to your <YOUR-PROJECDT>
repository as well.
That’s it! Your personal page should be up and running at https://yourusername.github.io
within a couple minutes.
If you’d like to use a custom domain for your GitHub Pages site, create a file static/CNAME
. Your custom domain name should be the only contents inside CNAME
. Since it’s inside static
, the published site will contain the CNAME file at the root of the published site, which is a requirements of GitHub Pages.
Refer to the official documentation for custom domains for further information.
GitLab makes it incredibly easy to build, deploy, and host your Hugo website via their free GitLab Pages service, which provides native support for Hugo, as well as numerous other static site generators.
cd your-hugo-site
In the root directory of your Hugo site, create a .gitlab-ci.yml
file. The .gitlab-ci.yml
configures the GitLab CI on how to build your page. Simply add the content below.
{{< code file=“gitlab-ci.yml” >}}
image: publysher/hugo
pages:
script:
Next, create a new repository on GitLab. It is not necessary to make the repository public. In addition, you might want to add /public
to your .gitignore file, as there is no need to push compiled assets to GitLab or keep your output website in version control.
# initialize new git repository
git init
# add /public directory to our .gitignore file
echo "/public" >> .gitignore
# commit and push code to master branch
git add .
git commit -m "Initial commit"
git remote add origin https://gitlab.com/YourUsername/your-hugo-site.git
git push -u origin master
That’s it! You can now follow the CI agent building your page at https://gitlab.com/
After the build has passed, your new website is available at https://<YourUsername>.gitlab.io/<your-hugo-site>/
.
GitLab supports using custom CNAME’s and TLS certificates. For more details on GitLab Pages, see the GitLab Pages setup documentation.
You can use Bitbucket and Aerobatic to build, deploy, and host a Hugo website. Aerobatic is a static hosting service that integrates with Bitbucket and provides a free hosting tier.
If you haven’t previously used Aerobatic, you’ll first need to install the Command Line Interface (CLI) and create an account. For a list of all commands available, see the Aerobatic CLI docs.
npm install aerobatic-cli -g
aero register
hugo new site my-new-hugo-site
cd my-new-hugo-site
cd themes; git clone https://github.com/eliasson/liquorice
hugo -t liquorice
aero create # create the Aerobatic site
hugo --baseURL https://my-new-hugo-site.aerobatic.io # build the site overriding baseURL
aero deploy -d public # deploy output to Aerobatic
Version v1 deployment complete.
View now at https://hugo-docs-test.aerobatic.io
In the rendered page response, the https://__baseurl__
will be replaced with your actual site url (in this example, https://my-new-hugo-site.aerobatic.io
). You can always rename your Aerobatic website with the aero rename
command.
We will now create a git repository and then push our code to Bitbucket. In Bitbucket, create a repository.
# initialize new git repository
git init
# set up our .gitignore file
echo -e "/public \n/themes \naero-deploy.tar.gz" >> .gitignore
# commit and push code to master branch
git add --all
git commit -m "Initial commit"
git remote add origin git@bitbucket.org:YourUsername/my-new-hugo-site.git
git push -u origin master
In the example above, we pushed the compiled assets in the /public
folder to Aerobatic. In the following example, we use Bitbucket Pipelines to continuously create and deploy the compiled assets to Aerobatic.
In your Hugo website’s Bitbucket repo;
image: beevelop/nodejs-python
pipelines:
branches:
master:
- step:
script:
- apt-get update -y && apt-get install wget
- apt-get -y install git
- wget https://github.com/gohugoio/hugo/releases/download/v0.18/hugo_0.18-64bit.deb
- dpkg -i hugo*.deb
- git clone https://github.com/eliasson/liquorice themes/liquorice
- hugo --theme=liquorice --baseURL https://__baseurl__ --buildDrafts
- npm install -g aerobatic-cli
- aero deploy
AEROBATIC_API_KEY
environment variable.This step only needs to be done once per account. From the command line;
aero apikey
aero apikey
command. Be sure to click the Secured checkbox.hugo new post/good-to-great.md
hugo server --buildDrafts -t liquorice #Check that all looks good
# commit and push code to master branch
git add --all
git commit -m "New blog post"
git push -u origin master
Your code will be committed to Bitbucket, Bitbucket Pipelines will run your build, and a new version of your site will be deployed to Aerobatic.
At this point, you can now create and edit blog posts directly in the Bitbucket UI.
The code for this example can be found in this Bitbucket repository. Aerobatic also provides a number of additional plugins such as auth and redirects that you can use for your Hugo site.
By the end of this guide, you will have completed the following:
If you do not meet these assumptions, the GitHub help section has an explanation of how to install and use git. Signing up for a GitHub account is free as well. If you are completely unfamiliar with creating a new Hugo website, visit the Hugo Quick Start.
{{% note “This Guide Uses the Hugo CLI” %}}
All the work for setting up a Hugo project and using this guide is done via the Hugo CLI’s most basic commands. See the command line reference page for a more exhaustive account of the CLI’s features.
{{% /note %}}
First, create your new Hugo website using the hugo new site
command and change into the newly created directory for the project. In this guide, we are calling our new project hugo-wercker-example
:
{{< code file=“hugo-new-site.sh” >}}
hugo new site hugo-wercker-example
cd hugo-wercker-example
{{< /code >}}
We will use the Herring Cove theme by first cloning the theme into the themes
directory.
{{< code file=“clone-herring-cove-theme.sh” >}}
cd themes
git clone https://github.com/spf13/herring-cove.git
{{< /code >}}
Cloning the project from the command line will conflict with our own version control. So, we need to remove the external git configuration that came with the clone of Herring Cove:
{{< code file=“remove-herring-cove-git.sh” >}}
rm -rf herring-cove/.git
{{< /code >}}
We need content for Hugo to build. Let’s add a quick /about
page:
hugo new about.md
{{% note %}}
The preceding example for the about page leverages archetypes to scaffold a new content file with preconfigured front matter. Find out more about Hugo’s archetypes.
{{% /note %}}
Now you can edit contents/about.md
in your text editor of choice, but this is not necessary for the purposes of this guide. Running the following command will build your Hugo site into the public
directory. We have added undraft
to ensure that the example page is no longer in draft mode:
{{< code file=“hugo-build-undraft.sh” >}}
hugo undraft content/about.md
{{< /code >}}
Once the website is build, t’s a good idea to run the following command to start a local server and ensure you’re changes have been implemented:
hugo server --theme=herring-cove
If everything is fine, you should see something similar to the image below when you go to http://localhost:1313 in your browser.
Adding Git to your project is done by running the git init
command from the root directory of your project.
git init
Running git status
at this point will show you the following entries: the config.toml
file, the themes
directory, the contents
directory, and the public
directory. However, we don’t want the public
directory version controlled because Wercker is responsible for generating the finished website later on. Therefore, we’ll add a .gitignore
file to our project that will exclude the /public
directory from being tracked by Git:
{{< code file=“gitignore.sh” >}}
echo “/public” >> .gitignore
{{< /code >}}
Wercker might complain when we try to build the site later on because we currently do not have any static files outside of the themes
directory. We simply have to add any file to the static folder to prevent Wercker from complaining. To keep this guide simple, let’s add a robots.txt
. The following command creates the file in /static
. The contents of the robots.txt
lets search engines know they have full access to crawl the published website:
{{< code file=“addrobotstxt.sh” >}}
echo “User-agent: *\nDisallow:” > static/robots.txt
{{< /code >}}
Now we need to add (i.e., stage seeGitdocumentation
git commit -a -m "Initial commit"
Now we need to create a new repository on GitHub. Once you are signed in to GitHub, you can add a new repository by clicking on the +▼ dropdown at the top right or by going to https://github.com/new…
We then choose a name for the project (hugo-wercker-example
). When clicking on create repository GitHub displays the commands for adding an existing project to the site. The commands shown below are the ones used for this site, if you’re following along you will need to use the ones shown by GitHub. Once we’ve run those commands the project is in GitHub and we can move on to setting up the Wercker configuration. Be sure to replace YourUserName
with your GitHub account/username:
{{< code file=“setup-gh-repo.sh” >}}
git remote add origin git@github.com:YourUsername/hugo-wercker-example.git
git push -u origin master
{{< /code >}}
To sign up for a free Wercker account, go to https://wercker.com and click the the Sign Up button on the top right of the home screen.
Sign up for Wercker using your GitHub credentials. If you don’t have a GitHub account, or don’t want to use it for your account, you have the option to register with a username and password as well. However, the second half of this guide—devoted to hosting your website on GitHub pages—will no longer be of interest to you.
After you are registered, you will need to link your GitHub or Bitbucket account to Wercker. You can link your account by navigating to your profile settings and then selecting “Git connections.”
If you registered for Wercker using GitHub, it will most likely look like the following image. To connect a missing service, click the Connect button, which may send you to either GitHub or Bitbucket to sign into your respective account.
Now that we’ve got all the preliminaries out of the way, it’s time to set up our application. For this we click on the + Create button next to Applications and choose GitHub as our provider.
When selecting GitHub, Wercker will show all your GitHub repositories. You have the option to filter repositories using the search input at the top of the repositories list. Once you have your repository selected, click the Use selected repo button.
In the next step, Wercker asks you to select the repository owner. Select your GitHub account and continue.
{{% note %}}
This guide assumes you are using a public GitHub repository and understand that the published GitHub Pages website will be available to everyone.
{{%/note %}}
This step can be slightly tricky. Wercker does not have privileges to check out your private projects by default and therefore needs your permission to add a deploy key to your repository. By selecting the first option, you’re simply allowing Wercker to check out the code via the same methods available to anyone visiting the project on GitHub.
Wercker will now attempt to create an initial wercker.yml
file for you. More specifically, it will create a code block within the Wercker interface that you can copy to your finished file. Wercker gives us a debian
box because our project does not have any special requirements.
Now we need to create a wercker.yml file in the root of our project. This file will contain our Wercker app’s configuration. After we finish setting up our app, we will expand the contents of this file to build and deploy our website.
This is a personal choice. You can make an app public so that everyone can see more details about it. Keeping it private or public does not provide any overt benefits for you as the creator of the app. That said, the app we are currently creating has been made public to facilitate easier usage of this hosting and deployment guide.
The application is now added and Wercker will offer you the chance to trigger a build. However, we will decline the offer because we haven’t yet pushed our wercker.yml
file to our GitHub repository.
Now we need to add the Wercker steps to our build process. First, we go to the “Registry” action in the top menu. When in the registry, we can search for “hugo build”. Select the “Hugo-Build by arjen” step.
A summary of very basic usage is available at the top of the details for the Hugo-Build step. Below the basic usage is the contents of the README.md
file associated with the step’s repository. README.md
’s on Wercker usually contain more details about the advanced options and examples of usage.
We’re not going to use any of the advanced features of Hugo-Build in this guide. Let’s return to our project and add the first section of details we need to our wercker.yml
.
{{% warning “Hugo Version in wercker.yml
” %}}
The docs are a work in progress. As such, the version
represented in this guide may not represent the version you’ve been using for local development. Be sure to use the appropriate Hugo version for your build step.
{{% /warning %}}
{{< code file=“wercker-build-step.yml” >}}
box: debian
build:
steps:
- arjen/hugo-build:
version: “0.17”
theme: herring-cove
flags: --buildDrafts=true
{{< /code >}}
We can conclude this first step by pushing our wercker.yml
to our GitHub repository and then seeing the magic at work within Wercker’s interface.
{{< code file=“push-wecker-to-gh.sh” >}}
git commit -a -m “Add wercker.yml”
git push origin master
{{< /code >}}
If completed and successful, a green check mark should appear in the commit column of your first build. However, this is only the build step. We still need to deploy the website to our free hosting on GitHub Pages. If you would like more details about the build, you can click the commit hash.
wercker.yml
In order to deploy to GitHub Pages, we need to add a deploy step to our wercker.yml
. We are going to add lukevevier/gh-pages
, the most popular GitHub Pages step in the Wercker Steps repository. Additionally, we need to ensure the box Wercker uses for our deployments has git and ssh installed. We can do this using the install-packages
command. Here is our final wercker.yml
file:
{{< code file=“wercker.yml” >}}
box: debian
build:
steps:
- arjen/hugo-build:
version: “0.17”
theme: herring-cove
flags: --buildDrafts=true
deploy:
steps:
- install-packages:
packages: git ssh-client
- lukevivier/gh-pages@0.2.1:
token: $GIT_TOKEN
domain: hugo-wercker.ig.nore.me
basedir: public
{{< /code >}}
We’ve provided a some important information in our wercker.yml
. First, we’ve added the domain we want to use for our published website. Configuring the domain here will ensure that GitHub Pages is aware of the domain we want to use.
Secondly, we’ve configured the basedir
to public
. This is the directory that will be used as the website on GitHub Pages. public
is also the default publishing directory in Hugo. (For more information, see hugo’s configuration docs).
Lastly, you’ll notice a $GIT_TOKEN
variable. This is used for pushing our changes to GitHub. We will need to configure this token before Wercker can build our website.
We can set our deploy target by going to our app’s settings and clicking on Deploy targets. Now select Add deploy target and then Custom deploy.
The next screen requires you fill in the deploy target name.
The website described in this guide is available at http://hugo-wercker.ig.nore.me.
Once this workflow is established, you can update your website automatically by pushing any content changes to your GitHub repository.
The source code for the site used in this guide is available on GitHub, as is the Wercker Hugo Build step.
If you want to see an example of how you can deploy to S3 instead of GitHub pages, check Wercker’s documentation for guidance on setup.
The spoiler is that you can deploy your entire website with a command that looks like the following:
hugo && rsync -avz --delete public/ www-data@ftp.topologix.fr:~/www/
As you will see, we put it in a shell script file, which makes building and deployment as easy as executing ./deploy
.
If it is not done yet, we will make an automated way to SSH to your server. If you have already installed an SSH key, switch to the next section.
First, install the ssh client. On Debian/Ubuntu/derivates, use the following command:
{{< code file=“install-openssh.sh” >}}
sudo apt-get install openssh-client
{{< /code >}}
Then generate your ssh key by entering the following commands:
~$ cd && mkdir .ssh & cd .ssh
~/.ssh/$ ssh-keygen -t rsa -q -C "For SSH" -f rsa_id
~/.ssh/$ cat >> config <<EOF
Host HOST
Hostname HOST
Port 22
User USER
IdentityFile ~/.ssh/rsa_id
EOF
Don’t forget to replace the HOST
and USER
values with your own ones. Then copy your ssh public key to the remote server:
~/.ssh/$ ssh-copy-id -i rsa_id.pub USER@HOST.com
Now you can easily connect to the remote server:
~$ ssh user@host
Enter passphrase for key '/home/mylogin/.ssh/rsa_id':
And you’ve done it!
We will put the first command in a script at the root of your Hugo tree:
~/websites/topologix.fr$ editor deploy
Here you put the following content. Replace the USER
, HOST
, and DIR
values with your own:
#!/bin/sh
USER=my-user
HOST=my-server.com
DIR=my/directory/to/topologix.fr/ # might sometimes be empty!
hugo && rsync -avz --delete public/ ${USER}@${HOST}:~/${DIR}
exit 0
Note that DIR
is the relative path from the remote user’s home. If you have to specify a full path (for instance /var/www/mysite/
) you must change ~/${DIR}
to ${DIR}
inside the command line. For most cases you should not have to.
Save and close, and make the deploy
file executable:
~/websites/topologix.fr$ chmod +x deploy
Now you only have to enter the following command to deploy and update your website:
~/websites/topologix.fr$ ./deploy
Started building sites ...
Built site for language en:
0 draft content
0 future content
0 expired content
5 pages created
0 non-page files copied
0 paginator pages created
0 tags created
0 categories created
total in 56 ms
sending incremental file list
404.html
index.html
index.xml
sitemap.xml
cours-versailles/index.html
exercices/index.html
exercices/index.xml
exercices/barycentre-et-carres-des-distances/index.html
post/
post/index.html
sujets/index.html
sujets/index.xml
sujets/2016-09_supelec-jp/index.html
tarifs-contact/index.html
sent 9,550 bytes received 1,708 bytes 7,505.33 bytes/sec
total size is 966,557 speedup is 85.86
Hugo relies heavily on the enthusiasm and participation of the open-source community. We need your support in both its development and documentation.
Hugo’s contribution guidelines are detailed in a CONTRIBUTING.md
in the Hugo source repository on GitHub.
Hugo is an open-source project and lives by the work of its contributors. There are plenty of open issues, and we need your help to make Hugo even more awesome. You don’t need to be a Go guru to contribute to the project’s development.
This contribution guide takes a step-by-step approach in hopes of helping newcomers. Therefore, we only assume the following:
{{% note “Additional Questions?” %}}
If you’re struggling at any point in this contribution guide, reach out to the Hugo community in Hugo’s Discussion forum.
{{% /note %}}
The installation of Go should take only a few minutes. You have more than one option to get Go up and running on your machine.
If you are having trouble following the installation guides for go, check out Go Bootcamp, which contains setups for every platform or reach out to the Hugo community in the Hugo Discussion Forums.
Download the latest stable version of Go and follow the official Golang installation guide.
Once you’re finished installing Go, let’s confirm everything is working correctly. Open a terminal—or command line under Windows–and type the following:
go version
You should see something similar to the following written to the console. Note that the version here reflects the most recent version of Go as of the last update for this page:
go version go1.8 darwin/amd64
Next, make sure that you set up your GOPATH
as described in the installation guide.
You can print the GOPATH
with echo $GOPATH
. You should see a non-empty string containing a valid path to your Go workspace; .e.g.:
/Users/<yourusername>/Code/go
If you are a macOS user and have Homebrew installed on your machine, installing Go is as simple as the following command:
{{< code file=“install-go.sh” >}}
brew install go
{{< /code >}}
More experienced users can use the Go Version Manager (GVM). GVM allows you to switch between different Go versions on the same machine. If you’re a beginner, you probably don’t need this feature. However, GVM makes it easy to upgrade to a new released Go version with just a few commands.
GVM comes in especially handy if you follow the development of Hugo over a longer period of time. Future versions of Hugo will usually be compiled with the latest version of Go. Sooner or later, you will have to upgrade if you want to keep up.
If you’re going to contribute code, you’ll need to have an account on GitHub. Go to www.github.com/join and set up a personal account.
You will need to have Git installed on your computer to contribute to Hugo development. Teaching git is outside the scope of the Hugo docs, but if you’re looking for an excellent reference to learn the basics of Git, we recommend the Git book if you are not sure where to begin. The used terminology will be explained with annotations.
Git is a version control system to track the changes of source code. Hugo depends on smaller third-party packages that are used to extend the functionality. We use them because we don’t want to reinvent the wheel.
Go ships with a sub-command called get
that will download these packages for us when we setup our working environment. The source code of the packages is tracked with Git. get
will interact with the Git servers of the package hosters in order to fetch all dependencies.
Move back to the terminal and check if Git is already installed. Type in git version
and press enter. You can skip the rest of this section if the command returned a version number. Otherwise download the lastest version of Git and follow this installation guide.
Finally, check again with git version
if Git was installed successfully.
There are several GUI clients that help you to operate Git. Not all are available for all operating systems and maybe differ in their usage. Thus, so we will use the command line since the commands are everywhere the same.
Hub is a great tool for working with GitHub. The main site for it is hub.github.com. Feel free to install this little Git wrapper.
On a Mac, you can install Hub using Homebrew:
brew install hub
Now we’ll create an alias in Bash so that typing git
actually runs Hub
:
echo "alias git='hub'" >> ~/.bash_profile
Confirm the installation:
git version 2.6.3
hub version 2.2.2
The working copy is set up locally on your computer. It’s what you’ll edit, compile, and end up pushing back to GitHub. The main steps are cloning the repository and creating your fork as a remote.
We assume that you’ve set up your GOPATH
(see the section above if you’re unsure about this). You should now copy the Hugo repository down to your computer. You’ll hear this called “clone the repo”. GitHub’s help pages give us a short explanation:
When you create a repository on GitHub, it exists as a remote repository. You can create a local clone of your repository on your computer and sync between the two locations.
We’re going to clone the master Hugo repository. That seems counter-intuitive, since you won’t have commit rights on it. But it’s required for the Go workflow. You’ll work on a copy of the master and push your changes to your own repository on GitHub.
So, let’s clone that master repository:
go get -v -u github.com/gohugoio/hugo
If you’re not fimiliar with this term, GitHub’s help pages provide again a simple explanation:
A fork is a copy of a repository. Forking a repository allows you to freely experiment with changes without affecting the original project.
Open the Hugo repository on GitHub and click on the “Fork” button in the top right.
Now open your fork repository on GitHub and copy the remote url of your fork. You can choose between HTTPS and SSH as protocol that Git should use for the following operations. HTTPS works always if you’re not sure.
Switch back to the terminal and move into the directory of the cloned master repository from the last step.
cd $GOPATH/src/github.com/gohugoio/hugo
Now Git needs to know that our fork exists by adding the copied remote url:
git remote add <YOUR-GITHUB-USERNAME> <COPIED REMOTE-URL>
Alternatively, you can use the Git wrapper Hub. Hub makes forking a repository easy:
git fork
That command will log in to GitHub using your account, create a fork of the repository that you’re currently working in, and add it as a remote to your working copy.
Let’s check if everything went right by listing all known remotes:
git remote -v
The output should look similar:
digitalcraftsman git@github.com:digitalcraftsman/hugo.git (fetch)
digitalcraftsman git@github.com:digitalcraftsman/hugo.git (push)
origin https://github.com/gohugoio/hugo (fetch)
origin https://github.com/gohugoio/hugo (push)
You should never develop against the “master” branch. The development team will not accept a pull request against that branch. Instead, create a descriptive named branch and work on it.
First, you should always pull the latest changes from the master repository:
git checkout master
git pull
Now we can create a new branch for your additions:
git checkout -b <BRANCH-NAME>
You can check on which branch your are with git branch
. You should see a list of all local branches. The current branch is indicated with a little asterisk.
Perhaps you want to start contributing to the Hugo docs. If so, you can ignore most of the following steps and focus on the /docs
directory within your newly cloned repository. You can change directories into the Hugo docs using cd docs
.
You can start Hugo’s built-in server via hugo server
. Browse the documentation by entering http://localhost:1313 in the address bar of your browser. The server automatically updates the page whenever you change content.
We have developed a separate Hugo documentation contribution guide for more information on how the Hugo docs are built, organized, and improved by the generosity of people like you.
While making changes in the codebase it’s a good idea to build the binary to test them:
go build -o hugo main.go
Sometimes changes on the codebase can cause unintended side effects. Or they don’t work as expected. Most functions have their own test cases. You can find them in files ending with _test.go
.
Make sure the commands go test ./...
passes, and go build
completes.
The Go code styleguide maybe is opiniated but it ensures that the codebase looks the same, regardless who wrote the code. Go comes with its own formatting tool. Let’s apply the styleguide to our addtions:
go fmt ./...
Once you made your additions commit your changes. Make sure that you follow our code contribution guidelines:
# Add all changed files
git add --all
git commit --message "YOUR COMMIT MESSAGE"
The commit message should describe what the commit does (e.g. add feature XYZ), not how it is done.
You noticed some commit messages don’t fulfill the code contribution guidelines or you just forget something to add some files? No problem. Git provides the necessary tools to fix such problems. The next two methods cover all common cases.
If you are unsure what a command does leave the commit as it is. We can fix your commits later in the pull request.
Let’s say you want to modify the last commit message. Run the following command and replace the current message:
git commit --amend -m"YOUR NEW COMMIT MESSAGE"
Take a look at the commit log to see the change:
git log
# Exit with q
After making the last commit you may forgot something. There is no need to create a new commit. Just add the latest changes and merge them into the intended commit:
git add --all
git commit --amend
{{% warning “Be Careful Modifying Multiple Commits”%}}
Modifications such as those described in this section can have serious unintended consequences. Skip this section if you’re not sure!
{{% /warning %}}
This is a bit more advanced. Git allows you to rebase commits interactively. In other words: it allows you to rewrite the commit history.
git rebase --interactive @~6
The 6
at the end of the command represents the number of commits that should be modified. An editor should open and present a list of last six commit messages:
pick 80d02a1 tpl: Add hasPrefix to the template funcs' "smoke test"
pick aaee038 tpl: Sort the smoke tests
pick f0dbf2c tpl: Add the other test case for hasPrefix
pick 911c35b Add "How to contribute to Hugo" tutorial
pick 33c8973 Begin workflow
pick 3502f2e Refactoring and typo fixes
In the case above we should merge the last to commits in the commit of this tutorial (Add "How to contribute to Hugo" tutorial
). You can “squash” commits, i.e. merge two or more commits into a single one.
All operations are written before the commit message. Replace “pick” with an operation. In this case squash
or s
for short:
pick 80d02a1 tpl: Add hasPrefix to the template funcs' "smoke test"
pick aaee038 tpl: Sort the smoke tests
pick f0dbf2c tpl: Add the other test case for hasPrefix
pick 911c35b Add "How to contribute to Hugo" tutorial
squash 33c8973 Begin workflow
squash 3502f2e Refactoring and typo fixes
We also want to rewrite the commits message of the third last commit. We forgot “docs:” as prefix according to the code contribution guidelines. The operation to rewrite a commit is called reword
(or r
as shortcut).
You should end up with a similar setup:
pick 80d02a1 tpl: Add hasPrefix to the template funcs' "smoke test"
pick aaee038 tpl: Sort the smoke tests
pick f0dbf2c tpl: Add the other test case for hasPrefix
reword 911c35b Add "How to contribute to Hugo" tutorial
squash 33c8973 Begin workflow
squash 3502f2e Refactoring and typo fixes
Close the editor. It should open again with a new tab. A text is instructing you to define a new commit message for the last two commits that should be merged (aka “squashed”). Save the file with CTRL+S and close the editor again.
A last time a new tab opens. Enter a new commit message and save again. Your terminal should contain a status message. Hopefully this one:
Successfully rebased and updated refs/heads/<BRANCHNAME>.
Check the commit log if everything looks as expected. Should an error occur you can abort this rebase with git rebase --abort
.
To push our commits to the fork on GitHub we need to speficy a destination. A destination is defined by the remote and a branch name. Earlier, the defined that the remote url of our fork is the same as our GitHub handle, in my case digitalcraftsman
. The branch should have the same as our local one. This makes it easy to identify corresponding branches.
git push --set-upstream <YOUR-GITHUB-USERNAME> <BRANCHNAME>
Now Git knows the destination. Next time when you to push commits you just need to enter git push
.
If you modified your commit history in the last step GitHub will reject your try to push. This is a safety-feature because the commit history isn’t the same and new commits can’t be appended as usual. You can enforce this push explicitly with git push --force
.
We made a lot of progress. Good work. In this step we finally open a pull request to submit our additions. Open the Hugo master repository on GitHub in your browser.
You should find a green button labeld with “New pull request”. But GitHub is clever and probably suggests you a pull request like in the beige box below:
The new page summaries the most important information of your pull request. Scroll down and you find the additions of all your commits. Make sure everything looks as expected and click on “Create pull request”.
Last but not least you should accept the contributor license agreement (CLA). A new comment should be added automatically to your pull request. Click on the yellow badge, accept the agreement and authenticate yourself with your GitHub account. It just takes a few clicks and only needs to be done once.
We use the Travis CI loop (Linux and OS X) and AppVeyor (Windows) to compile Hugo with your additions. This should ensure that everything works as expected before merging your pull request. This in most cases only relevant if you made changes to the codebase of Hugo.
Above you can see that Travis wasn’t able to compile the changes in this pull request. Click on “Details” and try to investigate why the build failed. But it doesn’t have to be your fault. Mostly, the master
branch that we used as foundation for your pull request should build without problems.
If you have questions, leave a comment in the pull request. We are willing to assist you.
Thank you for reading through this contribution guide. Hopefully, we will see you again soon on GitHub. There are plenty of open issues for you to help with.
Feel free to open an issue if you think you found a bug or you have a new idea to improve Hugo. We are happy to hear from you.
It’s best to make changes to the Hugo docs on your local machine to check for consistent visual styling. Make sure you’ve created a fork of hugoDocs on GitHub and cloned the repository locally on your machine. For more information, you can see GitHub’s documentation on “forking” or follow along with Hugo’s development contribution guide.
You can then create a separate branch for your additions. Be sure to choose a descriptive branch name that best fits the type of content. The following is an example of a branch name you might use for adding a new website to the showcase:
git checkout -b jon-doe-showcase-addition
The Hugo docs make heavy use of Hugo’s archetypes feature. All content sections in Hugo documentation have an assigned archetype.
Adding new content to the Hugo docs follows the same pattern, regardless of the content section:
hugo new <DOCS-SECTION>/<new-content-lowercase>.md
Once you have cloned the Hugo repository, you can create a new function via the following command. Keep the file name lowercase.
hugo new functions/newfunction.md
The archetype for functions
according to the Hugo theme is as follows:
{{< code file=“archetypes/functions.md” >}}
{{< readfile file=“/themes/gohugoioTheme/archetypes/functions.md”>}}
{{< /code >}}
Here is a review of the front matter fields automatically generated for you using hugo new functions/*
:
title
hugo new
generator.linktitle
replaceRE
rather than replacere
).description
categories
tags
signature
apply SEQUENCE FUNCTION PARAM...
).workson
lists
,taxonomies
, terms
, groups
, and files
.hugoversion
relatedfuncs
{{.Content}}
In the body of your function, expand the short description used in the front matter. Include as many examples as possible, and leverage the Hugo docs code
shortcode. If you are unable to add examples but would like to solicit help from the Hugo community, add needsexample: true
to your front matter.
Code blocks are crucial for providing examples of Hugo’s new features to end users of the Hugo docs. Whenever possible, create examples that you think Hugo users will be able to implement in their own projects.
Across all pages on the Hugo docs, the typical triple-back-tick markdown syntax is used. If you do not want to take the extra time to implement the following code block shortcodes, please use standard GitHub-flavored markdown. The Hugo docs use a version of highlight.js with a specific set of languages.
Your options for languages are xml
/html
, go
/golang
, md
/markdown
/mkd
, handlebars
, apache
, toml
, yaml
, json
, css
, asciidoc
, ruby
, powershell
/ps
, scss
, sh
/zsh
/bash
/git
, http
/https
, and javascript
/js
.
The Hugo documentation comes with a very robust shortcode for adding interactive code blocks.
{{% note %}}
With the code
shortcodes, you must include triple back ticks and a language declaration. This was done by design so that the shortcode wrappers were easily added to legacy documentation and will be that much easier to remove if needed in future versions of the Hugo docs.
{{% /note %}}
code
code
is the Hugo docs shortcode you’ll use most often. code
requires has only one named parameter: file
. Here is the pattern:
{{%/* code file="smart/file/name/with/path.html" download="download.html" copy="true" */%}}
A whole bunch of coding going on up in here!
{{%/* /code */%}}
The following are the arguments passed into code
:
file
file
is needed for styling but also plays an important role in helping users create a mental model around Hugo’s directory structure. Visually, this will be displayed as text in the top left of the code block.download
download
, it’s used as the filename for a downloadable version of the code block.copy
code
shortcodes. If you want to keep the filename and styling of code
but don’t want to encourage readers to copy the code (e.g., a “Do not do” snippet in a tutorial), use copy="false"
.code
InputThis example HTML code block tells Hugo users the following:
layouts/_default
, as demonstrated by layouts/_default/single.html
as the value for file
.download="single.html"
.{{%/* code file="layouts/_default/single.html" download="single.html" */%}}
{{ define “main” }}
The output of this example will render to the Hugo docs as follows:
{{< code file=“layouts/_default/single.html” download=“single.html” >}}
{{ define “main” }}
Blockquotes can be added to the Hugo documentation using typical Markdown blockquote syntax:
> Without the threat of punishment, there is no joy in flight.
The preceding blockquote will render as follows in the Hugo docs:
Without the threat of punishment, there is no joy in flight.
However, you can add a quick and easy <cite>
element (added on the client via JavaScript) by separating your main blockquote and the citation with a hyphen with a single space on each side:
> Without the threat of punishment, there is no joy in flight. - [Kobo Abe](https://en.wikipedia.org/wiki/Kobo_Abe)
Which will render as follows in the Hugo docs:
Without the threat of punishment, there is no joy in flight. - Kobo Abe
{{% note “Blockquotes !=
Admonitions” %}}
Previous versions of Hugo documentation used blockquotes to draw attention to text. This is not the intended semantic use of <blockquote>
. Use blockquotes when quoting. To note or warn your user of specific information, use the admonition shortcodes that follow.
{{% /note %}}
Admonitions are common in technical documentation. The most popular is that seen in reStructuredText Directives. From the SourceForge documentation:
Admonitions are specially marked “topics” that can appear anywhere an ordinary body element can. They contain arbitrary body elements. Typically, an admonition is rendered as an offset block in a document, sometimes outlined or shaded, with a title matching the admonition type. - SourceForge
The Hugo docs contain three admonitions: note
, tip
, and warning
.
note
AdmonitionUse the note
shortcode when you want to draw attention to information subtly. note
is intended to be less of an interruption in content than is warning
.
note
Input{{< code file=“note-with-heading.md” >}}
{{%/* note /%}}
Here is a piece of information I would like to draw your attention to.
{{%/ /note */%}}
{{< /code >}}
note
Output{{< output file=“note-with-heading.html” >}}
{{% note %}}
Here is a piece of information I would like to draw your attention to.
{{% /note %}}
{{< /output >}}
note
Display{{% note %}}
Here is a piece of information I would like to draw your attention to.
{{% /note %}}
tip
AdmonitionUse the tip
shortcode when you want to give the reader advice. tip
, like note
, is intended to be less of an interruption in content than is warning
.
tip
Input{{< code file=“using-tip.md” >}}
{{%/* tip /%}}
Here’s a bit of advice to improve your productivity with Hugo.
{{%/ /tip */%}}
{{< /code >}}
tip
Output{{< output file=“tip-output.html” >}}
{{% tip %}}
Here’s a bit of advice to improve your productivity with Hugo.
{{% /tip %}}
{{< /output >}}
tip
Display{{% tip %}}
Here’s a bit of advice to improve your productivity with Hugo.
{{% /tip %}}
warning
AdmonitionUse the warning
shortcode when you want to draw the user’s attention to something important. A good usage example is for articulating breaking changes in Hugo versions, known bugs, or templating “gotchas.”
warning
Input{{< code file=“warning-admonition-input.md” >}}
{{%/* warning /%}}
This is a warning, which should be reserved for important information like breaking changes.
{{%/ /warning */%}}
{{< /code >}}
warning
Output{{< output file=“warning-admonition-output.html” >}}
{{% warning %}}
This is a warning, which should be reserved for important information like breaking changes.
{{% /warning %}}
{{< /output >}}
warning
Display{{% warning %}}
This is a warning, which should be reserved for important information like breaking changes.
{{% /warning %}}
{{% note “Pull Requests and Branches” %}}
Similar to contributing to Hugo development, the Hugo team expects you to create a separate branch/fork when you make your contributions to the Hugo docs.
{{% /note %}}
A collection of all themes created by the Hugo community, including screenshots and demos, can be found at https://themes.gohugo.io. Every theme in this list will automatically be added to the theme site. Theme updates aren’t scheduled but usually happen at least once a week.
hugo new theme <THEMENAME>
;theme.toml
file to the root of the theme with all required metadataREADME.md
to the root of the theme source/images/screenshot.png
and /images/tn.png
* If your theme doesn’t fit into the Hugo Basic Example
site, we encourage theme authors to supply a self-contained Hugo site in /exampleSite
.
{{% note %}}
The folder name here—exampleSite
—is important, as this folder will be picked up and used by the script that generates the Hugo Theme Site. It mirrors the root directory of a Hugo website and allows you to add custom content, assets, and a config
file with preset values.
{{% /note %}}
See the Hugo Artist theme’s exampleSite for a good example.
{{% note %}}
Please make your example site’s content is as neutral as possible. We hope this goes without saying.
{{% /note %}}
In order to add your theme to the Hugo Themes Showcase, the following requirements need to be met:
theme.toml
with all required fieldsThe easiest way to add your theme is to open up a new issue in the theme repository with a link to the theme’s repository on GitHub.
theme.toml
Filetheme.toml
contains metadata about the theme and its creator and should be created automatically when running the hugo new theme
. The auto-generated file is provided here as well for easy downloading:
{{< code file=“theme.toml” download=“theme.toml” >}}
name = “”
license = “MIT”
licenselink = “https://github.com/
description = “”
homepage = “http://example.com/”
tags =
features =
min_version = 0.19
author
original
The following fields are required:
name = "Hyde"
license = "MIT"
licenselink = "https://github.com/spf13/hyde/blob/master/LICENSE.md"
description = "An elegant open source and mobile first theme"
homepage = "http://siteforthistheme.com/"
tags = ["blog", "company"]
features = ["blog"]
min_version = 0.13
[author]
name = "spf13"
homepage = "http://spf13.com/"
# If porting an existing theme
[original]
author = "mdo"
homepage = "http://hyde.getpoole.com/"
repo = "https://www.github.com/mdo/hyde"
{{% note %}}
theme.toml
file created by hugo new theme
in Hugo versions before v0.14.theme.toml
is accepted; ie. not theme.yaml
andnot theme.json
.Screenshots are used for previews in the Hugo Theme Gallery. Make sure that they have the right dimensions:
Additional media may be provided in the same directory.
Your theme’s README file should be written in markdown and saved at the root of your theme’s directory structure. Your README.md
serves as
README.md
You can download the following README.md
as an outline:
{{< code file=“README.md” download=“README.md” >}}
Need input from @digitalcraftsman on what could be added to this file.
{{< /code >}}
{{% note “Screenshots in your README.md
”%}}
If you add screenshots to the README, please make use of absolute file paths instead of relative ones like /images/screenshot.png
. Relative paths work great on GitHub but they don’t correspond to the directory structure of themes.gohugo.io. Therefore, browsers will not be able to display screenshots on the theme site under the given (relative) path.
{{% /note %}}