diff options
Diffstat (limited to 'docs/content/tutorials')
-rw-r--r-- | docs/content/tutorials/automated-deployments.md | 275 | ||||
-rw-r--r-- | docs/content/tutorials/create-a-multilingual-site.md | 168 | ||||
-rw-r--r-- | docs/content/tutorials/creating-a-new-theme.md | 1717 | ||||
-rw-r--r-- | docs/content/tutorials/deployment-with-rsync.md | 125 | ||||
-rw-r--r-- | docs/content/tutorials/github-pages-blog.md | 197 | ||||
-rw-r--r-- | docs/content/tutorials/hosting-on-bitbucket.md | 138 | ||||
-rw-r--r-- | docs/content/tutorials/hosting-on-gitlab.md | 68 | ||||
-rw-r--r-- | docs/content/tutorials/how-to-contribute-to-hugo.md | 352 | ||||
-rw-r--r-- | docs/content/tutorials/installing-on-mac.md | 240 | ||||
-rw-r--r-- | docs/content/tutorials/installing-on-windows.md | 123 | ||||
-rw-r--r-- | docs/content/tutorials/mathjax.md | 84 | ||||
-rw-r--r-- | docs/content/tutorials/migrate-from-jekyll.md | 162 |
12 files changed, 3649 insertions, 0 deletions
diff --git a/docs/content/tutorials/automated-deployments.md b/docs/content/tutorials/automated-deployments.md new file mode 100644 index 000000000..9f6d5c628 --- /dev/null +++ b/docs/content/tutorials/automated-deployments.md @@ -0,0 +1,275 @@ +--- +authors: +- Arjen Schwarz +- Samuel Debruyn +lastmod: 2017-02-26 +date: 2015-01-12 +linktitle: Automated deployments +toc: true +menu: + main: + parent: tutorials +next: /tutorials/creating-a-new-theme +prev: /community/contributing +title: Automated deployments with Wercker +weight: 10 +--- + +# Automated deployments with Wercker + +In this tutorial we will set up a basic Hugo project and then configure a free tool called Wercker to automatically deploy the generated site any time we add an article. We will deploy it to GitHub pages as that is easiest to set up, but you will see that we can use anything. This tutorial takes you through every step of the process, complete with screenshots and is fairly long. + +The assumptions made for this tutorial are that you know how to use git for version control, and have a GitHub account. In case you are unfamiliar with these, in their [help section](https://help.github.com/articles/set-up-git/) GitHub has an explanation of how to install and use git and you can easily sign up for a free GitHub account as well. + +## Creating a basic Hugo site + +There are already [pages](http://gohugo.io/overview/quickstart/) dedicated to describing how to set up a Hugo site so we will only go through the most basic steps required to get a site up and running before we dive into the Wercker configuration. All the work for setting up the project is done using the command line, and kept as simple as possible. + +Create the new site using the `hugo new site` command, and we move into it. + +```bash +hugo new site hugo-wercker-example +cd hugo-wercker-example +``` + +Add the herring-cove theme by cloning it into the theme directory using the following commands. + +```bash +mkdir themes +cd themes +git clone https://github.com/spf13/herring-cove.git +``` + +Cloning the project like this will conflict with our own version control, so we remove the external git configuration. + +```bash +rm -rf herring-cove/.git +``` + +Let's add a quick **about** page. + +```bash +hugo new about.md +``` + +Now we'll edit contents/about.md to ensure it's no longer a draft and add some text to it. + +```bash +hugo undraft content/about.md +``` + +Once completed it's a good idea to do a quick check if everything is working by running + +```bash +hugo server --theme=herring-cove +``` + +If everything is fine, you should be able to see something similar to the image below when you go to localhost:1313 in your browser. + +![][1] + +[1]: /img/tutorials/automated-deployments/creating-a-basic-hugo-site.png + +## Setting up version control + +Adding git to our project is done by running the `git init` command from the root directory of the project. + +```bash +git init +``` + +Running `git status` at this point will show you p entries: the **config.toml** file, the **themes** directory, the **contents** directory, and the **public** directory. We don't want the **public** directory version controlled however, as we will use wercker to generate that later on. Therefore, we'll add a gitignore file that will exclude this using the following command. + +```bash +echo "/public" >> .gitignore +``` + +As we currently have no static files outside of the theme directory, Wercker might complain when we try to build the site later on. To prevent this, we simply have to add any file to the static folder. To keep it simple for now we'll add a robots.txt file that will give all search engines full access to the site when it's up. + +```bash +echo "User-agent: *\nDisallow:" > static/robots.txt +``` + +After this we can add everything to the repository. + +```bash +git commit -a -m "Initial commit" +``` + +## Adding the project to GitHub + +First we'll create a new repository. You can do this by clicking on the **+** sign 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. + +```bash +git remote add origin [email protected]:YourUsername/hugo-wercker-example.git +git push -u origin master +``` + +![][2] + +[2]: /img/tutorials/automated-deployments/adding-the-project-to-github.png + +## Welcome to wercker + +Let's start by setting up an account for Wercker. To do so we'll go to http://wercker.com and click on the **Sign up** button. + +![][3] + +[3]: /img/tutorials/automated-deployments/wercker-sign-up.png + +## Register + +To make life easier for ourselves, we will then register using GitHub. If you don't have a GitHub account, or don't want to use it for your account, you can of course register with a username and password as well. + +![][4] + +[4]: /img/tutorials/automated-deployments/wercker-sign-up-page.png + +## Connect GitHub/Bitbucket + +After you are registered, you will need to link your GitHub and/or Bitbucket account to Wercker. You do this by going to your profile settings, and then "Git connections" If you registered using GitHub it will most likely look like the image below. To connect a missing service, simply click on the connect button which will then send you to either GitHub or Bitbucket where you might need to log in and approve their access to your account. + +![][5] + +[5]: /img/tutorials/automated-deployments/wercker-git-connections.png + +## Add your project + +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. Create a new application, and choose to use GitHub. + +![][6] + +[6]: /img/tutorials/automated-deployments/wercker-add-app.png + +## Select a repository + +Clicking this will make Wercker show you all the repositories you have on GitHub, but you can easily filter them as well. So we search for our repository, select it, and then click on "Use selected repo". + +![][7] + +[7]: /img/tutorials/automated-deployments/wercker-select-repository.png + +## Configure access + +As Wercker doesn't access to check out your private projects by default, it will ask you what you want to do. When your project is public, as needs to be the case if you wish to use GitHub Pages, the top choice is recommended. When you use this it will simply check out the code in the same way anybody visiting the project on GitHub can do. + +![][8] + +[8]: /img/tutorials/automated-deployments/wercker-access.png + +## Public or not + +This is a personal choice; you can make an app public so that everyone can see more details about it. This doesn't give you any real benefits either way in general, although as part of the tutorial I have of course made this app public so you can see it in action [yourself](https://app.wercker.com/#applications/5586dcbdaf7de9c51b02b0d5). + +![][9] + +[9]: /img/tutorials/automated-deployments/public-or-not.png + +## Wercker.yml + +Choose Default for your programming language. Wercker will now attempt to create an initial *wercker.yml* file for you. Or rather, it will create the code you can copy into it yourself. Because there is nothing special about our project according to Wercker, we will simply get the `debian` box. So what we do now is create a *wercker.yml* file in the local root of our project that contains the provided configuration, and after we finish setting up the app we will expand this file to make it actually do something. + +![][10] + +[10]: /img/tutorials/automated-deployments/werckeryml.png + +## And we've got an app + +The application is added now, and Wercker will be offering you the chance to trigger a build. As we haven't pushed up the **wercker.yml** file however, we will politely decline this option. Wercker has automatically added a build pipeline to your application. + +## Adding build step + +And now we're going to add the build step to the build pipeline. First, we go to the "Registry" action in the top menu and then search for "hugo build". Find the **Hugo-Build** task by Arjen and select it. + +![][11] + +[11]: /img/tutorials/automated-deployments/wercker-search.png + +## Using Hugo-Build + +Inside the details of this step you will see how to use it. At the top is a summary for very basic usage, but when scrolling down you go through the README of the step which will usually contain more details about the advanced options available and a full example of using the step. + +We're not going to use any of the advanced features in this tutorial, so we'll return to our project and add the details we need to our wercker.yml file so that it looks like below: + +```yaml +box: debian +build: + steps: + - install-packages: + packages: git + - script: + name: download theme + code: | + $(git clone https://github.com/spf13/herring-cove ./themes/herring-cove) + - arjen/hugo-build: + version: "0.14" + theme: herring-cove + flags: --buildDrafts=true +``` + +As you can see, we have two steps in the build pipeline. The first step downloads the theme, and the second step runs arjen's hugo-build step. To use a different theme, you can replace the link to the herring-cove source with another theme's repository - just make sure the name of the folder you download the theme to (./themes/your-theme-name) matches the theme name you tell arjen/hugo-build to use (theme: your-theme-name). Now we'll test that it all works as it should by pushing up our wercker.yml file to GitHub and seeing the magic at work. + +```bash +git commit -a -m "Add wercker.yml" +git push origin master +``` + +Once completed a nice tick should have appeared in front of your first build, and if you want you can look at the details by clicking on it. However, we're not done yet as we still need to deploy it to GitHub Pages. + +![][12] + +[12]: /img/tutorials/automated-deployments/using-hugo-build.png + +## Adding a deploy pipeline + +In order to deploy to GitHub Pages we need to add a deploy pipeline. + +1. First, go to your Wercker application's page. Go to the "Workflows" tab and click on "Add new pipeline." Name it whatever you want; "deploy-production" or "deploy" works fine. For your YML Pipeline name, type in "deploy" without quotes. Leave the hook type as "Default" and hit the Create button. + +2. Now you need to link the deploy pipeline to your build pipeline. In the workflow editor, click on the + next to your build pipeline and add the deploy pipeline you've just made. Now the deploy pipeline will be run automatically whenever the build pipeline is completed successfully. + +![][13] + +[13]: /img/tutorials/automated-deployments/adding-a-deploy-pipeline.png + +## Adding a deploy step + +Next, we need to add a step to our deploy pipeline that will deploy the Hugo-built website to your GitHub pages repository. Once again searching through the Steps registry, we find that the most popular step is the **lukevevier/gh-pages** step so we add the configuration for that to our wercker.yml file. Additionally, we need to ensure that the box we run on has git and ssh installed. We can do this using the **install-packages** command, which then turns the wercker.yml file into this: + +```yaml +box: debian +build: + steps: + - arjen/hugo-build: + version: "0.14" + theme: herring-cove + flags: --buildDrafts=true +deploy: + steps: + - install-packages: + packages: git ssh-client + - lukevivier/[email protected]: + token: $GIT_TOKEN + domain: hugo-wercker.ig.nore.me + basedir: public +``` + +How does the GitHub Pages configuration work? We've selected a couple of things, first the domain we want to use for the site. Configuring this here will ensure that GitHub Pages is aware of the domain you 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. + +And lastly, you can see here that this has a **$GIT_TOKEN** variable. This is used for pushing our changes up to GitHub and we will need to configure this before we can do that. To do this, go to your application page and click on the "Environment" tab. Under Application Environment Variables, put **$GIT_TOKEN** for the Key. Now you'll need to create an access token in GitHub. How to do that is described on a [GitHub help page](https://help.github.com/articles/creating-an-access-token-for-command-line-use/). Copy and paste the access token you generated from GitHub into the Value box. **Make sure you check Protected** and then hit Add. + +![][14] + +[14]: /img/tutorials/automated-deployments/adding-a-deploy-step.png + +With the deploy step configured in Wercker, we can push the updated wercker.yml file to GitHub and it will create the GitHub pages site for us. The example site we used here is accessible under hugo-wercker.ig.nore.me + +## Conclusion + +From now on, any time you want to put a new post on your blog all you need to do is push your new page to GitHub and the rest will happen automatically. The source code for the example site used here is available on [GitHub](https://github.com/ArjenSchwarz/hugo-wercker-example), as is the [Hugo Build step](https://github.com/ArjenSchwarz/wercker-step-hugo-build) itself. + +If you want to see an example of how you can deploy to S3 instead of GitHub pages, take a look at [Wercker's documentation](http://devcenter.wercker.com/docs/deploy/s3.html) about how to set that up. diff --git a/docs/content/tutorials/create-a-multilingual-site.md b/docs/content/tutorials/create-a-multilingual-site.md new file mode 100644 index 000000000..8a2dd960e --- /dev/null +++ b/docs/content/tutorials/create-a-multilingual-site.md @@ -0,0 +1,168 @@ +--- +author: "Rick Cogley" +lastmod: 2015-12-24 +date: 2015-07-08 +linktitle: Multilingual Site +menu: + main: + parent: tutorials +prev: /tutorials/migrate-from-jekyll +title: Create a Multilingual Site +weight: 10 +--- + +> **Note:** Since v0.17 Hugo has built-in support for the creation of multilingual website. [Read more about it]({{< relref "content/multilingual.md" >}}). + +## Introduction + +Hugo allows you to create a multilingual site from its built-in tools. This tutorial will show one way to do it, and assumes: + +* You already know the basics about creating a Hugo site +* You have a separate domain name for each language +* You'll use `/data` files for some translation strings +* You'll use single, combined `layout` and `static` folders +* You'll use a subfolder for each language under `content` and `public` + +## Site Configs + +Create your site configs in the root of your repository, for example for an English and Japanese site. + +**English Config `config_en.toml`**: + +~~~toml +baseURL = "http://acme.com/" +title = "Acme Inc." +contentDir = "content/en" +publishDir = "public/en" + +[params] + locale = "en-US" +~~~ + +**Japanese Config `config_ja.toml`**: + +~~~toml +baseURL = "http://acme.jp/" +title = "有限会社アクミー" +contentDir = "content/ja" +publishDir = "public/ja" + +[params] + locale = "ja-JP" +~~~ + +If you had more domains and languages, you would just create more config files. The standard `config.toml` is what Hugo will run as a default, but since we're creating language-specific ones, you'll need to specify each config file when running `hugo server` or just `hugo` before deploying. + +## Prep Translation Strings in `/data` + +Create `.yaml` (or `.json` or `.toml`) files for each language, under `/data/translations`. + +**English Strings `en-US.yaml`**: + +~~~yaml +topSlogan: Acme Inc. +topSubslogan: You'll love us +... +~~~ + +**Japanese Strings `ja-JP.yaml`**: + +~~~yaml +topSlogan: 有限会社アクミー +topSubslogan: キット勝つぞ +... +~~~ + +In some cases, where there is more complex formatting within the strings you want to show, it might be better to employ some conditional logic in your template, to display a block of html per language. + +## Reference Strings in templates + +Now you can reference the strings in your templates. One way is to do it like in this `layouts/index.html`, leveraging the fact that you have the locale set: + +~~~html +<!DOCTYPE html> +<html lang="{{ .Site.Params.locale }}"> +... + <head> + <meta charset="utf-8"> + <title>{{ if eq .Site.Params.locale "en-US" }}{{ if .IsHome }}Welcome to {{ end }}{{ end }}{{ .Title }}{{ if eq .Site.Params.locale "ja-JP" }}{{ if .IsHome }}へようこそ{{ end }}{{ end }}{{ if ne .Title .Site.Title }} : {{ .Site.Title }}{{ end }}</title> + ... + </head> + <body> + <div class="container"> + <h1 class="header">{{ ( index $.Site.Data.translations $.Site.Params.locale ).topSlogan }}</h1> + <h3 class="subheader">{{ ( index $.Site.Data.translations $.Site.Params.locale ).topSubslogan }}</h3> + </div> + </body> +</html> +~~~ + +The above shows both techniques, using an `if eq` and `else if eq` to check the locale, and using `index` to pull strings from the data file that matches the locale set in the site's config file. + +## Customize Dates + +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: + +~~~toml +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: + +~~~html +<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. + +## Create Multilingual Content + +Now you can create markdown content in your languages, in the `content/en` and `content/ja` folders. The frontmatter stays the same on the key side, but the values would be set in each of the languages. + +## Run Hugo Server or Deploy Commands + +Once you have things set up, you can run `hugo server` or `hugo` before deploying. You can create scripts to do it, or as shell functions. Here are sample basic `zsh` functions: + +**Live Reload with `hugo server`**: + +~~~shell +function hugoserver-com { + cd /Users/me/dev/mainsite + hugo server --buildDrafts --verbose --source="/Users/me/dev/mainsite" --config="/Users/me/dev/mainsite/config_en.toml" --port=1377 +} +function hugoserver-jp { + cd /Users/me/dev/mainsite + hugo server --buildDrafts --verbose --source="/Users/me/dev/mainsite" --config="/Users/me/dev/mainsite/config_ja.toml" --port=1399 +} +~~~ + +**Deploy with `hugo` and `rsync`**: + +~~~shell +function hugodeploy-acmecom { + rm -rf /tmp/acme.com + hugo --config="/Users/me/dev/mainsite/config_en.toml" -s /Users/me/dev/mainsite/ -d /tmp/acme.com + rsync -avze "ssh -p 22" --delete /tmp/acme.com/ [email protected]:/home/me/webapps/acme_com_site +} + +function hugodeploy-acmejp { + rm -rf /tmp/acme.jp + hugo --config="/Users/me/dev/mainsite/config_ja.toml" -s /Users/me/dev/mainsite/ -d /tmp/acme.jp + rsync -avze "ssh -p 22" --delete /tmp/acme.jp/ [email protected]:/home/me/webapps/acme_jp_site +} +~~~ + +Adjust to fit your situation, setting dns, your webserver config, and other settings as appropriate. diff --git a/docs/content/tutorials/creating-a-new-theme.md b/docs/content/tutorials/creating-a-new-theme.md new file mode 100644 index 000000000..a0b95b5e6 --- /dev/null +++ b/docs/content/tutorials/creating-a-new-theme.md @@ -0,0 +1,1717 @@ +--- +author: "Michael Henderson" +lastmod: 2016-09-01 +date: 2015-11-26 +linktitle: Creating a New Theme +menu: + main: + parent: tutorials +next: /tutorials/github-pages-blog +prev: /tutorials/automated-deployments +title: Creating a New Theme +weight: 10 +--- +## Introduction + +This tutorial will show you how to create a simple theme in Hugo. + +I'll introduce Hugo's use of templates, +and explain how to organize them into a theme. +The theme will grow, minimizing effort while meeting evolving needs. +To promote this focus, and to keep everything simple, I'll omit CSS styling. + +We'll start by creating a tiny, blog-like web site. +We'll implement this blog with just one — quite basic — template. +Then we'll add an About page, and a few articles. +Overall, this web site (along with what you learn here) +will provide a good basis for you to continue working with Hugo in the future. +By making small variations, +you'll be able to create many different kinds of web sites. + +I will assume you're comfortable with HTML, Markdown formatting, +and the Bash command line (possibly using [Git for +Windows](https://git-for-windows.github.io/)). + +A few symbols might call for explanation: in this tutorial, +the commands you'll enter will be preceded by a `$` prompt — +and their output will follow. +`vi` means to open your editor; then `:wq` means to save the file. +Sometimes I'll add comments to explain a point — these start with `#`. +So, for example: +```bash +# this is a comment +$ echo this is a command +this is a command + +# edit the file +$ vi foo.md ++++ +date = "2040-01-18" +title = "creating a new theme" + ++++ +Bah! Humbug! +:wq + +# show it +$ cat foo.md ++++ +date = "2040-01-18" +title = "creating a new theme" + ++++ +Bah! Humbug! +``` +## Definitions + +Three concepts: + +1. _Non-content_ files; +1. _Templates_ (as Hugo defines them); and +1. _Front-matter_ + +are essential for creating your first Hugo theme, +as well as your first Hugo website. +### Non-Content + +The source files of a web site (destined to be rendered by Hugo) +are divided into two kinds: + +1. The files containing its textual content (and nothing else — +except Hugo front-matter: see below, and Markdown styling); and +1. All other files. (These contain ***no*** textual content — ideally.) + +Temporarily, let's affix the adjective _non-content_ +to the latter kind of source files. + +Non-content files are responsible for your web site's look and feel. +(Follow these article links from [Bop +Design](https://www.bopdesign.com/bop-blog/2013/11/what-is-the-look-and-feel-of-a-website-and-why-its-important/) +and +[Wikipedia](https://en.wikipedia.org/w/index.php?title=Look_and_feel&oldid=731052704) +if you wish for more information.) +They comprise its images, its CSS (for the sizes, colors and fonts), +its JavaScript (for the actions and reactions), and its Hugo templates +(which contain the rules Hugo uses to transform your content into HTML). + +Given these files, Hugo will render a static web site — +informed by your content — +which contains the above images, HTML, CSS and JavaScript, +ready to be served to visitors. + +Actually, a few of your invariant textual snippets +could reside in non-content files as well. +However, because someone might reuse your theme (eventually), +preferably you should keep those textual snippets in their own content files. +#### Where + +Regarding where to create your non-content files, you have two options. +The simplest is the `./layouts/` and `./static/` filesystem trees. +If you choose this way, +then you needn't worry about configuring Hugo to find them. +Invariably, these are the first two places Hugo seeks for templates +(as well as images, CSS and JavaScript); +so in that case, it's guaranteed to find all your non-content files. + +The second option is to create them in a filesystem tree +located somewhere under the `./themes/` directory. +If you choose that way, +then you must always tell Hugo where to search for them — +that's extra work, though. So, why bother? +#### Theme + +Well — the difference between creating your non-content files under +`./layouts/` and `./static/` and creating them under `./themes/` +is admittedly very subtle. +Non-content files created under `./layouts/` and `./static/` +cannot be customized without editing them directly. +On the other hand, non-content files created under `./themes/` +can be customized, in another way. That way is both conventional +(for Hugo web sites) and non-destructive. Therefore, +creating your non-content files under `./themes/` +makes it easier for other people to use them. + +The rest of this tutorial will call a set of non-content files a ***theme*** +if they comprise a filesystem tree rooted anywhere under the +`./themes/` directory. + +Note that you can use this tutorial to create your set of non-content files +under `./layouts/` and `./static/` if you wish. The only difference is that +you wouldn't need to edit your web site's configuration file +in order to select a theme. +### Home + +The home page, or landing page, +is the first page that many visitors to a web site will see. +Often this is `/index.html`, located at the root URL of the web site. +Since Hugo writes files into the `./public/` tree, +your home page will reside in file `./public/index.html`. +### Configure + +When Hugo runs, it first looks for an overall configuration file, +in order to read its settings, and applies them to the entire web site. +These settings override Hugo's default values. + +The file can be in TOML, YAML, or JSON format. +I prefer TOML for my configuration files. +If you prefer JSON or YAML, you'll need to translate my examples. +You'll also need to change the basename, since Hugo uses its extension +to determine how to process it. + +Hugo translates Markdown files into HTML. +By default, Hugo searches for Markdown files in the `./content/` tree +and template files under the `./themes/` directory. +It will render HTML files to the `./public/` tree. +You can override any of these defaults by specifying alternative locations +in the configuration file. +### Template + +_Templates_ direct Hugo in rendering content into HTML; +they bridge content and presentation. + +Rules in template files determine which content is published and where, +and precisely how it will be rendered into HTML files. +Templates also guide your web site's presentation +by specifying the CSS styling to use. + +Hugo uses its knowledge of each piece of content +to seek a template file to use in rendering it. +If it can't find a template that matches the content, it will zoom out, +one conceptual level; it will then resume the search from there. +It will continue to do so, till it finds a matching template, +or runs out of templates to try. +Its last resort is your web site's default template, +which could conceivably be missing. If it finds no suitable template, +it simply forgoes rendering that piece of content. + +It's important to note that _front-matter_ (see next) +can influence Hugo's template file selection process. +### Content + +Content is stored in text files which contain two sections. +The first is called _front-matter_: this is information about the content. +The second contains Markdown-formatted text, +destined for conversion to HTML format. +#### Front-Matter + +The _front-matter_ is meta-information describing the content. +Like the web site's configuration file, it can be written in the +TOML, YAML, or JSON formats. +Unlike the configuration file, Hugo doesn't use the file's extension +to determine the format. +Instead, it looks for markers in the file which signal this. +TOML is surrounded by "`+++`" and YAML by "`---`", but +JSON is enclosed in curly braces. I prefer to use TOML. +You'll need to translate my examples if you prefer YAML or JSON. + +Hugo informs its chosen template files with the front-matter information +before rendering the content in HTML. +#### Markdown + +Content is written in Markdown format, which makes it easy to create. +Hugo runs the content through a Markdown engine to transform it into HTML, +which it then renders to the output file. +### Template Kinds + +Here I'll discuss three kinds of Hugo templates: +_Single_, _List_, and _Partial_. +All these kinds take one or more pieces of content as input, +and transform the pieces, based on commands in the template. +#### Single + +A _Single_ template is used to render one piece of content. +For example, an article or a post is a single piece of content; +thus, it uses a Single template. +#### List + +A _List_ template renders a group of related content items. +This could be a summary of recent postings, +or all of the articles in a category. +List templates can contain multiple groups (or categories). + +The home page template is a special kind of List template. +This is because Hugo assumes that your home page will act as a portal +to all of the remaining content on your web site. +#### Partial + +A _Partial_ template is a template that's incapable of producing a web page, +by itself. To include a Partial template in your web site, +another template must call it, using the `partial` command. + +Partial templates are very handy for rolling up common behavior. +For example, you might want the same banner to appear on all +of your web site's pages — so, rather than copy your banner's text +into multiple content files, +as well as the other information relevant to your banner +into multiple template files (both Single and List), +you can instead create just one content file and one Partial template. +That way, whenever you decide to change the banner, you can do so +by editing one file only (or maybe two). +## Site + +Let's let Hugo help you create your new web site. +The `hugo new site` command will generate a skeleton — +it will give you a basic directory structure, along with +a usable configuration file: +```bash +$ cd /tmp/ + +$ hugo new site mySite + +$ cd mySite/ + +$ ls -l +total 8 +drwxr-xr-x 2 {user} {group} 68 {date} archetypes +-rw-r--r-- 1 {user} {group} 107 {date} config.toml +drwxr-xr-x 2 {user} {group} 68 {date} content +drwxr-xr-x 2 {user} {group} 68 {date} data +drwxr-xr-x 2 {user} {group} 68 {date} layouts +drwxr-xr-x 2 {user} {group} 68 {date} static +drwxr-xr-x 2 {user} {group} 68 {date} themes +``` +Take a look in the `./content/` and `./themes/` directories to confirm +they are empty. + +The other directories +(`./archetypes/`, `./data/`, `./layouts/` and `./static/`) +are used for customizing a named theme. +That's a topic for a different tutorial, so please ignore them for now. +### Render + +Running the `hugo` command with no options will read +all of the available content and render the HTML files. Also, it will copy +all the static files (that's everything besides content). +Since we have an empty web site, Hugo won't be doing much. +However, generally speaking, Hugo does this very quickly: +```bash +$ hugo --verbose +INFO: {date} {source} Using config file: /tmp/mySite/config.toml +WARN: {date} {source} No theme set +INFO: {date} {source} /tmp/mySite/static/ is the only static directory available to sync from +INFO: {date} {source} syncing static files to /tmp/mySite/public/ +Started building site +WARN: {date} {source} Unable to locate layout for homepage: [index.html _default/list.html] +WARN: {date} {source} "/" is rendered empty +============================================================= +Your rendered home page is blank: /index.html is zero-length + * Did you specify a theme on the command-line or in your + "config.toml" file? (Current theme: "") +============================================================= +WARN: {date} {source} Unable to locate layout for 404 page: [404.html] +WARN: {date} {source} "404.html" is rendered empty +0 draft content +0 future content +0 expired content +0 pages created +0 non-page files copied +0 paginator pages created +0 tags created +0 categories created +in 4 ms +``` +The "`--verbose`" flag gives extra information that will be helpful +whenever we are developing a template. +Every line of the output starting with "INFO:" or "WARN:" is present +because we used that flag. The lines that start with "WARN:" +are warning messages. We'll go over them later. + +We can verify that the command worked by looking at the directory again: +```bash +$ ls -l +total 8 +drwxr-xr-x 2 {user} {group} 68 {date} archetypes +-rw-r--r-- 1 {user} {group} 107 {date} config.toml +drwxr-xr-x 2 {user} {group} 68 {date} content +drwxr-xr-x 2 {user} {group} 68 {date} data +drwxr-xr-x 2 {user} {group} 68 {date} layouts +drwxr-xr-x 6 {user} {group} 204 {date} public +drwxr-xr-x 2 {user} {group} 68 {date} static +drwxr-xr-x 2 {user} {group} 68 {date} themes +``` +See that new `./public/` directory? +Hugo placed all its rendered content there. +When you're ready to publish your web site, that's the place to start. +For now, though, let's just confirm we have the files we expect +for a web site with no content: +```bash +$ ls -l public/ +total 16 +-rw-r--r-- 1 {user} {group} 0 {date} 404.html +-rw-r--r-- 1 {user} {group} 0 {date} index.html +-rw-r--r-- 1 {user} {group} 511 {date} index.xml +-rw-r--r-- 1 {user} {group} 210 {date} sitemap.xml +``` +Hugo rendered two XML files and some empty HTML files. +The XML files are used for RSS feeds. Hugo has an opinion about what +those feeds should contain, so it populated those files. +Hugo has no opinion on the look or content of your web site, +so it left those files empty. + +If you look back at the output from the `hugo server` command, +you'll notice that Hugo said: +```bash +0 pages created +``` +That's because Hugo doesn't count the home page, the 404 error page, +or the RSS feed files as pages. +### Serve + +Let's verify you can run the built-in web server — +that'll shorten your development cycle, dramatically. +Start it, by running the `hugo server` command. +If successful, you'll see output similar to the following: +```bash +$ hugo server --verbose +INFO: {date} {source} Using config file: /tmp/mySite/config.toml +WARN: {date} {source} No theme set +INFO: {date} {source} /tmp/mySite/static/ is the only static directory available to sync from +INFO: {date} {source} syncing static files to / +WARN: {date} {source} Unable to locate layout for homepage: [index.html _default/list.html] +WARN: {date} {source} "/" is rendered empty +============================================================= +Your rendered home page is blank: /index.html is zero-length + * Did you specify a theme on the command-line or in your + "config.toml" file? (Current theme: "") +============================================================= +WARN: {date} {source} Unable to locate layout for 404 page: [404.html] +WARN: {date} {source} "404.html" is rendered empty +0 draft content +0 future content +0 expired content +0 pages created +0 non-page files copied +0 paginator pages created +0 tags created +0 categories created +in 3 ms +Watching for changes in /tmp/mySite/{data,content,layouts,static} +Serving pages from memory +Web Server is available at http://localhost:1313/ (bind address 127.0.0.1) +Press Ctrl+C to stop +``` +Connect to the listed URL (it's on the line that begins with +`Web Server is available`). If everything's working correctly, +you should get a page that shows nothing. +### Warnings + +Let's go back and look at some of those warnings again: +```bash +WARN: {date} {source} Unable to locate layout for 404 page: [404.html] +WARN: {date} {source} Unable to locate layout for homepage: [index.html _default/list.html] +``` +The 404 warning is easy to explain — it's because we haven't created +the template file `layouts/404.html`. Hugo uses this to render an HTML file +which serves "page not found" errors. However, +the 404 page is a topic for a separate tutorial. + +Regarding the home page warning: the first layout Hugo looked for was +`layouts/index.html`. Note that Hugo uses this file for the home page only. + +It's good that Hugo lists the files it seeks, when +we give it the verbose flag. For the home page, these files are +`layouts/index.html` and `layouts/_default/list.html`. +Later, we'll cover some rules which explain these paths +(including their basenames). For now, just remember that +Hugo couldn't find a template to use for the home page, and it said so. + +All right! So, now — after these few steps — you have a working +installation, and a web site foundation you can build upon. +All that's left is to add some content, as well as a theme to display it. +## Theme + +Hugo doesn't ship with a default theme. However, a large number of themes +are easily available: for example, at +[hugoThemes](https://github.com/gohugoio/hugoThemes). +Also, Hugo comes with a command to generate them. + +We're going to generate a new theme called Zafta. +The goal of this tutorial is simply to show you how to create +(in a theme) the minimal files Hugo needs in order to display your content. +Therefore, the theme will exclude CSS — +it'll be functional, not beautiful. + +Every theme has its own opinions on content and layout. For example, this +Zafta theme prefers the Type "article" over the Types "blog" or "post." +Strong opinions make for simpler templates, but unconventional opinions +make themes tougher for other users. So when you develop a theme, you should +consider the value of adopting the terms used by themes similar to yours. +### Skeleton + +Let's press Ctrl+C and use the `hugo new theme` command +to generate the skeleton of a theme. The result is a directory structure +containing empty files for you to fill out: +```bash +$ hugo new theme zafta + +$ find themes -type f | xargs ls -l +-rw-r--r-- 1 {user} {group} 8 {date} themes/zafta/archetypes/default.md +-rw-r--r-- 1 {user} {group} 0 {date} themes/zafta/layouts/404.html +-rw-r--r-- 1 {user} {group} 0 {date} themes/zafta/layouts/_default/list.html +-rw-r--r-- 1 {user} {group} 0 {date} themes/zafta/layouts/_default/single.html +-rw-r--r-- 1 {user} {group} 0 {date} themes/zafta/layouts/index.html +-rw-r--r-- 1 {user} {group} 0 {date} themes/zafta/layouts/partials/footer.html +-rw-r--r-- 1 {user} {group} 0 {date} themes/zafta/layouts/partials/header.html +-rw-r--r-- 1 {user} {group} 1081 {date} themes/zafta/LICENSE.md +-rw-r--r-- 1 {user} {group} 450 {date} themes/zafta/theme.toml +``` +The skeleton includes templates (files ending in `.html`), a license file, +a description of your theme (`theme.toml`), and a default archetype file. + +When you're developing a real theme, please remember to fill out files +`theme.toml` and `LICENSE.md`. They're optional, but if you're going to +distribute your theme, it tells the world who to praise (or blame). +It's also important to declare your choice of license, so people will know +whether (or where) they can use your theme. + +Note that the skeleton theme's template files are empty. Don't worry; +we'll change that shortly: +```bash +$ find themes/zafta -name '*.html' | xargs ls -l +-rw-r--r-- 1 {user} {group} 0 {date} themes/zafta/layouts/404.html +-rw-r--r-- 1 {user} {group} 0 {date} themes/zafta/layouts/_default/list.html +-rw-r--r-- 1 {user} {group} 0 {date} themes/zafta/layouts/_default/single.html +-rw-r--r-- 1 {user} {group} 0 {date} themes/zafta/layouts/index.html +-rw-r--r-- 1 {user} {group} 0 {date} themes/zafta/layouts/partials/footer.html +-rw-r--r-- 1 {user} {group} 0 {date} themes/zafta/layouts/partials/header.html +``` +### Select + +Now that we've created a theme we can work with, it's a good idea +to add its name to the configuration file. This is optional, because +it's possible to add "-t zafta" to all your commands. +I like to put it in the configuration file because I like +shorter command lines. If you don't put it in the configuration file, +or specify it on the command line, sometimes you won't get the template +you're expecting. + +So, let's edit your configuration file to add the theme name: +```toml +$ vi config.toml +theme = "zafta" +baseURL = "http://example.org/" +title = "My New Hugo Site" +languageCode = "en-us" +:wq +``` +### Themed Render + +Now that we have a theme (albeit empty), let's render the web site again: +```bash +$ hugo --verbose +INFO: {date} {source} Using config file: /tmp/mySite/config.toml +INFO: {date} {source} using a UnionFS for static directory comprised of: +INFO: {date} {source} Base: /tmp/mySite/themes/zafta/static +INFO: {date} {source} Overlay: /tmp/mySite/static/ +INFO: {date} {source} syncing static files to /tmp/mySite/public/ +Started building site +WARN: {date} {source} "/" is rendered empty +============================================================= +Your rendered home page is blank: /index.html is zero-length + * Did you specify a theme on the command-line or in your + "config.toml" file? (Current theme: "zafta") +============================================================= +WARN: {date} {source} "404.html" is rendered empty +0 draft content +0 future content +0 expired content +0 pages created +0 non-page files copied +0 paginator pages created +0 tags created +0 categories created +in 4 ms +``` +Did you notice the output is different? +Two previous warning messages have disappeared, which contained the words +"Unable to locate layout" for your home page and the 404 page. +And, a new informational message tells us Hugo is accessing your theme's tree +(`./themes/zafta/`). + +Let's check the `./public/` directory to see what Hugo rendered: +```bash +$ ls -l public/ +total 16 +-rw-r--r-- 1 {user} {group} 0 {date} 404.html +drwxr-xr-x 2 {user} {group} 68 {date} css +-rw-r--r-- 1 {user} {group} 0 {date} index.html +-rw-r--r-- 1 {user} {group} 511 {date} index.xml +drwxr-xr-x 2 {user} {group} 68 {date} js +-rw-r--r-- 1 {user} {group} 210 {date} sitemap.xml +``` +It's similar to what we had before, without a theme. +We'd expect so, since all your theme's templates are empty. But notice: +in `./public/`, Hugo created the `css/` and `js/` directories. +That's because Hugo found them in your theme's `static/` directory: +```bash +$ ls -l themes/zafta/static/ +total 0 +drwxr-xr-x 2 {user} {group} 68 {date} css +drwxr-xr-x 2 {user} {group} 68 {date} js +``` +#### Home + +In a Hugo web site, each kind of page is informed (primarily) by just one +of the many different kinds of templates available; +yet the home page is special, because it gets its own kind of template, +and its own template file. + +Hugo uses template file `layouts/index.html` to render the home page's HTML. +Although Hugo's documentation may state that this file is the home page's +only required template, Hugo's earlier warning message showed it actually +looks for two different templates: +```bash +WARN: {date} {source} Unable to locate layout for homepage: [index.html _default/list.html] +``` +#### Empty + +When Hugo generated your theme, it included an empty home page template. +Whenever Hugo renders your web site, it seeks that same template and uses it +to render the HTML for the home page. Currently, the template file is empty, +so the output HTML file is empty, too. Whenever we add rules to that template, +Hugo will use them in rendering the home page: +```bash +$ find * -name index.html | xargs ls -l +-rw-r--r-- 1 {user} {group} 0 {date} public/index.html +-rw-r--r-- 1 {user} {group} 0 {date} themes/zafta/layouts/index.html +``` +As we'll see later, Hugo follows this same pattern for all its templates. +## Static Files + +Hugo does two things when it renders your web site. +Besides using templates to transform your content into HTML, +it also incorporates your static files. Hugo's rule is simple: +unlike with templates and content, static files aren't transformed. +Hugo copies them over, exactly as they are. + +Hugo assumes that your web site will use both CSS and JavaScript, +so it generates some directories in your theme to hold them. +Remember opinions? Well, Hugo's opinion is that you'll store your CSS +in directory `static/css/`, and your JavaScript in directory `static/js/`. +If you don't like that, you can relocate these directories +or change their names (as long as they remain in your theme's `static/` tree), +or delete them completely. +Hugo is nice enough to offer its opinion; yet it still behaves nicely, +if you disagree: +```bash +$ find themes/zafta/* -type d | xargs ls -dl +drwxr-xr-x 3 {user} {group} 102 {date} themes/zafta/archetypes +drwxr-xr-x 6 {user} {group} 204 {date} themes/zafta/layouts +drwxr-xr-x 4 {user} {group} 136 {date} themes/zafta/layouts/_default +drwxr-xr-x 4 {user} {group} 136 {date} themes/zafta/layouts/partials +drwxr-xr-x 4 {user} {group} 136 {date} themes/zafta/static +drwxr-xr-x 2 {user} {group} 68 {date} themes/zafta/static/css +drwxr-xr-x 2 {user} {group} 68 {date} themes/zafta/static/js +``` +## Theme Development + +Generally (using any kind of software), working on a theme means +changing your files, serving your web site again, and then verifying +the resulting improvements in your browser. +With Hugo, this way of working is quite easy: + +- First purge the `./public/` tree. (This is optional but useful, +if you want to start with a clean slate.) +- Run the built-in Hugo web server. +- Open your web site in a browser — and then: + +1. Edit your theme; +1. Glance at your browser window to see your changes; and +1. Repeat. + +I'll throw in one more opinion: ***never*** directly edit a theme on a live +web site. Instead, always develop ***using a copy***. First, make some changes +to your theme and test them. Afterwards, **when you've got them working,** +copy them to your web site. For added safety, use a tool like Git to keep +some revision history of your content, and of your theme. Believe me: +it's too easy to lose your changes, and your mind! + +Check out the main Hugo web site for information about using Git with Hugo. +### Purge + +When rendering your web site, Hugo will create new files in the `./public/` +tree and update existing ones. But it won't delete files that are +no longer used. For example, files previously rendered with +(what is now) the wrong basename, or in the wrong directory, will remain. +Later, if you leave them, they'll likely confuse you. +Cleaning out your `./public/` files prior to rendering can help. + +When Hugo is running in web server mode (as of version 0.15), +it doesn't actually write the files. Instead, +it keeps all the rendered files in memory. So, you can "clean" up +your files simply by stopping and restarting the web server. +### Serve +#### Watch + +Hugo's watch functionality monitors the relevant content, theme and +(overriding) site trees for filesystem changes, +and renders your web site again automatically, when changes are detected. + +By default, watch is +enabled when in web server mode (`hugo server`), +but disabled for the web site renderer (`hugo`). + +In some use cases, +Hugo's web site renderer should continue running and watch — simply +type `hugo --watch` on the command line. + +Sometimes with Docker containers (and Heroku slugs), +the site sources may live on a read-only filesystem. +In that scenario, it makes no sense +for Hugo's web server to watch for file changes — so +use `hugo server --watch=false`. +#### Reload + +Hugo's built in web server includes +[LiveReload](/extras/livereload/) functionality. When any page is updated +in the filesystem, the web browser is told to refresh its currently-open tabs +from your web site. Usually, this happens faster than you can say, +"Wow, that's totally amazing!" +### Workflow + +Again, +I recommend you use the following commands as the basis for your workflow: +```bash +# purge old files. Hugo will recreate the public directory +$ rm -rf public/ + +# run Hugo in watch mode with LiveReload; +# when you're done, stop the web server +$ hugo server --verbose +Press Ctrl+C to stop +``` +Below is some sample output showing Hugo detecting a change in the home page +template. (Actually, the change is the edit we're about to do.) Once it's +rendered again, the web browser automatically reloads the page. + +(As I said above — it's amazing:) +```bash +$ rm -rf public/ + +$ hugo server --verbose +INFO: {date} {source} Using config file: /tmp/mySite/config.toml +INFO: {date} {source} using a UnionFS for static directory comprised of: +INFO: {date} {source} Base: /tmp/mySite/themes/zafta/static +INFO: {date} {source} Overlay: /tmp/mySite/static/ +INFO: {date} {source} syncing static files to / +Started building site +WARN: {date} {source} "/" is rendered empty +============================================================= +Your rendered home page is blank: /index.html is zero-length + * Did you specify a theme on the command-line or in your + "config.toml" file? (Current theme: "") +============================================================= +WARN: {date} {source} "404.html" is rendered empty +0 draft content +0 future content +0 expired content +0 pages created +0 non-page files copied +0 paginator pages created +0 tags created +0 categories created +in 4 ms +Watching for changes in /tmp/mySite/{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 +INFO: {date} {source} Received System Events: ["/tmp/mySite/themes/zafta/layouts/index.html": WRITE] + +Change detected, rebuilding site +{date} +Template changed /tmp/mySite/themes/zafta/layouts/index.html +WARN: {date} {source} "404.html" is rendered empty +0 draft content +0 future content +0 expired content +0 pages created +0 non-page files copied +0 paginator pages created +0 tags created +0 categories created +in 3 ms +``` +## Home Template + +The home page is one of the few special pages Hugo renders automatically. +As mentioned earlier, it looks in your theme's `layouts/` tree for one +of two files: + +1. `index.html` +1. `_default/list.html` + +We could edit the default template, but a good design principle is to edit +the most specific template available. That's not a hard-and-fast rule +(in fact, in this tutorial, we'll break it a few times), +but it's a good generalization. +### Static + +Right now, your home page is empty because you've added no content, +and because its template includes no logic. Let's change that by adding +some text to your home page template (`layouts/index.html`): +```html +$ vi themes/zafta/layouts/index.html +<!DOCTYPE html> +<html> +<body> + <p>Hugo says hello!</p> +</body> +</html> +:wq +``` +Let's press Ctrl+C and render the web site, and then verify the results: +```html +$ rm -rf public/ + +$ hugo --verbose +INFO: {date} {source} Using config file: /tmp/mySite/config.toml +INFO: {date} {source} using a UnionFS for static directory comprised of: +INFO: {date} {source} Base: /tmp/mySite/themes/zafta/static +INFO: {date} {source} Overlay: /tmp/mySite/static/ +INFO: {date} {source} syncing static files to /tmp/mySite/public/ +Started building site +WARN: {date} {source} "404.html" is rendered empty +0 draft content +0 future content +0 expired content +0 pages created +0 non-page files copied +0 paginator pages created +0 tags created +0 categories created +in 4 ms + +$ ls -l public/index.html +-rw-r--r-- 1 {user} {group} 72 {date} public/index.html + +$ cat public/index.html +<!DOCTYPE html> +<html> +<body> + <p>Hugo says hello!</p> +</body> +</html> +``` +### Dynamic + +A ***dynamic*** home page? Because Hugo is a _static web site_ generator, +the word _dynamic_ seems odd, doesn't it? But this means arranging for your +home page to reflect the content in your web site automatically, +each time Hugo renders it. + +To accomplish that, later we'll add an iterator to your home page template. +## Article + +Now that Hugo is successfully rendering your home page with static content, +let's add more pages to your web site. We'll display some new articles +as a list on your home page; and we'll display each article +on its own page, too. + +Hugo has a command to generate an entry skeleton for new content, +just as it does for web sites and themes: +```bash +$ hugo --verbose new article/First.md +INFO: {date} {source} Using config file: /tmp/mySite/config.toml +INFO: {date} {source} attempting to create article/First.md of article +INFO: {date} {source} curpath: /tmp/mySite/themes/zafta/archetypes/default.md +INFO: {date} {source} creating /tmp/mySite/content/article/First.md +/tmp/mySite/content/article/First.md created + +$ ls -l content/article/ +total 8 +-rw-r--r-- 1 {user} {group} 61 {date} First.md +``` +Let's generate a second article, while we're here: +```bash +$ hugo --verbose new article/Second.md +INFO: {date} {source} Using config file: /tmp/mySite/config.toml +INFO: {date} {source} attempting to create article/Second.md of article +INFO: {date} {source} curpath: /tmp/mySite/themes/zafta/archetypes/default.md +INFO: {date} {source} creating /tmp/mySite/content/article/Second.md +/tmp/mySite/content/article/Second.md created + +$ ls -l content/article/ +total 16 +-rw-r--r-- 1 {user} {group} 61 {date} First.md +-rw-r--r-- 1 {user} {group} 62 {date} Second.md +``` +Let's edit both those articles. Be careful to preserve their front-matter, +but append some text to their bodies, as follows: +```bash +$ vi content/article/First.md +In vel ligula tortor. Aliquam erat volutpat. +Pellentesque at felis eu quam tincidunt dignissim. +Nulla facilisi. + +Pellentesque tempus nisi et interdum convallis. +In quam ante, vulputate at massa et, rutrum +gravida dui. Phasellus tristique libero at ex. +:wq + +$ vi content/article/Second.md +Fusce lacus magna, maximus nec sapien eu, +porta efficitur neque. Aliquam erat volutpat. +Vestibulum enim nibh, posuere eu diam nec, +varius sagittis turpis. + +Praesent quis sapien egestas mauris accumsan +pulvinar. Ut mattis gravida venenatis. Vivamus +lobortis risus id nisi rutrum, at iaculis. +:wq +``` +So, for example, `./content/article/Second.md` becomes: +```toml +$ cat content/article/Second.md ++++ +date = "2040-01-18T21:08:08-06:00" +title = "Second" + ++++ +Fusce lacus magna, maximus nec sapien eu, +porta efficitur neque. Aliquam erat volutpat. +Vestibulum enim nibh, posuere eu diam nec, +varius sagittis turpis. + +Praesent quis sapien egestas mauris accumsan +pulvinar. Ut mattis gravida venenatis. Vivamus +lobortis risus id nisi rutrum, at iaculis. +``` +Let's render the web site, and then verify the results: +```bash +$ rm -rf public/ + +$ hugo --verbose +INFO: {date} {source} Using config file: /tmp/mySite/config.toml +INFO: {date} {source} using a UnionFS for static directory comprised of: +INFO: {date} {source} Base: /tmp/mySite/themes/zafta/static +INFO: {date} {source} Overlay: /tmp/mySite/static/ +INFO: {date} {source} syncing static files to /tmp/mySite/public/ +Started building site +INFO: {date} {source} found taxonomies: map[string]string{"tag":"tags", "category":"categories"} +WARN: {date} {source} "article" is rendered empty +WARN: {date} {source} "article/Second.html" is rendered empty +WARN: {date} {source} "article/First.html" is rendered empty +WARN: {date} {source} "404.html" is rendered empty +0 draft content +0 future content +0 expired content +2 pages created +0 non-page files copied +0 paginator pages created +0 tags created +0 categories created +in 7 ms +``` +The output says Hugo rendered ("created") two pages. +Those pages are your new articles: +```bash +$ find public -type f -name '*.html' | xargs ls -l +-rw-r--r-- 1 {user} {group} 0 {date} public/404.html +-rw-r--r-- 1 {user} {group} 0 {date} public/article/First/index.html +-rw-r--r-- 1 {user} {group} 0 {date} public/article/index.html +-rw-r--r-- 1 {user} {group} 0 {date} public/article/Second/index.html +-rw-r--r-- 1 {user} {group} 72 {date} public/index.html +``` +The new pages are empty, because Hugo rendered their HTML from empty +template files. The home page doesn't show us the new content, either: +```html +$ cat public/index.html +<!DOCTYPE html> +<html> +<body> + <p>Hugo says hello!</p> +</body> +</html> +``` +So, we have to edit the templates, in order to pick up the articles. +### Single & List + +Here again I'll discuss three kinds of Hugo templates. One kind is +the home page template we edited previously; it's applicable only to +the home page. Another kind is Single templates, which render output for +just one content file. The third kind are List templates, which group +multiple pieces of content before rendering output. + +It's important to note that, generally, List templates +(except the home page template) are named `list.html`; +and Single templates are named `single.html`. + +Hugo also has three other kinds of templates: +Partials, _Content Views_, and _Terms_. +We'll give examples of some Partial templates; but otherwise, +we won't go into much detail about these. +### Home + +You'll want your home page to list the articles you just created. +So, let's alter its template file (`layouts/index.html`) to show them. +Hugo runs each template's logic whenever it renders that template's web page +(of course): +```html +$ vi themes/zafta/layouts/index.html +<!DOCTYPE html> +<html> +<body> + {{- range first 10 .Data.Pages }} + <h4><a href="{{ .Permalink }}">{{ .Title }}</a></h4> + {{- end }} +</body> +</html> +:wq +``` +#### Engine + +Hugo uses the [Go language's template +engine](https://gohugo.io/templates/go-templates/). +That engine scans your template files for commands enclosed between +"{{" and "}}" (these are doubled, curly braces — affectionately +known as "mustaches"). + +BTW, a hyphen, if placed immediately after an opening mustache, or +immediately before a closing one, will prevent extraneous newlines. +(This can make Hugo's output look better, when viewed as text.) + +So, the mustache commands in your newly-altered template are: + +1. `range ...` +1. `.Permalink` +1. `.Title` +1. `end` + +The `range` command is an iterator. We're using it to go through the latest +ten pages. (Hugo characterizes some of its HTML output files as "pages," +but not all — see above.) + +Looping through the list of data pages will consider each such HTML file +that Hugo renders (or rather — to speak more precisely — each +such HTML file that Hugo currently calculates it _will_ render). + +It's helpful to remember that Hugo sets some variables, such as `.Data`, quite +early in its overall processing. Hugo loads information from every content +file into that variable, and gives all the templates a chance to process that +variable's contents, before actually rendering any HTML output files. + +`.Permalink` supplies the URL which links to that article's page, and +`.Title` supplies the value of its "title" variable. Hugo obtains this +from the front-matter in the article's Markdown file. + +Automatically, the pages are considered in descending order of the generation +times of their Markdown files (actually, based on the value of the "date" +variable in their front-matter) so that the latest is first (naturally). + +The `end` command signals the end of the range iterator. The engine +loops back to the top of the iterator, whenever it finds `end.` +Everything between `range` and `end` is reevaluated, +each time the engine goes through the iterator. + +For the present template, this means that the titles of your latest +ten pages (or however many exist, if that's less) become the +[textContent](https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent) +of an equivalent number of copies Hugo makes, of your level-four +subheading tags (and anchor tags). `.Permalink` enables these to link +to the actual articles. + +Let's render your web site, and then verify the results: +```html +$ rm -rf public/ + +$ hugo --verbose +INFO: {date} {source} Using config file: /tmp/mySite/config.toml +INFO: {date} {source} using a UnionFS for static directory comprised of: +INFO: {date} {source} Base: /tmp/mySite/themes/zafta/static +INFO: {date} {source} Overlay: /tmp/mySite/static/ +INFO: {date} {source} syncing static files to /tmp/mySite/public/ +Started building site +INFO: {date} {source} found taxonomies: map[string]string{"tag":"tags", "category":"categories"} +WARN: {date} {source} "article" is rendered empty +WARN: {date} {source} "article/Second.html" is rendered empty +WARN: {date} {source} "article/First.html" is rendered empty +WARN: {date} {source} "404.html" is rendered empty +0 draft content +0 future content +0 expired content +2 pages created +0 non-page files copied +0 paginator pages created +0 tags created +0 categories created +in 7 ms + +$ find public -type f -name '*.html' | xargs ls -l +-rw-r--r-- 1 {user} {group} 0 {date} public/404.html +-rw-r--r-- 1 {user} {group} 0 {date} public/article/First/index.html +-rw-r--r-- 1 {user} {group} 0 {date} public/article/index.html +-rw-r--r-- 1 {user} {group} 0 {date} public/article/Second/index.html +-rw-r--r-- 1 {user} {group} 232 {date} public/index.html + +$ cat public/index.html +<!DOCTYPE html> +<html> +<body> + <h4><a href="http://example.org/article/Second/">Second</a></h4> + <h4><a href="http://example.org/article/First/">First</a></h4> +</body> +</html> +``` +### All Done + +Congratulations! Your home page shows the titles of your two articles, along +with the links to them. The articles themselves are still empty. But, +let's take a moment to appreciate what we've done, so far! + +Your home page template (`layouts/index.html`) now renders output dynamically. +Believe it or not, by inserting the range command inside those doubled +curly braces, you've learned everything you need to know — +essentially — about developing a theme. + +All that's left is understanding which of your templates renders each content +file, and becoming more familiar with the commands for the template engine. +## More + +Well — if things were so simple, this tutorial would be much shorter! + +Some things are still useful to learn, because they'll make creating new +templates _much_ easier — so, I'll cover them, now. +### Base URL + +While developing and testing your theme, did you notice that the links in the +rendered `./public/index.html` file use the full "baseURL" from your +`./config.toml` file? That's because those files are intended to be deployed +to your web server. + +Whenever you test your theme, you start Hugo in web server mode +(with `hugo server`) and connect to it with your web browser. +That command is smart enough to replace the "baseURL" with +`http://localhost:1313` on the fly, so that the links automatically +work for you. + +That's another reason why we recommend testing with the built-in web server. +### Content + +The articles you've been working with are in your `./content/article/` +directory. That means their _Section_ (as far as templates are concerned) +is "article". Unless we do something unusual in their front-matter, their +_Type_ is also "article". +#### Search + +Hugo uses the Section and Type to find a template file for every piece of +content it renders. Hugo first will seek a template file in subdirectories of +`layouts/` that match its Section or Type name (i.e., in `layouts/SECTION/` +or `layouts/TYPE/`). If it can't find a file there, then it will look in the +`layouts/_default/` directory. Other documentation covers some twists about +categories and tags, but we won't use those in this tutorial. Therefore, +we can assume that Hugo will try first `layouts/article/single.html`, then +`layouts/_default/single.html`. + +Now that we know the search rule, let's see what's available: +```bash +$ find themes/zafta -name single.html | xargs ls -l +-rw-r--r-- 1 {user} {group} 0 {date} themes/zafta/layouts/_default/single.html +``` +If you look back at the articles Hugo has rendered, you can see that +they were empty. Now we can see that this is because Hugo sought +`layouts/article/single.html` but couldn't find it, and template +`layouts/_default/single.html` was empty. Therefore, the rendered article +file was empty, too. + +So, we could either create a new template, `layouts/article/single.html`, +or edit the default one. +#### Default Single + +Since we know of no other content Types, let's start by editing the default +template file, `layouts/_default/single.html`. + +As we mentioned earlier, you always should edit (or create) the most +specific template first, in order to avoid accidentally changing how other +content is displayed. However, we're breaking that rule intentionally, +just so we can explore how the default is used. + +Remember, any content — for which we don't create a specific template +— will end up using this default template. That can be good or bad. +Bad, because I know we'll be adding different Types of content, and we'll +eventually undo some of the changes we've made. Good, because then we'll be +able to see some results immediately. It's also good to create the default +template first, because with it, we can start to develop the basic layout +for the web site. + +As we add more content Types, we'll refactor this file and move its logic +around. Hugo makes this fairly painless, so we'll accept the cost and proceed. + +Please see Hugo's documentation on template rendering, for all the details on +determining which template to use. And, as the documentation mentions, if +your web site is a single-page application (SPA), you can delete all the +other templates and work with just the default Single one. By itself, +that fact provides a refreshing amount of joy. + +Let's edit the default template file (`layouts/_default/single.html`): +```html +$ vi themes/zafta/layouts/_default/single.html +<!DOCTYPE html> +<html> +<head> + <title>{{ .Title }}</title> +</head> +<body> + <h1>{{ .Title }}</h1> + <h6>{{ .Date.Format "Mon, Jan 2, 2006" }}</h6> + {{ .Content }} + <h4><a href="{{ .Site.BaseURL }}">Home</a></h4> +</body> +</html> +:wq +``` +#### Verify + +Let's render the web site, and verify the results: +```bash +$ rm -rf public/ + +$ hugo --verbose +INFO: {date} {source} Using config file: /tmp/mySite/config.toml +INFO: {date} {source} using a UnionFS for static directory comprised of: +INFO: {date} {source} Base: /tmp/mySite/themes/zafta/static +INFO: {date} {source} Overlay: /tmp/mySite/static/ +INFO: {date} {source} syncing static files to /tmp/mySite/public/ +Started building site +INFO: {date} {source} found taxonomies: map[string]string{"tag":"tags", "category":"categories"} +WARN: {date} {source} "article" is rendered empty +WARN: {date} {source} "404.html" is rendered empty +0 draft content +0 future content +0 expired content +2 pages created +0 non-page files copied +0 paginator pages created +0 tags created +0 categories created +in 7 ms + +$ find public -type f -name '*.html' | xargs ls -l +-rw-r--r-- 1 {user} {group} 0 {date} public/404.html +-rw-r--r-- 1 {user} {group} 473 {date} public/article/First/index.html +-rw-r--r-- 1 {user} {group} 0 {date} public/article/index.html +-rw-r--r-- 1 {user} {group} 514 {date} public/article/Second/index.html +-rw-r--r-- 1 {user} {group} 232 {date} public/index.html +``` +Note that although Hugo rendered a file, to list your articles: +`./public/article/index.html`, the file is empty, because we don't have +a template for it. (However: see next.) The other HTML files contain your +content, as we can see below: +```html +$ cat public/article/First/index.html +<!DOCTYPE html> +<html> +<head> + <title>First</title> +</head> +<body> + <h1>First</h1> + <h6>Wed, Jan 18, 2040</h6> + <p>In vel ligula tortor. Aliquam erat volutpat. +Pellentesque at felis eu quam tincidunt dignissim. +Nulla facilisi.</p> + +<p>Pellentesque tempus nisi et interdum convallis. +In quam ante, vulputate at massa et, rutrum +gravida dui. Phasellus tristique libero at ex.</p> + + <h4><a href="http://example.org/">Home</a></h4> +</body> +</html> + +$ cat public/article/Second/index.html +<!DOCTYPE html> +<html> +<head> + <title>Second</title> +</head> +<body> + <h1>Second</h1> + <h6>Wed, Jan 18, 2040</h6> + <p>Fusce lacus magna, maximus nec sapien eu, +porta efficitur neque. Aliquam erat volutpat. +Vestibulum enim nibh, posuere eu diam nec, +varius sagittis turpis.</p> + +<p>Praesent quis sapien egestas mauris accumsan +pulvinar. Ut mattis gravida venenatis. Vivamus +lobortis risus id nisi rutrum, at iaculis.</p> + + <h4><a href="http://example.org/">Home</a></h4> +</body> +</html> +``` +Again, notice that your rendered article files have content. +You can run `hugo server` and use your browser to confirm this. +You should see your home page, and it should contain the titles of both +articles. Each title should be a link to its respective article. + +Each article should be displayed fully on its own page. And at the bottom of +each article, you should see a link which takes you back to your home page. +### Article List + +Your home page still lists your most recent articles. However — +remember, from above, that I mentioned an empty file, +`./public/article/index.html`? +Let's make that show a list of ***all*** of your articles +(not just the latest ten). + +We need to decide which template to edit. Key to this, is that +individual pages always come from Single templates. On the other hand, +only List templates are capable of rendering pages which display collections +(or lists) of other pages. + +Because the new page will show a listing, we should select a List template. +Let's take a quick look to see which List templates are available already: +```bash +$ find themes/zafta -name list.html | xargs ls -l +-rw-r--r-- 1 {user} {group} 0 {date} themes/zafta/layouts/_default/list.html +``` +So, just as before with the single articles, so again now with the list of +articles, we must decide: whether to edit `layouts/_default/list.html`, +or to create `layouts/article/list.html`. +#### Default List + +We still don't have multiple content Types — so, remaining consistent, +let's edit the default List template: +```html +$ vi themes/zafta/layouts/_default/list.html +<!DOCTYPE html> +<html> +<body> + <h1>Articles</h1> + {{- range first 10 .Data.Pages }} + <h4><a href="{{ .Permalink }}">{{ .Title }}</a></h4> + {{- end }} + <h4><a href="{{ .Site.BaseURL }}">Home</a></h4> +</body> +</html> +:wq +``` +Let's render everything again: +```bash +$ rm -rf public/ + +$ hugo --verbose +INFO: {date} {source} Using config file: /tmp/mySite/config.toml +INFO: {date} {source} using a UnionFS for static directory comprised of: +INFO: {date} {source} Base: /tmp/mySite/themes/zafta/static +INFO: {date} {source} Overlay: /tmp/mySite/static/ +INFO: {date} {source} syncing static files to /tmp/mySite/public/ +Started building site +INFO: {date} {source} found taxonomies: map[string]string{"tag":"tags", "category":"categories"} +WARN: {date} {source} "404.html" is rendered empty +0 draft content +0 future content +0 expired content +2 pages created +0 non-page files copied +0 paginator pages created +0 categories created +0 tags created +in 7 ms + +$ find public -type f -name '*.html' | xargs ls -l +-rw-r--r-- 1 {user} {group} 0 {date} public/404.html +-rw-r--r-- 1 {user} {group} 473 {date} public/article/First/index.html +-rw-r--r-- 1 {user} {group} 327 {date} public/article/index.html +-rw-r--r-- 1 {user} {group} 514 {date} public/article/Second/index.html +-rw-r--r-- 1 {user} {group} 232 {date} public/index.html +``` +Now (as you can see), we have a list of articles. To confirm it, +type `hugo server`; then, in your browser, navigate to `/article/`. +(Later, we'll link to it.) +## About + +Let's add an About page, and try to display it at the top level +(as opposed to the next level down, where we placed your articles). +### Guide + +Hugo's default goal is to let the directory structure of the `./content/` +tree guide the location of the HTML it renders to the `./public/` tree. +Let's check this, by generating an About page at the content's top level: +```toml +$ hugo new About.md +/tmp/mySite/content/About.md created + +$ ls -l content/ +total 8 +-rw-r--r-- 1 {user} {group} 61 {date} About.md +drwxr-xr-x 4 {user} {group} 136 {date} article + +$ vi content/About.md ++++ +date = "2040-01-18T22:01:00-06:00" +title = "About" + ++++ +Neque porro quisquam est qui dolorem +ipsum quia dolor sit amet consectetur +adipisci velit. +:wq +``` +### Check + +Let's render your web site, and check the results: +```html +$ rm -rf public/ + +$ hugo --verbose +INFO: {date} {source} Using config file: /tmp/mySite/config.toml +INFO: {date} {source} using a UnionFS for static directory comprised of: +INFO: {date} {source} Base: /tmp/mySite/themes/zafta/static +INFO: {date} {source} Overlay: /tmp/mySite/static/ +INFO: {date} {source} syncing static files to /tmp/mySite/public/ +Started building site +INFO: {date} {source} found taxonomies: map[string]string{"tag":"tags", "category":"categories"} +WARN: {date} {source} "404.html" is rendered empty +0 draft content +0 future content +0 expired content +3 pages created +0 non-page files copied +0 paginator pages created +0 tags created +0 categories created +in 9 ms + +$ ls -l public/ +total 24 +-rw-r--r-- 1 {user} {group} 0 {date} 404.html +drwxr-xr-x 3 {user} {group} 102 {date} About +drwxr-xr-x 6 {user} {group} 204 {date} article +drwxr-xr-x 2 {user} {group} 68 {date} css +-rw-r--r-- 1 {user} {group} 316 {date} index.html +-rw-r--r-- 1 {user} {group} 2221 {date} index.xml +drwxr-xr-x 2 {user} {group} 68 {date} js +-rw-r--r-- 1 {user} {group} 681 {date} sitemap.xml + +$ ls -l public/About/ +total 8 +-rw-r--r-- 1 {user} {group} 305 {date} index.html + +$ cat public/About/index.html +<!DOCTYPE html> +<html> +<head> + <title>About</title> +</head> +<body> + <h1>About</h1> + <h6>Wed, Jan 18, 2040</h6> + <p>Neque porro quisquam est qui dolorem +ipsum quia dolor sit amet consectetur +adipisci velit.</p> + + <h4><a href="http://example.org/">Home</a></h4> +</body> +</html> +``` +Oh, well. — Did you notice that your page wasn't rendered at the +top level? It was rendered to a subdirectory named `./public/About/`. +That name came from the basename of your Markdown file `./content/About.md`. +Interesting — but, we'll let that go, for now. +### Home + +One other thing — let's take a look at your home page: +```html +$ cat public/index.html +<!DOCTYPE html> +<html> +<body> + <h4><a href="http://example.org/About/">About</a></h4> + <h4><a href="http://example.org/article/Second/">Second</a></h4> + <h4><a href="http://example.org/article/First/">First</a></h4> +</body> +</html> +``` +Did you notice that the About link is listed with your articles? +That's not exactly where we want it; so, let's edit your home page template +(`layouts/index.html`): +```html +$ vi themes/zafta/layouts/index.html +<!DOCTYPE html> +<html> +<body> + <h2>Articles</h2> + {{- range first 10 .Data.Pages -}} + {{- if eq .Type "article"}} + <h4><a href="{{ .Permalink }}">{{ .Title }}</a></h4> + {{- end -}} + {{- end }} + <h2>Pages</h2> + {{- range first 10 .Data.Pages -}} + {{- if eq .Type "page" }} + <h4><a href="{{ .Permalink }}">{{ .Title }}</a></h4> + {{- end -}} + {{- end }} +</body> +</html> +:wq +``` +Let's render your web site, and verify the results: +```html +$ rm -rf public/ + +$ hugo --verbose +INFO: {date} {source} Using config file: /tmp/mySite/config.toml +INFO: {date} {source} using a UnionFS for static directory comprised of: +INFO: {date} {source} Base: /tmp/mySite/themes/zafta/static +INFO: {date} {source} Overlay: /tmp/mySite/static/ +INFO: {date} {source} syncing static files to /tmp/mySite/public/ +Started building site +INFO: {date} {source} found taxonomies: map[string]string{"tag":"tags", "category":"categories"} +WARN: {date} {source} "404.html" is rendered empty +0 draft content +0 future content +0 expired content +3 pages created +0 non-page files copied +0 paginator pages created +0 tags created +0 categories created +in 9 ms + +$ cat public/index.html +<!DOCTYPE html> +<html> +<body> + <h2>Articles</h2> + <h4><a href="http://example.org/article/Second/">Second</a></h4> + <h4><a href="http://example.org/article/First/">First</a></h4> + <h2>Pages</h2> + <h4><a href="http://example.org/About/">About</a></h4> +</body> +</html> +``` +Good! This time, your home page has two Sections: "article" and "page", and +each Section contains the correct set of headings and links. +## Template Sharing + +If you've been following along on your computer, you might've noticed that +your home page doesn't show its title in your browser, although both of your +article pages do. That's because we didn't add your home page's title to its +template (`layouts/index.html`). That would be easy to do — but instead, +let's look at a better option. + +We can put the common information into a shared template. +These reside in the `layouts/partials/` directory. +### Header & Footer + +In Hugo (as elsewhere), a Partial is a template that's intended to be used +within other templates. We're going to create a Partial template that will +contain a header, for all of your page templates to use. That Partial will +enable us to maintain the header information in a single place, thus easing +our maintenance. Let's create both the header (`layouts/partials/header.html`) +and the footer (`layouts/partials/footer.html`): +```html +$ vi themes/zafta/layouts/partials/header.html +<!DOCTYPE html> +<html> +<head> + <title>{{ .Title }}</title> +</head> +<body> +:wq + +$ vi themes/zafta/layouts/partials/footer.html + <h4><a href="{{ .Site.BaseURL }}">Home</a></h4> +</body> +</html> +:wq +``` +### Calling + +Any `partial` is called relative to its conventional location +`layouts/partials/`. So, you pass just the basename, followed by the context +(the period before the closing mustache). For example: +```bash +{{ partial "header.html" . }} +``` +#### From Home + +Let's change your home page template (`layouts/index.html`) +in order to use the new header Partial we just created: +```html +$ vi themes/zafta/layouts/index.html +{{ partial "header.html" . }} + <h2>Articles</h2> + {{- range first 10 .Data.Pages -}} + {{- if eq .Type "article"}} + <h4><a href="{{ .Permalink }}">{{ .Title }}</a></h4> + {{- end -}} + {{- end }} + <h2>Pages</h2> + {{- range first 10 .Data.Pages -}} + {{- if eq .Type "page" }} + <h4><a href="{{ .Permalink }}">{{ .Title }}</a></h4> + {{- end -}} + {{- end }} +</body> +</html> +:wq +``` +Render your web site and verify the results. Now, the title on your home page +should be "My New Hugo Site". This comes from the "title" variable +in the `./config.toml` file. +#### From Default + +Let's also edit the default templates (`layouts/_default/single.html` and +`layouts/_default/list.html`) to use your new Partials: +```html +$ vi themes/zafta/layouts/_default/single.html +{{ partial "header.html" . }} + <h1>{{ .Title }}</h1> + <h6>{{ .Date.Format "Mon, Jan 2, 2006" }}</h6> + {{ .Content }} +{{ partial "footer.html" . -}} +:wq + +$ vi themes/zafta/layouts/_default/list.html +{{ partial "header.html" . -}} + <h1>Articles</h1> + {{- range first 10 .Data.Pages }} + <h4><a href="{{ .Permalink }}">{{ .Title }}</a></h4> + {{- end }} +{{ partial "footer.html" . -}} +:wq +``` +Render your web site and verify the results. +Now, the title of your About page should reflect the value of the "title" +variable in its corresponding Markdown file (`./content/About.md`). +The same should be true for each of your article pages as well (i.e., +`./content/article/First.md` and `./content/article/Second.md`). +### DRY + +Don't Repeat Yourself (also known as DRY) is a desirable goal, +in any kind of source code development — +and Hugo's partials do a fine job to help with that. + +Part of the art of good templates is knowing when to add new ones, and when +to edit existing ones. While you're still figuring out the art of templates, +you should accept that you'll do some refactoring — Hugo makes this +easy and fast. And it's okay to delay splitting your templates into Partials. +## Section +### Date + +Articles commonly display the date they were published +(or finalized) — so, here, let's do the same. + +The front-matter of your articles contains a "date" variable +(as discussed above). Hugo sets this, when it creates each content file. +Now, sometimes an article requires many days to prepare, so its actual +publishing date might be later than the front-matter's "date". However, for +simplicity's sake, let's pretend this is the date we want to display, each time. + +In Hugo, in order to format a variable date (or time), +we must do it by formatting the Go language [reference +time](https://golang.org/pkg/time/); for example: +```bash +{{ .Date.Format "Mon, Jan 2, 2006" }} +``` +Now, your articles use the `layouts/_default/single.html` template (see above). +Because that template includes a date-formatting snippet, they show a +nice looking date. However, your About page uses the same default template. +Unfortunately, now it too shows its creation date (which makes no sense)! + +There are a couple of ways to make the date display only for articles. +We could use an "if" statement, to display the date only when the Type equals +"article." That is workable, and acceptable for web sites with only a couple +of content Types. It aligns with the principle of "code for today," too. +### Template + +Let's assume, though (for didactic purposes), that you've made your web site so +complex that you feel you must create a new template Type. In Hugo-speak, this +will be a new Section. It will contain your new, "article" Single template. + +Let's restore your default Single template (`layouts/_default/single.html`) +to its earlier state (before we forget): +```html +$ vi themes/zafta/layouts/_default/single.html +{{ partial "header.html" . }} + <h1>{{ .Title }}</h1> + {{ .Content }} +{{ partial "footer.html" . -}} +:wq +``` +Now, let's create your new template. If you remember Hugo's rules, +the template engine will prefer this version over the default. The first step +is to create (within your theme) its Section's directory: `layouts/article/`. +Then, create a Single template (`layouts/article/single.html`) within it: +```html +$ mkdir themes/zafta/layouts/article + +$ vi themes/zafta/layouts/article/single.html +{{ partial "header.html" . }} + <h1>{{ .Title }}</h1> + <h6>{{ .Date.Format "Mon, Jan 2, 2006" }}</h6> + {{ .Content }} +{{ partial "footer.html" . -}} +:wq +``` +Basically, we moved the date logic — from the default template, to the +new "article" Section, Single template: `layouts/article/single.html`. + +Let's render your web site and verify the results: +```html +$ rm -rf public/ + +$ hugo --verbose +INFO: {date} {source} Using config file: /tmp/mySite/config.toml +INFO: {date} {source} using a UnionFS for static directory comprised of: +INFO: {date} {source} Base: /tmp/mySite/themes/zafta/static +INFO: {date} {source} Overlay: /tmp/mySite/static/ +INFO: {date} {source} syncing static files to /tmp/mySite/public/ +Started building site +INFO: {date} {source} found taxonomies: map[string]string{"tag":"tags", "category":"categories"} +WARN: {date} {source} "404.html" is rendered empty +0 draft content +0 future content +0 expired content +3 pages created +0 non-page files copied +0 paginator pages created +0 tags created +0 categories created +in 10 ms + +$ cat public/article/First/index.html +<!DOCTYPE html> +<html> +<head> + <title>First</title> +</head> +<body> + + <h1>First</h1> + <h6>Wed, Jan 18, 2040</h6> + <p>In vel ligula tortor. Aliquam erat volutpat. +Pellentesque at felis eu quam tincidunt dignissim. +Nulla facilisi.</p> + +<p>Pellentesque tempus nisi et interdum convallis. +In quam ante, vulputate at massa et, rutrum +gravida dui. Phasellus tristique libero at ex.</p> + + <h4><a href="http://example.org/">Home</a></h4> +</body> +</html> + +$ cat public/About/index.html +<!DOCTYPE html> +<html> +<head> + <title>About</title> +</head> +<body> + + <h1>About</h1> + <p>Neque porro quisquam est qui dolorem +ipsum quia dolor sit amet consectetur +adipisci velit.</p> + + <h4><a href="http://example.org/">Home</a></h4> +</body> +</html> +``` +Now, as you can see, your articles show their dates, +and your About page (sensibly) doesn't. diff --git a/docs/content/tutorials/deployment-with-rsync.md b/docs/content/tutorials/deployment-with-rsync.md new file mode 100644 index 000000000..7bc516650 --- /dev/null +++ b/docs/content/tutorials/deployment-with-rsync.md @@ -0,0 +1,125 @@ +--- +authors: +- Adrien Poupin +date: 2016-11-01 +linktitle: Deployment with rsync +toc: true +menu: + main: + parent: tutorials +next: /tutorials/creating-a-new-theme +prev: /tutorials/automated-deployments +title: Easy deployments with rsync +weight: 11 + +--- + +# How to build and deploy with hugo and rsync +We assume here that you have an access to your web host with SSH. In that case, as you will see, deployment is very simple. We also assume that you have a functional static site with hugo installed. + +The spoil is, you can deploy your entire site with a command that looks like this: + +```bash +hugo && rsync -avz --delete public/ [email protected]:~/www/ +``` + +As you will see, we put it in a shell script file, which makes building and deployment as easy as executing `./deploy`. + +## Installing SSH Key + +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, enter `sudo apt-get install openssh-client`. + +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 [email protected] +``` + +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! + +## Shell script + +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 +``` + +And it's done! + diff --git a/docs/content/tutorials/github-pages-blog.md b/docs/content/tutorials/github-pages-blog.md new file mode 100644 index 000000000..013642ded --- /dev/null +++ b/docs/content/tutorials/github-pages-blog.md @@ -0,0 +1,197 @@ +--- +aliases: + - /tutorials/github_pages_blog/ +author: Spencer Lyon, Gunnar Morling +lastmod: 2017-01-11 +date: 2014-03-21 +linktitle: Hosting on GitHub +toc: true +menu: + main: + parent: tutorials +next: /tutorials/how-to-contribute-to-hugo/ +prev: /tutorials/creating-a-new-theme +title: Hosting on GitHub Pages +weight: 10 +--- + +*This tutorial was contributed by [Spencer Lyon](http://spencerlyon.com/) (Personal/Organization Pages) and [Gunnar Morling](https://github.com/gunnarmorling/).* + +## Introduction + +This tutorial describes how to deploy your Hugo based website to [GitHub pages](https://pages.github.com/). + +The following sections are based on the assumption that you are working with a "Project Pages Site". +This means that you'll have your Hugo sources and the generated HTML output within a single repository +(in contrast, with a "User/Organization Pages Site", you'd have one repo for the sources and another repo for the published HTML files; +refer to the [GitHub Pages docs](https://help.github.com/articles/user-organization-and-project-pages/) to learn more). + +## Deployment via _/docs_ folder on master branch + +[As described](https://help.github.com/articles/configuring-a-publishing-source-for-github-pages/#publishing-your-github-pages-site-from-a-docs-folder-on-your-master-branch) in the GitHub Pages docs, you can deploy from a folder called _docs_ on your master branch. +This requires to change the Hugo publish directory in the site config (e.g. _config.toml_): + + publishDir = "docs" + +After running `hugo`, push your master branch to the remote repo and choose the _docs_ folder as the website source of your repo +(in your GitHub project, go to "Settings " -> "GitHub Pages" -> "Source" -> Select "master branch /docs folder"). +If that option isn't enabled, you likely haven't pushed your _docs_ folder yet. + +This is the simplest approach but requires the usage of a non-standard publish directory +(GitHub Pages cannot be configured to use another directory than _docs_ currently). +Also the presence of generated files on the master branch may not be to everyone's taste. + +## Deployment via gh-pages branch + +Alternatively, you can deploy site through a separate branch called "gh_pages". +That approach is a bit more complex but has some advantages: + +* It keeps sources and generated HTML in two different branches +* It uses the default _public_ folder +* It keeps the histories of source branch and gh-pages branch fully separated from each other + +### Preparations + +These steps only need to be done once (replace "upstream" with the name of your remote, e.g. "origin"): +First, add the _public_ folder to _.gitignore_ so it's ignored on the master branch: + + echo "public" >> .gitignore + +Then initialize the gh-pages branch as an empty [orphan branch](https://git-scm.com/docs/git-checkout/#git-checkout---orphanltnewbranchgt): + + 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 + +### Building and Deployment + +Now check out the gh-pages branch into your _public_ folder, using git's [worktree feature](https://git-scm.com/docs/git-worktree) +(essentially, it allows you to have multiple branches of the same local repo to be checked out in different directories): + + rm -rf public + git worktree add -B gh-pages public upstream/gh-pages + +Regenerate the site using Hugo and commit the generated files on the gh-pages branch: + + hugo + cd public && git add --all && git commit -m "Publishing to gh-pages" && cd .. + +If the changes in your local gh-pages branch look alright, push them to the remote repo: + + git push upstream gh-pages + +After a short while you'll see the updated contents on your GitHub Pages site. + +### Putting it into a script + +To automate these steps, you can create a script _scripts/publish_to_ghpages.sh_ with the following contents: + +``` +#!/bin/sh + +DIR=$(dirname "$0") + +cd $DIR/.. + +if [[ $(git status -s) ]] +then + echo "The working directory is dirty. Please commit any pending changes." + exit 1; +fi + +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)" +``` + +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. + +## Deployment with Git 2.4 and earlier + +The `worktree` command was only introduced in Git 2.5. +If you are still on an earlier version and cannot update, you can simply clone your local repo into the _public_ directory, only keeping the gh-pages branch: + + git clone .git --branch gh-pages public + +Having re-generated the site, you'd push back the gh-pages branch to your primary local repo: + + cd public && git add --all && git commit -m "Publishing to gh-pages" && git push origin gh-pages + +The other steps are the same as with the worktree approach. + +## Hosting Personal/Organization Pages + +As mentioned [in this GitHub's article](https://help.github.com/articles/user-organization-and-project-pages/), besides project pages, you may also want to host a user/organization page. Here are the key differences: + +> - You must use the `username.github.io` naming scheme. +> - Content from the `master` branch will be used to build and publish your GitHub Pages site. + +It becomes much simpler in that case: we'll create two separate repos, one for Hugo's content, and a git submodule with the `public` folder's content in it. + +Step by step: + +1. Create on GitHub `<your-project>-hugo` repository (it will host Hugo's content) +2. Create on GitHub `<username>.github.io` repository (it will host the `public` folder: the static website) +3. `git clone <<your-project>-hugo-url> && cd <your-project>-hugo` +4. Make your website work locally (`hugo server -t <yourtheme>`) +5. Once you are happy with the results, <kbd>Ctrl</kbd>+<kbd>C</kbd> (kill server) and `rm -rf public` (don't worry, it can always be regenerated with `hugo -t <yourtheme>`) +6. `git submodule add -b master [email protected]:<username>/<username>.github.io.git public` +7. Almost done: add a `deploy.sh` script to help you (and make it executable: `chmod +x deploy.sh`): + +``` +#!/bin/bash + +echo -e "\033[0;32mDeploying updates to GitHub...\033[0m" + +# Build the project. +hugo # if using a theme, replace by `hugo -t <yourtheme>` + +# Go To Public folder +cd public +# Add changes to git. +git add -A + +# 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 +cd .. +``` +7. `./deploy.sh "Your optional commit message"` to send changes to `<username>.github.io` (careful, you may also want to commit changes on the `<your-project>-hugo` repo). + +That's it! Your personal page is running at [http://username.github.io/](http://username.github.io/) (after up to 10 minutes delay). + +## Using a custom domain + +If you'd like to use a custom domain for your GitHub Pages site, create a file _static/CNAME_ with the domain name as its sole contents. +This will put the CNAME file to the root of the published site as required by GitHub Pages. + +Refer to the [official documentation](https://help.github.com/articles/using-a-custom-domain-with-github-pages/) for further information. + +## Conclusion + +Hopefully this tutorial helped you to get your website off its feet and out into the open! If you have any further questions, feel free to contact the community through the [discussion forum](/community/mailing-list/). diff --git a/docs/content/tutorials/hosting-on-bitbucket.md b/docs/content/tutorials/hosting-on-bitbucket.md new file mode 100644 index 000000000..027618fa5 --- /dev/null +++ b/docs/content/tutorials/hosting-on-bitbucket.md @@ -0,0 +1,138 @@ +--- +authors: +- Jason Gowans +lastmod: 2017-02-04 +date: 2017-02-04 +linktitle: Hosting on Bitbucket +toc: true +menu: + main: + parent: tutorials +next: /tutorials/github-pages-blog +prev: /tutorials/creating-a-new-theme +title: Continuous deployment with Bitbucket & Aerobatic +weight: 10 +--- + +# Continuous deployment with Bitbucket & Aerobatic + +## Introduction + +In this tutorial, we will use [Bitbucket](https://bitbucket.org/) and [Aerobatic](https://www.aerobatic.com) to build, deploy, and host a Hugo site. Aerobatic is a static hosting service that integrates with Bitbucket and provides a free hosting tier. + +It is assumed that you know how to use git for version control and have a Bitbucket account. + +## Install Aerobatic CLI + +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](https://www.aerobatic.com/docs/cli/) docs. + +```bash +npm install aerobatic-cli -g +aero register +``` + +## Create and Deploy Site + +```bash +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. + +## Push Hugo site to Bitbucket + +We will now create a git repository and then push our code to Bitbucket. In Bitbucket, create a repository. + +![][1] + +[1]: /img/tutorials/hosting-on-bitbucket/bitbucket-create-repo.png + + +```bash +# 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 [email protected]:YourUsername/my-new-hugo-site.git +git push -u origin master +``` + +## Continuous Deployment With Bitbucket Pipelines +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. + +### Step 1: Configure Bitbucket Pipelines + +In your Hugo website's Bitbucket repo; + +1. Click the Pipelines link in the left nav menu of your Bitbucket repository. +2. Click the Enable Pipelines button. +3. On the next screen, leave the default template and click Next. +4. In the editor, paste in the yaml contents below and click Commit. + +```bash +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 +``` + +### Step 2: Create `AEROBATIC_API_KEY` environment variable. + +This step only needs to be done once per account. From the command line; + +```bash +aero apikey +``` + +1. Navigate to the Bitbucket account settings for the account that the website repo belongs to. +2. Scroll down to the bottom of the left nav and click the Environment variables link in the PIPELINES section. +3. Create a new environment variable called AEROBATIC_API_KEY with the value you got by running the `aero apikey` command. Be sure to click the Secured checkbox. + +## Step 3: Edit and Commit Code + +```bash +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. + +![][2] + +[2]: /img/tutorials/hosting-on-bitbucket/bitbucket-blog-post.png + + +## Suggested next steps + +The code for this example can be found in this Bitbucket [repository](https://bitbucket.org/dundonian/hugo-docs-test). Aerobatic also provides a number of additional [plugins](https://www.aerobatic.com/docs) such as auth and redirects that you can use for your Hugo site. diff --git a/docs/content/tutorials/hosting-on-gitlab.md b/docs/content/tutorials/hosting-on-gitlab.md new file mode 100644 index 000000000..0c213d1ee --- /dev/null +++ b/docs/content/tutorials/hosting-on-gitlab.md @@ -0,0 +1,68 @@ +--- +author: Riku-Pekka Silvola +lastmod: 2016-06-23 +date: 2016-06-23 +linktitle: Hosting on GitLab +toc: true +menu: + main: + parent: tutorials +next: /tutorials/how-to-contribute-to-hugo/ +prev: /tutorials/github-pages-blog +title: Hosting on GitLab Pages +weight: 10 +--- +# Continuous deployment with GitLab + +## Introduction + +In this tutorial, we will use [GitLab](https://gitlab.com/) to build, deploy, and host a [Hugo](https://gohugo.io/) site. With Hugo and GitLab, this is incredibly easy. + +It is assumed that you know how to use git for version control and have a GitLab account, and that you have gone through the [quickstart guide]({{< relref "overview/quickstart.md" >}}) and already have a Hugo site on your local machine. + + +## Create .gitlab-ci.yml + +```bash +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. + +```yml +image: publysher/hugo + +pages: + script: + - hugo + artifacts: + paths: + - public + only: + - master +``` + +## Push Hugo site to GitLab +Next up, create a new repository on GitLab. It is *not* necessary to set 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. + +```bash +# 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 +``` + +## Wait for your page to be built +That's it! You can now follow the CI agent building your page at https://gitlab.com/YourUsername/your-hugo-site/pipelines. +After the build has passed, your new website is available at https://YourUsername.gitlab.io/your-hugo-site/ + +## Suggested next steps + +GitLab supports using custom CNAME's and TLS certificates, but this is out of the scope of this tutorial. For more details on GitLab Pages, see [https://about.gitlab.com/2016/04/07/gitlab-pages-setup/](https://about.gitlab.com/2016/04/07/gitlab-pages-setup/) diff --git a/docs/content/tutorials/how-to-contribute-to-hugo.md b/docs/content/tutorials/how-to-contribute-to-hugo.md new file mode 100644 index 000000000..5f3795f20 --- /dev/null +++ b/docs/content/tutorials/how-to-contribute-to-hugo.md @@ -0,0 +1,352 @@ +--- +date: 2016-04-03T13:21:56+02:00 +linktitle: How to contribute +menu: + main: + parent: tutorials +next: /tutorials/installing-on-mac/ +prev: /tutorials/github-pages-blog/ +title: How to contribute to Hugo +weight: 10 +--- + +## Introduction + +Hugo is an open source project and lives by the work of its [contributors](https://github.com/gohugoio/hugo/graphs/contributors). Help to make Hugo even more awesome. There are plenty of [open issues](https://github.com/gohugoio/hugo/issues) on GitHub and we need your help. + +This tutorial is intended for people who are new to Git, GitHub or open source projects in general. It should help to overcome most of the barriers that newcomers encounter. It describes step by step what you need to do. + +For any kind of questions please take a look at our [forum](https://discourse.gohugo.io/). + +## Install Go + +The installation of Go should take only a few minutes. [Download](https://golang.org/dl/) the latest stable version of Go and follow the official [installation guide](https://golang.org/doc/install). + +Let's confirm the correct installation of Go. Open a terminal (or command line under Windows). Execute `go version` and you should see the version number of your Go installation. Next, make sure that you setup the `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. + +### GVM as alternative + +More experienced users can use the [Go Version Manager](https://github.com/moovweb/gvm), or GVM for short. It allows you to switch between different Go versions *on the same machine*. Probably you don't need this feature. But you can easily upgrade to a new released Go version with a few commands. + +This is handy if you follow the developement 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 have to upgrade if you want to keep up. + + +## Create an account on GitHub + +If you're going to contribute code, you'll need to have an account on GitHub. Go to [www.github.com/join](https://github.com/join) and set up a personal account. + + +## Install Git on your system + +You will need to install Git. This tutorial assumes basic knowledge about Git. Refer to this excellent [Git book](https://git-scm.com/) if you are not sure where to begin. The used terminology will be explained with annotations. + +Git is a [version control system](https://en.wikipedia.org/wiki/Version_control) 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](https://git-scm.com/downloads) the lastest version of Git and follow this [installation guide](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git). + +Finally, check again with `git version` if Git was installed successfully. + +### Git Graphical Front Ends + +There are several [GUI clients](https://git-scm.com/downloads/guis) 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. + +### Install Hub on your system (optional) + +Hub is a great tool for working with GitHub. The main site for it is [www.hub.github.com](https://hub.github.com/). Feel free to install this little Git wrapper. + +On a Mac, install Hub using brew: + +```sh +brew install hub +``` + +Create an alias (in Bash) so that typing git actually runs Hub: + +```sh +echo "alias git='hub'" >> ~/.bash_profile +``` + +Confirm the installation: + +```sh +git version 2.6.3 +hub version 2.2.2 +``` + + +## Set up your working copy + +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. + +### Vendored Dependencies + +Hugo uses [govendor](https://github.com/kardianos/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 since `go get` is not vendor-aware. +You **must use govendor** to fetch and manage Hugo's dependencies. + +```sh +go get -v -u github.com/kardianos/govendor +``` + +### Fetch the Sources from GitHub + +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](https://help.github.com/articles/cloning-a-repository/) 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](https://github.com/gohugoio/hugo). 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 with govendor: + +```sh +govendor get -v github.com/gohugoio/hugo +``` + +### Fork the repository + +If you're not familiar with this term, GitHub's [help pages](https://help.github.com/articles/fork-a-repo/) 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. + +#### Fork by hand + +Open the [Hugo repository](https://github.com/gohugoio/hugo) on GitHub and click on the "Fork" button in the top right. + +![Fork button](/img/tutorials/how-to-contribute-to-hugo/forking-a-repository.png) + +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](https://help.github.com/articles/which-remote-url-should-i-use/). + +![Copy remote url](/img/tutorials/how-to-contribute-to-hugo/copy-remote-url.png) + +Switch back to the terminal and move into the directory of the cloned master repository from the last step. + +```sh +cd $GOPATH/src/github.com/gohugoio/hugo +``` + +Now Git needs to know that our fork exists by adding the copied remote url: + +```sh +git remote add <YOUR-GITHUB-USERNAME> <COPIED REMOTE-URL> +``` + +#### Fork with Hub + +Alternatively, you can use the Git wrapper Hub. Hub makes forking a repository easy: + +```sh +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. + +#### Trust, but verify + +Let's check if everything went right by listing all known remotes: + +```sh +git remote -v +``` + +The output should look similar: + +```sh +digitalcraftsman [email protected]:digitalcraftsman/hugo.git (fetch) +digitalcraftsman [email protected]:digitalcraftsman/hugo.git (push) +origin https://github.com/gohugoio/hugo (fetch) +origin https://github.com/gohugoio/hugo (push) +``` + + +## The contribution workflow + +### Create a new branch + +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: + +```sh +git checkout master +git pull +``` + +Now we can create a new branch for your additions: + +```sh +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. + +### Contributing to the documentation + +Perhaps you want to start contributing to the docs. Then you can ignore most of the following steps. You can find the documentation within the cloned repository in the subfolder `docs`. Change the directory with `cd docs`. Install the [latest release]({{< relref "overview/installing.md" >}}). Or read on and build Hugo from source. + +You can start Hugo's built-in server via `hugo server`. Browse the documentation by entering [http://localhost:1313](http://localhost:1313) in the address bar of your browser. The server automatically updates the page if you change its content. + +### Building Hugo + +While making changes in the codebase it's a good idea to build the binary to test them: + +```sh +make hugo +``` + +### Testing + +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`. + +```sh +make check +``` + +### Formatting + +The Go code styleguide maybe is opinionated 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 additions: + +```sh +govendor fmt +local +``` + +Once you made your additions commit your changes. Make sure that you follow our [code contribution guidelines](https://github.com/gohugoio/hugo/blob/master/CONTRIBUTING.md): + +```sh +# 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. + +### Modify commits + +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. + +#### Modifying the last commit + +Let's say you want to modify the last commit message. Run the following command and replace the current message: + +```sh +git commit --amend -m"YOUR NEW COMMIT MESSAGE" +``` + +Take a look at the commit log to see the change: + +```sh +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: + +```sh +git add --all +git commit --amend +``` + +#### Modifying multiple commits + +This is a bit more advanced. Git allows you to [rebase](https://git-scm.com/docs/git-rebase) commits interactively. In other words: it allows you to rewrite the commit history. **Take care of your actions. They can cause unintended changes. Skip this section if you're not sure!** + +```sh +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: + +```sh +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: + + +```sh +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: + +```sh +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 (a.k.a. squashed). Save the file (<kbd>CTRL</kbd>+<kbd>S</kbd>) 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: + +```sh +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`. + +### Push commits + +To push our commits to the fork on GitHub we need to specify 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. + +```sh +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`. + + +## Open a pull request + +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](https://github.com/gohugoio/hugo/) on GitHub in your browser. + +You should find a green button labeled with "New pull request". But GitHub is clever and probably suggests you a pull request like in the beige box below: + +<img src="/img/tutorials/how-to-contribute-to-hugo/open-pull-request.png" alt="Open a pull request"> + +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". + +### Accept the contributor license agreement + +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. + +<img src="/img/tutorials/how-to-contribute-to-hugo/accept-cla.png" alt="Accept the CLA"> + + +### Automatic builds + +We use the [Travis CI loop](https://travis-ci.org/gohugoio/hugo) (Linux and OS X) and [AppVeyor](https://ci.appveyor.com/project/gohugoio/hugo/branch/master) (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. + +<img src="/img/tutorials/how-to-contribute-to-hugo/ci-errors.png" alt="Automic builds and their status"> + +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. + +## Where to start? + +Thank you for reading this tutorial. Hopefully, we see you again on GitHub. There are plenty of [open issues](https://github.com/gohugoio/hugo/issues) on GitHub. 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. diff --git a/docs/content/tutorials/installing-on-mac.md b/docs/content/tutorials/installing-on-mac.md new file mode 100644 index 000000000..12bf01e2b --- /dev/null +++ b/docs/content/tutorials/installing-on-mac.md @@ -0,0 +1,240 @@ +--- +author: "Michael Henderson" +lastmod: 2016-08-10 +date: 2015-02-22 +linktitle: Installing on Mac +toc: true +menu: + main: + parent: tutorials +next: /tutorials/installing-on-windows +prev: /tutorials/how-to-contribute-to-hugo/ +title: Installing on a Mac +weight: 10 +--- + +# Installing Hugo on a Mac + +This tutorial aims to be a complete guide to installing Hugo on your Mac computer. + +## Assumptions + +1. You know how to open a terminal window. +2. You're running a modern 64-bit Mac. +3. You will use `~/Sites` as the starting point for your site. + +## Pick Your Method + +There are three ways to install Hugo on your Mac computer: the `brew` utility, from the distribution, or from source. +There's no "best" way to do this. You should use the method that works best for your use case. + +There are pros and cons for each. + +1. `Brew` is the simplest and least 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 + (unless you install it with the `--HEAD` option). The release to + `brew` may lag a few days behind because it has to be coordinated + with another team. Still, I'd recommend `brew` if you want to work + from a stable, widely used source. It works well and is really easy + to update. + +2. Downloading the tarball and installing from it is also easy. You have to have a few more command line skills. Updates are easy, too. 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 binary is a good choice. + +3. Compiling from source is the most work. The advantage 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. It's not a lot, but it's more than with the other two options. + +Since this is a "beginner" how-to, I'm going to cover the first two +options in detail and go over the third more quickly. + +## Brew + +### Step 1: Install `brew` if you haven't already + +Go to the `brew` website, http://brew.sh/, and follow the directions there. The most important step is: + +``` +ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" +``` + +When I did this, I had some problems with directory permissions. Searches on Google pointed me to pages that walked me through updating permissions on the `/usr/local` directory. Seemed scary, but it's worked well since. + +### Step 2: Run the `brew` command to install `hugo` + +```bash +$ brew install hugo +==> Downloading https://homebrew.bintray.com/bottles/hugo-0.21.sierra.bottle.tar.gz +######################################################################## 100,0% +==> Pouring hugo-0.21.sierra.bottle.tar.gz +==> Using the sandbox +==> Caveats +Bash completion has been installed to: + /usr/local/etc/bash_completion.d +==> Summary +🍺 /usr/local/Cellar/hugo/0.21: 32 files, 17.4MB +``` + +(Note: Replace `brew install hugo` with `brew install hugo --HEAD` +if you want the absolute latest version in development, +but beware — there might be bugs!) + +`Brew` should have updated your path to include Hugo. Confirm by opening a new terminal window and running a few commands: + +```bash +$ # 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 +``` + +### Step 3: You're Done + +You've installed Hugo. Now you need to set up your site. Read the +[Quickstart guide](/overview/quickstart/), explore the rest of the +documentation, and if you still have questions +[just ask!](https://discourse.gohugo.io/ "Discussion forum") + +## From Tarball + +### Step 1: Decide on the location + +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: + +1. 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. + +2. 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. + +3. 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 just make a copy of the entire site, update the Hugo executable, and have it. + +All three locations will work for you. I'm going to document the second option, mostly because I'm comfortable with it. + +### Step 2: Download the Tarball + +1. Open <https://github.com/gohugoio/hugo/releases> in your browser. + +2. Find the current release by scrolling down and looking for the green tag that reads "Latest Release." + +3. 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. + +4. By default, the tarball will be saved to your `~/Downloads` directory. If you chose to use a different location, you'll need to change that in the following steps. + +### Step 3: Confirm your download + +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. The other file is the executable. + +### Step 4: Install into your 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 then open a new terminal to pick up the changes to your profile. Verify by running the `which hugo` command again. + +### Step 5: You're Done + +You've installed Hugo. Now you need to set up your site. Read the +[Quickstart guide](/overview/quickstart/), explore the rest of the +documentation, and if you still have questions +[just ask!](https://discourse.gohugo.io/ "Discussion forum") + +## Building from Source + +If you want to compile Hugo yourself, you'll need +[Go](http://golang.org), which is also available from Homebrew: `brew +install go`. + +### Step 1: Get the Source + +If you want to compile a specific version, 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 +``` + +### Step 2: Compiling + +Make the directory containing the source your working directory, then +fetch Hugo's dependencies: + +``` +mkdir -p src/github.com/spf13 +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, so if +Hugo fails to build it may be because the author of a dependency +introduced a breaking change. + +Then compile: + +``` +go build -o hugo main.go +``` + +Then place the `hugo` executable somewhere in your `$PATH`. + +### Step 3: You're Done + +You probably know where to go from here. diff --git a/docs/content/tutorials/installing-on-windows.md b/docs/content/tutorials/installing-on-windows.md new file mode 100644 index 000000000..d249571f6 --- /dev/null +++ b/docs/content/tutorials/installing-on-windows.md @@ -0,0 +1,123 @@ +--- +author: "Michael Henderson" +lastmod: 2016-07-18 +date: 2015-03-30 +linktitle: Installing on Windows +toc: true +menu: + main: + parent: tutorials +next: /tutorials/mathjax +prev: /tutorials/installing-on-mac +title: Installing on Windows +weight: 10 +--- + +# Installing Hugo on Windows + +This tutorial aims to be a complete guide to installing Hugo on your Windows computer. + +## Assumptions + +1. We'll call your website `example.com` for the purpose of this tutorial. +2. You will use `C:\Hugo\Sites` as the starting point for your site. +3. You will use `C:\Hugo\bin` to store executable files. + +## Setup Your Directories + +You'll need a place to store the Hugo executable, your content (the files that you build), and the generated files (the HTML that Hugo builds for you). + +1. Open Windows Explorer. +2. Create a new folder: `C:\Hugo` (assuming you want Hugo on your C drive – it can go anywhere.) +3. Create a subfolder in the Hugo folder: `C:\Hugo\bin`. +4. Create another subfolder in Hugo: `C:\Hugo\Sites`. + +## Technical users + +1. Download the latest zipped Hugo executable from the [Hugo Releases](https://github.com/gohugoio/hugo/releases) page. +2. Extract all contents to your `..\Hugo\bin` folder. +3. The hugo executable will be named as `hugo_hugo-version_platform_arch.exe`. Rename that executable to `hugo.exe` for ease of use. +4. In PowerShell or your preferred CLI, add the `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. + +## Less technical users + +1. Go the [Hugo Releases](https://github.com/gohugoio/hugo/releases) page. +2. The latest release is announced on top. Scroll to the bottom of the release announcement to see the downloads. They're all ZIP files. +3. Find the Windows files near the bottom (they're in alphabetical order, so Windows is last) – download either the 32-bit or 64-bit file depending on whether you have 32-bit or 64-bit Windows. (If you don't know, [see here](https://esupport.trendmicro.com/en-us/home/pages/technical-support/1038680.aspx).) +4. Move the ZIP file into your `C:\Hugo\bin` folder. +5. Double-click on the ZIP file and extract its contents. Be sure to extract the contents into the same `C:\Hugo\bin` folder – Windows will do this by default unless you tell it to extract somewhere else. +6. You should now have three new files: hugo executable (example: 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. +7. Now add Hugo to your Windows PATH settings: + + ### For Windows 10 users: + + - Right click on the **Start** button. + - Click on **System**. + - Click on **Advanced System Settings** on the left. + - Click on the **Environment Variables...** button on the bottom. + - In the User variables section, find the row that starts with PATH (PATH will be all caps). + - Double-click on **PATH**. + - Click the **New...** button. + - Type in the folder where `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, not the binary.* Press <kbd>Enter</kbd> when you're done typing. + - Click OK at every window to exit. + + > <small>Note that the path editor in Windows 10 was added in the large [November 2015 Update](https://blogs.windows.com/windowsexperience/2015/11/12/first-major-update-for-windows-10-available-today/). 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 <i class="fa fa-windows"></i> Start button → Settings → System → About. See [here](http://www.howtogeek.com/236195/how-to-find-out-which-build-and-version-of-windows-10-you-have/) for more.)</small> + + ### For Windows 7 and 8.x users: + + 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](http://eveditor.com/) or [Path Editor](https://patheditor2.codeplex.com/). + +## Verify the executable + +Run a few commands to verify that the executable is ready to run, and then build a sample site to get started. + +1. Open a command prompt window. + +2. At the prompt, type `hugo help` and press the <kbd>Enter</kbd> key. You should see output that starts with: + + {{< nohighlight >}}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/. +{{< /nohighlight >}} + + 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, post a note on the Hugo discussion list (in the `Support` topic) with your command and the output. + +3. At the prompt, change your directory to the `Sites` directory. + + {{< nohighlight >}}C:\Program Files> cd C:\Hugo\Sites +C:\Hugo\Sites> +{{< /nohighlight >}} + +4. Run the command to generate a new site. I'm using `example.com` as the name of the site. + + {{< nohighlight >}}C:\Hugo\Sites> hugo new site example.com +{{< /nohighlight >}} + +5. 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: + + {{< nohighlight >}}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 +{{< /nohighlight >}} + +You now have Hugo installed and a site to work with. You need to add a layout (or theme), then create some content. Go to http://gohugo.io/overview/quickstart/ for steps on doing that. + +## Troubleshooting + +@dhersam has created a nice video on common issues: + +{{< youtube c8fJIRNChmU >}} diff --git a/docs/content/tutorials/mathjax.md b/docs/content/tutorials/mathjax.md new file mode 100644 index 000000000..e8d896354 --- /dev/null +++ b/docs/content/tutorials/mathjax.md @@ -0,0 +1,84 @@ +--- +author: Spencer Lyon +lastmod: 2015-05-22 +date: 2014-03-20 +menu: + main: + parent: tutorials +next: /tutorials/migrate-from-jekyll +prev: /tutorials/installing-on-windows +title: MathJax Support +toc: true +weight: 10 +--- + +## What is MathJax? + +[MathJax](http://www.mathjax.org/) 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. + +## Enabling MathJax + +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](http://docs.mathjax.org/en/latest/configuration.html) section of the MathJax documentation for additional methods of including MathJax), but the easiest way is to use [the officially recommended secure CDN](https://cdnjs.com/) by including the following HTML snippet in the source of a page: + + <script type="text/javascript" + src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"> + </script> + +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. + +### Options and Features + +MathJax is a stable open-source library with many features. I encourage the interested reader to view the [MathJax Documentation](http://docs.mathjax.org/en/latest/index.html), specifically the sections on [Basic Usage](http://docs.mathjax.org/en/latest/index.html#basic-usage) and [MathJax Configuration Options](http://docs.mathjax.org/en/latest/index.html#mathjax-configuration-options). + +## Issues with Markdown + +After enabling MathJax, any math entered in-between proper markers (see 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. + +### Solution + +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](http://doswa.com/2011/07/20/mathjax-in-markdown.html)---all credit goes to the original author). + + <script type="text/x-mathjax-config"> + MathJax.Hub.Config({ + tex2jax: { + inlineMath: [['$','$'], ['\\(','\\)']], + displayMath: [['$$','$$'], ['\[','\]']], + processEscapes: true, + processEnvironments: true, + skipTags: ['script', 'noscript', 'style', 'textarea', 'pre'], + TeX: { equationNumbers: { autoNumber: "AMS" }, + extensions: ["AMSmath.js", "AMSsymbols.js"] } + } + }); + </script> + + <script type="text/x-mathjax-config"> + MathJax.Hub.Queue(function() { + // Fix <code> tags after MathJax finishes running. This is a + // hack to overcome a shortcoming of Markdown. Discussion at + // https://github.com/mojombo/jekyll/issues/199 + var all = MathJax.Hub.getAllJax(), i; + for(i = 0; i < all.length; i += 1) { + all[i].SourceElement().parentNode.className += ' has-jax'; + } + }); + </script> + +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.has-jax {font: inherit; + font-size: 100%; + background: inherit; + border: inherit; + color: #515151;} + +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. + +### Usage + +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 `` `$ TeX Code $` `` or `` `\( TeX Code \)` ``. To include display style mathematics, just put LaTeX code in between `<div>$$TeX Code$$</div>`. All the math will be properly typeset and displayed within your Hugo generated web page! diff --git a/docs/content/tutorials/migrate-from-jekyll.md b/docs/content/tutorials/migrate-from-jekyll.md new file mode 100644 index 000000000..0fd5d4af7 --- /dev/null +++ b/docs/content/tutorials/migrate-from-jekyll.md @@ -0,0 +1,162 @@ +--- +lastmod: 2015-12-24 +date: 2014-03-10 +linktitle: Migrating from Jekyll +toc: true +menu: + main: + parent: tutorials +prev: /tutorials/mathjax +next: /tutorials/create-a-multilingual-site +title: Migrate to Hugo from Jekyll +weight: 10 +--- + +**Note:** Hugo 0.15 comes with a `hugo import jekyll` command, see [import from Jekyll](/commands/hugo_import_jekyll/). +## Move static content to `static` +Jekyll has a rule that any directory not starting with `_` will be copied as-is to the `_site` output. Hugo keeps all static content under `static`. You should therefore move it all there. +With Jekyll, something that looked like + + ▾ <root>/ + ▾ images/ + logo.png + +should become + + ▾ <root>/ + ▾ static/ + ▾ images/ + logo.png + +Additionally, you'll want any files that should reside at the root (such as `CNAME`) to be moved to `static`. + +## Create your Hugo configuration file +Hugo can read your configuration as JSON, YAML or TOML. Hugo supports parameters custom configuration too. Refer to the [Hugo configuration documentation](/overview/configuration/) for details. + +## Set your configuration publish folder to `_site` +The default is for Jekyll to publish to `_site` and for Hugo to publish to `public`. If, like me, you have [`_site` mapped to a git submodule on the `gh-pages` branch](http://blog.blindgaenger.net/generate_github_pages_in_a_submodule.html), you'll want to do one of two alternatives: + +1. Change your submodule to point to map `gh-pages` to public instead of `_site` (recommended). + + git submodule deinit _site + git rm _site + git submodule add -b gh-pages [email protected]:your-username/your-repo.git public + +2. Or, change the Hugo configuration to use `_site` instead of `public`. + + { + .. + "publishDir": "_site", + .. + } + +## Convert Jekyll templates to Hugo templates +That's the bulk of the work right here. The documentation is your friend. You should refer to [Jekyll's template documentation](http://jekyllrb.com/docs/templates/) if you need to refresh your memory on how you built your blog and [Hugo's template](/layout/templates/) to learn Hugo's way. + +As a single reference data point, converting my templates for [heyitsalex.net](http://heyitsalex.net/) took me no more than a few hours. + +## Convert Jekyll plugins to Hugo shortcodes +Jekyll has [plugins](http://jekyllrb.com/docs/plugins/); Hugo has [shortcodes](/doc/shortcodes/). It's fairly trivial to do a port. + +### Implementation +As an example, I was using a custom [`image_tag`](https://github.com/alexandre-normand/alexandre-normand/blob/74bb12036a71334fdb7dba84e073382fc06908ec/_plugins/image_tag.rb) plugin to generate figures with caption when running Jekyll. As I read about shortcodes, I found Hugo had a nice built-in shortcode that does exactly the same thing. + +Jekyll's plugin: + +```ruby +module Jekyll + class ImageTag < Liquid::Tag + @url = nil + @caption = nil + @class = nil + @link = nil + // Patterns + IMAGE_URL_WITH_CLASS_AND_CAPTION = + IMAGE_URL_WITH_CLASS_AND_CAPTION_AND_LINK = /(\w+)(\s+)((https?:\/\/|\/)(\S+))(\s+)"(.*?)"(\s+)->((https?:\/\/|\/)(\S+))(\s*)/i + IMAGE_URL_WITH_CAPTION = /((https?:\/\/|\/)(\S+))(\s+)"(.*?)"/i + IMAGE_URL_WITH_CLASS = /(\w+)(\s+)((https?:\/\/|\/)(\S+))/i + IMAGE_URL = /((https?:\/\/|\/)(\S+))/i + def initialize(tag_name, markup, tokens) + super + if markup =~ IMAGE_URL_WITH_CLASS_AND_CAPTION_AND_LINK + @class = $1 + @url = $3 + @caption = $7 + @link = $9 + elsif markup =~ IMAGE_URL_WITH_CLASS_AND_CAPTION + @class = $1 + @url = $3 + @caption = $7 + elsif markup =~ IMAGE_URL_WITH_CAPTION + @url = $1 + @caption = $5 + elsif markup =~ IMAGE_URL_WITH_CLASS + @class = $1 + @url = $3 + elsif markup =~ IMAGE_URL + @url = $1 + end + end + def render(context) + if @class + source = "<figure class='#{@class}'>" + else + source = "<figure>" + end + if @link + source += "<a href=\"#{@link}\">" + end + source += "<img src=\"#{@url}\">" + if @link + source += "</a>" + end + source += "<figcaption>#{@caption}</figcaption>" if @caption + source += "</figure>" + source + end + end +end +Liquid::Template.register_tag('image', Jekyll::ImageTag) +``` + +is written as this Hugo shortcode: + + <!-- image --> + <figure {{ with .Get "class" }}class="{{.}}"{{ end }}> + {{ with .Get "link"}}<a href="{{.}}">{{ end }} + <img src="{{ .Get "src" }}" {{ if or (.Get "alt") (.Get "caption") }}alt="{{ with .Get "alt"}}{{.}}{{else}}{{ .Get "caption" }}{{ end }}"{{ end }} /> + {{ if .Get "link"}}</a>{{ end }} + {{ if or (or (.Get "title") (.Get "caption")) (.Get "attr")}} + <figcaption>{{ if isset .Params "title" }} + {{ .Get "title" }}{{ end }} + {{ if or (.Get "caption") (.Get "attr")}}<p> + {{ .Get "caption" }} + {{ with .Get "attrlink"}}<a href="{{.}}"> {{ end }} + {{ .Get "attr" }} + {{ if .Get "attrlink"}}</a> {{ end }} + </p> {{ end }} + </figcaption> + {{ end }} + </figure> + <!-- image --> + +### Usage +I simply changed: + + {% image full http://farm5.staticflickr.com/4136/4829260124_57712e570a_o_d.jpg "One of my favorite touristy-type photos. I secretly waited for the good light while we were "having fun" and took this. Only regret: a stupid pole in the top-left corner of the frame I had to clumsily get rid of at post-processing." ->http://www.flickr.com/photos/alexnormand/4829260124/in/set-72157624547713078/ %} + +to this (this example uses a slightly extended version named `fig`, different than the built-in `figure`): + + {{%/* fig class="full" src="http://farm5.staticflickr.com/4136/4829260124_57712e570a_o_d.jpg" title="One of my favorite touristy-type photos. I secretly waited for the good light while we were having fun and took this. Only regret: a stupid pole in the top-left corner of the frame I had to clumsily get rid of at post-processing." link="http://www.flickr.com/photos/alexnormand/4829260124/in/set-72157624547713078/" */%}} + +As a bonus, the shortcode named parameters are, arguably, more readable. + +## Finishing touches +### Fix content +Depending on the amount of customization that was done with each post with Jekyll, this step will require more or less effort. There are no hard and fast rules here except that `hugo server` is your friend. Test your changes and fix errors as needed. + +### Clean up +You'll want to remove the Jekyll configuration at this point. If you have anything else that isn't used, delete it. + +## A practical example in a diff +[Hey, it's Alex](http://heyitsalex.net/) was migrated in less than a _father-with-kids day_ from Jekyll to Hugo. You can see all the changes (and screw-ups) by looking at this [diff](https://github.com/alexandre-normand/alexandre-normand/compare/869d69435bd2665c3fbf5b5c78d4c22759d7613a...b7f6605b1265e83b4b81495423294208cc74d610). |