Nested list of sections and content - Hugo - hugo

I have a series of nested sections that contain recipes, grouped by type of dish, e.g.:
content
└─ recipes
  ├─ _index.md
  ├─ bread
  │  ├─ _index.md
  │  ├─ beer_rolls.md
  │  ├─ ciabatta.md
  │  └─ potato_bread.md
├─ dessert
  │  ├─ _index.md
│  ├─ chocolate_brownies.md
│  ├─ elderberry_pie.md
│  └─ victoria_sponge_cake.md
└─ mains
├─ _index.md
├─ bean_chilli.md
├─ braised_leeks.md
└─ yorkshire_pudding.md
I want to write a list.html for content/recipes/_index.md, to produce a nested list that reflects the directory structure in recipes/, such that the first level of the list links to the subsection e.g. bread or dessert, and the second level of the list links to the individual recipes, e.g. bread/beer_rolls.md or mains_bean_chilli.md.
What does the list.html contain? Do I need to have multiple list.html files, one for each nested subsection?

With help from this example, I constructed the following system, which works well for me:
in layouts/recipes/list.html I included this:
{{ if (eq .Title "Recipes") }}
<ul class="postlist">
{{ range .Sections.ByTitle }}
<li>
{{ .Title }}
{{ partial "recursive.html" . }}
</li>
{{ end }}
</ul>
{{ else }}
<ul class="postlist">
{{ range .RegularPages }}
<li>
{{ .Title | markdownify }}
</li>
{{ end }}
</ul>
{{ end }}
And in layouts/partials/recursive.html I included this:
{{ $child_pages := union .Sections .Pages }}
<ul>
{{ range $child_pages.ByTitle }}
<li>
{{ .Title }}
{{ if or (.Sections) (.Pages) }}
{{ partial "recursive.html" . }}
{{ end }}
</li>
{{ end }}
</ul>
content/recipes/_index.md looks like this:
---
title: "Recipes"
---
and for example content/recipes/drinks/_index.md looks like this:
---
title: "Drinks"
---
This produces a page at ./recipes which contains a grouped list, where the first level includes links to further list pages (e.g. ./recipes/bread), which themselves contain links to the recipes in that group. All recipes are also listed below their parent group on ./recipes.

Related

Loop over posts in _index.html

