Tutorial: Make a Hugo blog from scratch

Copied from the tutorial intro:

In my opinion, Hugo’s current quick start is ample. It does just what the name says, gets you started you quickly .

Still, there have many requests on the forums for a tutorial that dives deeper than the quick start, and gets into some templating basics. The thing you’re reading is my go at that. Starting from scratch, we’ll build a Hugo blog.

For the folks out there thinking, “just show me the money already”, here’s the finished product source code and demo.

I hope you guys enjoy :heart: Make a Hugo Blog From Scratch | zwbetz


Thanks. Your other blog posts about Hugo are cool too. Bookmarked :+1:

Your article should be included in the docs. It was exactly what I was looking for since I was struggling just to display navigation links on the page. Thank you for writing this guide. It was structured like the Jekyll quickstart guide and I really liked it for that reason.

Edit: I would be more happy, if you actually explained why partial css is better than linking to an external css file. And also why PublishedDate is the best of the both worlds. Or maybe they are explained in the docs and I just exposed my ignorance :sweat_smile:

@martignoni :slight_smile:

@MrSimsek Glad to hear it was helpful. To address your questions:

Placing the CSS in a partial allows the use of templating features. In particular, accessing params from the config file. This allows you (or others users, if it’s a theme) to configure CSS settings from their config file.

There are other ways to accomplish this, such as creating a resource from template, I just prefer this way.

Per the configure dates docs, the default configuration for publish date is:

publishDate = ["publishDate", "date"]

@zwbetz, can’t thank you enough for this! That’s a lot of well organized work friend.

@theadle am glad you liked it :+1: it’s something I’ve been meaning to write for a few weeks now

Oh I see. Thank you again for the article.

Thank you so much for this. Amazing contribution!

1 Like

I’ve been meaning to write for a few years now, hopefully this should get me liftoff.

1 Like

@zwbetz thanks for writing this tutorial. Stuff like this is very helpful for beginners.

I don’t get the part when creating a tag (term) page.

<h1>{{ .Title }}</h1>

{{ $type := .Type }}
{{ range $key, $value := .Data.Terms.ByCount }}
  {{ $name := .Name }}
  {{ $count := .Count }}
  {{ with $.Site.GetPage (printf "/%s/%s" $type $name) }}
    <a class="btn btn-outline-dark font-125" href="{{ .Permalink }}">
      <span class="badge badge-dark">{{ $count }}</span> {{ $name }}
  {{ end }}
{{ end }}

{{ end }}

What does this part mean?: {{ range $key, $value := .Data.Terms.ByCount }}
I searched in docs and found something similar but its not really explained. (examples 2–4)

Example 4: Declaring variable names for a map element’s key and value

For a map, the first declared variable will map to each map element’s key.

{{ range $elem_key, $elem_val := $map }}
{{ $elem_key }} – {{ $elem_val }}
{{ end }}

Would be grateful for help here.

1 Like

This is a convenient way to lists all terms/tags on http://localhost:1313/tags/. You need to add something like

  - A tag
  - another tag

to the front matter part of some of your blog files for the code to work.

If the code is difficult to understand you can use this one at first and then work your way up to @zwbetz’s.

{{ define "main" }}
  <ul class="terms">
    {{ range .Data.Terms.ByCount }}
        <a href="{{ .Page.Permalink }}">{{ .Page.Title }}</a> ({{ .Count }})
    {{ end }}
{{ end }}
1 Like

Thanks @pawsys, and good catch. In that example, $key, $value are actually unused (I’ve since updated the source code and blog post). So as @Grob mentioned, it can be rewritten as {{ range .Data.Terms.ByCount }} to achieve the same result.

Now, to see $key, $value in action, take this example. Let’s say you had front matter like:

  first_name: John
  last_name: Smith

And template code like:

{{ range $key, $value := .Params.person }}
  {{ $key }} is {{ $value }}
{{ end }}

Your output would be:

first_name is John
last_name is Smith

Thanks so much. Very helpful!

Just to make it clear that I understand well: So $key and value aren't actually custom variables names, but predefined commands that will grab key and value from key-value pair? If yes, are there more predefined commands like this starting with "" sign?

They’re not predefined commands, but regular variable names. One could have said $k, $v or $foo, $bar.

so how come the algorithm knows that $key is John and $value is Smith. Does it takes first two and assigns them in order? What would happen if the front matter had three entries?

Not quite. In that example, for the first entry, $key is first_name and $value is John. Then this pattern repeats for each map entry.

I realize I asked it incorrectly. Given that one could use any variable names the code could be formatted this way:

{{ range $k, $v := .Params.person }}

{{ $k }} is {{ $v }}

{{ end }}

The output wouldn’t change. Would it?.

Do I get it right: As long as you define two variables here {{ range $k, $v := .Params.person }} these variables will always refer to key and value of a key-value pair of a map entry. (thanks so much for helping me w this)

1 Like

Correct. Don’t take my word for it, though. Test it out for yourself to confirm your understanding.

thanks again!