I'm using Hugo to build my own website
I'm having a problem I have a _index.html page, and that is my homepage
But when I try to loop over posts, it just prints text no posts are shown
{{ range .Pages.ByDate }}
<div class="w-full md:w-1/2 md:px-3 mt-6">
<article class="h-full flex flex-col rounded-lg shadow-lg>
<h1>Post</h1>
</article>
{{ end }}
Where is _index.html located? If it's under content/, then raw Go-Template code will not work there. If it's under layouts/, then it is a Go Template but it is not the correct name for the layout of your home page. Possible names for the home-page layout file include:
layouts/index.html
layouts/home.html
layouts/_default/index.html
layouts/_default/home.html
(and more)
For details, see:
https://gohugo.io/templates/homepage/
https://gohugo.io/templates/lookup-order/#examples-layout-lookup-for-home-page
After you figure out what directory and what file name you want to use, you probably want to use something other than this inside the range:
<h1>Post</h1>
For example, maybe this:
<h2>{{ .Title }}</h2>
You could do the following:
{{ range ( where .Site.RegularPages "Type" "posts" ) }}
<h4>{{ .Title }}</h4>
{{ end }
Where posts is the name of the directory containing the posts (i.e., your_blog/content/posts in my case where I renamed posts directory to blog the above will look like this:
{{ range ( where .Site.RegularPages "Type" "blog" ) }}
<h4>{{ .Title }}</h4>
{{ end }

Hugo not rendering the summary from the front matter

According to the Hugo content summary guide, I can define a summary in 3 ways (listed in order of highest preference):
Use the <!--more--> tag to tell how much of the article Hugo should use as the summary
Use the summary variable in the front matter in order to use a custom summary
Let Hugo by default use the first 70 words of the article
First and foremost, here is the template I have for individual pages:
{{ partial "header" . }}
{{ partial "nav" . }}
<section class="section">
<div class="container">
<div class="subtitle tags is-6 is-pulled-right">
{{ if .Params.tags }}
{{ partial "tags" .Params.tags }}
{{ end }}
</div>
{{if not .Date.IsZero }}
<h2 class="subtitle is-6">{{ .Date.Format "January 2, 2006" }}</h2>
{{ end }}
<h1 class="title">{{ .Title }}</h1>
{{ if .Site.Params.Info.related }}
<div class="related">{{ partial "related" . }}</div>
{{ end }}
<div class="content">
<h1 id="summary">Summary</h1>
{{ .Summary }}
<h1 id="toc">Table of Contents</h1>
{{ .TableOfContents }}
{{ .Content }}
</div>
</div>
</section>
{{ partial "footer" . }}
Here is a sample article I made:
---
title: "Test"
date: 2019-11-23T19:51:44-06:00
draft: true
summary: "This is a simple placeholder summary defined in the front matter"
---
This is a simple placeholder written in the article
# Section 1
Hello world!
The title and date render just fine, however, the summary is ignored and the words from the article as used as the summary:
I then used the <!--more--> tag like so:
---
title: "Test"
date: 2019-11-23T19:51:44-06:00
draft: true
summary: "This is a simple placeholder summary defined in the front matter"
---
This is a simple placeholder written in the article
<!--more-->
# Section 1
Hello world!
It worked like a charm...
So methods 1 and 3 for content summaries work, but method 2 does not. Is there a reason why I can't get the summary front matter to render?
This feature was introduce in Hugo 0.55.0 via issue #5800.
Upgrade to Hugo 0.55.0 or above to solve the issue

Hugo Page Resources - can't get a match

I want to write a generic shortcode for my hugo-powered webseite that adds a download section to my pages listing all the files in the downloads folder.
I have the website layed out like this:
.
├── content
│   └── press
│   ├── downloads
│ │ ├── presstext.pdf
│   │   └── presskit.zip
│   ├── _index.de.md
│   └── _index.en.md
└── layouts
   └── shortcodes
   └── downloads.html
My markdown file looks like this:
---
title: "Downloads"
date: 2019-10-26T09:59:26+01:00
draft: true
resources:
- src: downloads/presskit.zip
title: Presskit
params:
icon: pdf
- src: downloads/presstext.pdf
title: Presstext
params:
icon: pdf
---
Look at my awesome downloads:
{{< downloads >}}
And my shortcode looks like this:
<ul class="downloads">
{{ range .Page.Resources.Match "downloads/*" }}
<li>
<a target="_blank" href="{{ .Permalink }}">
<i class="far fa-file-{{ .Params.icon }}"></i> {{ .Title }}
</a>
</li>
{{ end }}
</ul>
But no document ever get's matched, so {{ range .Resources.Match "downloads/*" }} always returns empty. Am I overlooking something?
I already tried:
{{ range .Resources.Match "downloads/*" }}
{{ range .Resources.Match "/downloads/*" }}
{{ range .Resources.Match "**.zip" }}
{{ range .Resources.Match "**.pdf" }}
{{ range .Resources.Match "press/downloads/*" }}
{{ range .Resources.Match "/press/downloads/*" }}
Running on Hugo 0.59.0
I gave up on this and ended up doing this instead:
.
├── content
│ └── press
│ ├── presstext.pdf
│ ├── presskit.zip
│ ├── _index.de.md
│ └── _index.en.md
└── layouts
└── shortcodes
└── downloads.html
my markdown:
---
title: "Downloads"
date: 2019-10-26T09:59:26+01:00
draft: true
resources:
- src: presskit.zip
title: Press kit
params:
icon: archive
download: true
- src: presstext.pdf
title: Press text
params:
icon: pdf
download: true
---
Look at my awesome downloads:
{{< downloads >}}
Shortcode:
<ul class="downloads">
{{ range .Page.Resources }}
{{ if isset .Params "download" }}
<li>
<a target="_blank" href="{{ .Permalink }}">
<i class="far fa-file-{{ .Params.icon }}"></i> {{ .Title }}
</a>
</li>
{{ end }}
{{ end }}
</ul>
OK, this is an old one, but the right answer is that for branch bundles (_index.md) you can have resources ONLY in the same folder.
For leaf bundles (index.md) you can have resources in subfolders.
I guess it is because every subfolder in branch bundles is supposed to be a page with resources (leaf bundle).
Here is the source https://gohugo.io/content-management/page-bundles/ (see the table row Where can the Resources live?)

Hugo cannot convert type page.PagesGroup to Pages

I have a Hugo list template like this:
{{ range (.Paginate (.Data.Pages.GroupByDate "2006")).PageGroups }}
<h3>{{ .Key }}</h3>
<ul>
{{ range .Pages.ByWeight }}
<li>
{{ if .Draft }}{{ T "draft" }}: {{end}}{{ .Title | markdownify }}
<time class="date-meta">{{ .Date.Format "Jan 2" }}</time>
</li>
{{ end }}
</ul>
{{ end }}
When I run the site like this hugo server -D it works fine.
When I build the site I get:
execute of template failed: template: _default/list.html:15:14: executing "main" at <.Paginate>: error calling Paginate: cannot convert type page.PagesGroup to Pages
Turning on debug and verbose do not help. I have:
content
content/web
content/web/one.md
content/web/two.md
content/web/_index.md
content/web/three.md
content/about
content/about/index.md
What gives?
I encountered this error while writing a custom theme except it happened when running hugo -D or hugo server -D. As a workaround try wrapping it in an if condition to check .Data.Pages.
{{ if .Data.Pages }}
{{ range (.Paginate (.Data.Pages.GroupByDate "2006")).PageGroups }}
...
{{ end }}
{{ end }}

Hugo: .Data.Pages works in Blog.html context but fails in another context

In blog.html partial, I have:
{{ range first 1 (where .Data.Pages "Type" "post") }}
<div class="ph1-ns w-50-ns flex">
{{ .Render "li" }}
</div>
{{ end }}
which successfully pulls data for one blog post.
I have another partial comic.html with the exact same code:
{{ range first 1 (where .Data.Pages "Type" "post") }}
<div class="ph1-ns w-50-ns flex">
{{ .Render "li" }}
</div>
{{ end }}
but this fails with the message:
2:18:57 PM: ERROR 2018/08/11 04:18:57 Error while rendering "section": template: /opt/build/repo/site/layouts/section/products.html:3:3: executing "main" at <partial "jumbotron" ...>: error calling partial: template: partials/jumbotron.html:6:11: executing "partials/jumbotron.html" at <partial "comic" .>: error calling partial: template: partials/comic.html:6:19: executing "partials/comic.html" at <where .content.Data....>: error calling where: can't iterate over <nil>
Notes:
blog partial is directly called from index.html using:
{{ partial "blog" . }}
comic partial is indirectly called from index html via jumbotron.html
index.html:
{{ partial "jumbotron" (dict "imageUrl" .Params.image "title" .Title "subtitle") }}
jumbotron.html:
{{ partial "comic" . }}
I suspected this might have been caused by not passing the context to jumbotron, so tried in jumbotron.html:
{{ partial "jumbotron" (dict "imageUrl" .Params.image "title" .Title "subtitle" .Params.subtitle "content" .) }}
and then pulled that context with .content i.e.
{{ range first 1 (where .content.Data.Pages "Type" "post") }}
but this also didn't work. I even tried declaring a variable using .Site.GetPage
and then referencing this variable for the .Data.Pages data, but it didn't work. Any help would be appreciated.

Resources