Different page types without organising into subdirectories?

My site is pretty much ‘all blog’, so I’ve not bothered with organising my content into a “posts” subdirectory, or anything like that [So I can keep the URLs that wee bit shorter]. However, I would like to add a static “About” page and I’m wondering how to go about this.

At the minute I’ve got type="post" in the front-matter of all the blog posts and type="staticpage" in the front-matter of the About page. I’m not quite clear on how:

  1. I filter out the ‘About’ page so it doesn’t show up on the index page in amongst the list of blog posts. Some template code needed for the index to only list pages where type="post"

  2. Populate my navigation menu with only links to pages [or in this case a solitary page] where type="staticpage"

I know the ‘conventional’ way to do it would be to have ‘posts’ and ‘about’ subdirectories, but it seems a bit clunky to have to lengthen every URL on my site with an extra /posts/ element, just for the sake of adding one extra ‘About’ page.

Can anyone help me with some necessary template code magic?

{{ range where .Data.Pages "Type" "post" }}
1 Like

Nice one, cheers. I’ll try that.

I knew it would be something simple, but I’m still getting my head round Hugo’s templating code.

I’ve just noticed that this seems to have broken, since upgrading to the latest version of Hugo with the ‘Paginator’ function.

Where before, in my index.html template, I had:

{{ range where .Data.Pages "Type" "post" }}

working to filter out my static page, so it was not listed amongst the blog entries, the equivalent code with the new paginator function isn’t working:

{{ $paginator := .Paginate (where .Data.Pages "Type" "post") }}

The paginator seems to be taking no notice of the type=..." in the front matter and is listing my static page alongside the blog posts, even though its type is set to type="staticpage" rather than post.

Any suggestions folks?

As I implemented the paginator thingy, I suggest you are doing something wrong :slight_smile:

My best guess is that you access the .Pagiantor or .Paginate earlier in the template chain (by including the paginator.html partial, maybe?). The paginator is static (one per Node) and the first will win, so to speak.

This [sans header and footer partial includes] is the body of my index.html template. Can you see where I’m going wrong?

<div class="paginatorheading">Page {{ .Paginator.PageNumber }} of  {{ .Paginator.TotalPages }}</div>
    {{"<!--  begin main //-->" | safeHtml}} 
    <main class="indexpage">
      {{ $paginator := .Paginate (where .Data.Pages "Type" "post") }}
      {{ range $paginator.Pages }}
            {{"<!--  begin main > article //-->" | safeHtml}} 
            <article class="indexpage">
                {{"<!--  begin main > article > header //-->" | safeHtml}} 
                    <a href="{{ .Permalink }}">{{title .Title }}</a> <span class="headerpostdate">{{.Date.Format "02 Jan 2006"}}</span>
                {{"<!--  end main > article > header //-->" | safeHtml}} 
                {{"<!--  begin main > article > summary //-->" | safeHtml}}
                {{ .Summary }}... 
                <span class="readmore">[ <a href="{{ .Permalink }}">Read More</a> ]</span>
                {{"<!--  end main > article > summary //-->" | safeHtml}}
            {{"<!--  end main > article //-->" | safeHtml}}
            {{ end }}
      {{ template "theme/partials/pagination.html" . }}


{{ .Paginator.PageNumber }}

And the paginator will be created with default bells and whistles.

Move this line to the top:

 {{ $paginator := .Paginate (where .Data.Pages "Type" "post") }}

And you should be good.

Edit in: We should add a ERROR logging for this case.

1 Like

Worked a treat.



Sorry for using this old thread but I’ve got a similar issue where “About” page is still listed amongst the list of blog posts.

I modified this file as below:

{{ partial "header.html" . }}

<main id="content">
{{ $paginator := .Paginate (where .Data.Pages "Type" "post") }}
        <h1 class="post-title">{{ .Title }}</h1>
    {{ range $index, $page := $paginator.Pages }}
        {{ .Render "li" }}
    {{ end }}

    {{ partial "pagination.html" $paginator }}

{{ partial "footer.html" . }}

Hard to say without a more complete example (what Type is the About page, really? etc).

Have you remembered to set your ‘About’ page to be a type which isn’t 'post" in its frontmatter?

Here’s what I’ve currently got and it works fine:

example frontmatter for blog post:

date = "2015-08-04T09:50:25+01:00"
mdrbyeline = "A change of [virtual] scenery"
mdrpagetype = "blogpage"
mdrposticon = "/icons/cogs.png"
tags = ["frankfurt","germany","deutschland","linode","server","datacentre"]
title = "Ich Bin Ein Frankfurter!"
type = "post"

frontmatter for ‘About’ page:

date = "2015-01-01T17:00:51Z"
type = "staticpage"
mdrbyeline = ""
tags = [""]
title = "About"

list view temple: themes/mytheme/layouts/_default/list.html

{{ template "theme/partials/header.html" . }}
	{{"<!-- index layout //-->" | safeHTML}}
	{{"<!-- begin [banner] header //-->" | safeHTML}} 
	<header class="banner">
		{{"<!-- begin [banner] navbar //-->" | safeHTML}} 
		<div class="navbar">
			{{ template "theme/partials/navbar.html" . }}
		{{"<!-- end [banner] navbar //-->" | safeHTML}} 
	 <a href="{{ .Site.BaseURL }}">
		 <img src="{{ .Site.BaseURL }}/grafix/themsgoodbrothlogo.png" />
	{{"<!-- end [banner] header //-->" | safeHTML}} 
	{{ $paginator := .Paginate (where .Data.Pages "Type" "post") }}
  <div class="paginatorheading">Page {{ .Paginator.PageNumber }} of  {{ .Paginator.TotalPages }}</div>
	{{"<!--  begin main //-->" | safeHTML}} 
    <main class="indexpage">
      {{ range $paginator.Pages }}
			{{"<!--  begin main > article //-->" | safeHTML}} 
			<article class="indexpage">
				{{"<!--  begin main > article > header //-->" | safeHTML}} 
					<a href="{{ .Permalink }}">{{title .Title }}</a> <div class="headerpostdate">{{.Date.Format "02 Jan 2006"}}</div>
				{{"<!--  end main > article > header //-->" | safeHTML}} 
				{{"<!--  Posticon. Show one if defined //-->" | safeHTML}} 
				<div class="posticon">
					{{ if isset .Params "mdrposticon" }}
					<img src="{{.Params.mdrposticon }}" />
					{{"<!--  Posticon. Otherwise show default //-->" | safeHTML}} 
					{{ else }}
					<img src="/icons/default.png" />
					{{ end }}
				{{"<!--  begin main > article > summary //-->" | safeHTML}}
				{{ .Summary }}... 
				<span class="readmore">[ <a href="{{ .Permalink }}">Read More</a> ]</span>
				{{"<!--  end main > article > summary //-->" | safeHTML}}
				<div class="clearing"></div>
			{{"<!--  end main > article //-->" | safeHTML}}
			{{ end }}
      {{ template "theme/partials/pagination.html" . }}
		{{"<!-- end main //-->" | safeHTML}}
		{{ template "theme/partials/footer.html" . }}
1 Like

Sorry, I forgot to add this info, all posts are set to type = "post" and then about page is set to type = "staticpage"

That’s weird. On the face of it, you seem to have the exact same setup as me. But it’s working fine on mine.

Now I come to think of it though, I seem to remember it breaking once a while back, but I can’t for the life of me remember what the cause was… possibly a Hugo update, or something I did while tweaking the template.

I’ll have a look back through my git history and see if there’s anything in the commit messages that might shed light on it. If so, I’ll get back to you.

Thanks for your help.

This seems to work when I moved both files (li.html, list.html) from theme directory to local layout directory, any idea why?

It also displays a site .Title on the list page for some reason now.

I didn’t find anything in my git history to remind me what I broke/fixed when wrestling with this before, but I’ve just noticed something that might shed some light on it.

When you view your site’s frontpage, the template in:


is used.

When you view a list of related posts, for example by clicking on a tag to see all posts with that tag, the template used is the one in


So you actually have two template files producing ‘list of posts’ type pages. you’d need to make sure that you had your static page excluding code in both. In fact, the snippets I posted above might have been misleading, since I gave you what was in my themes/yourtheme/layouts/_default/list.html rather than my ```themes/yourtheme/layouts/index.html file –even though both are essentially the same in my theme.

Now that I come to think of it, that may have been the gotcha I ran into that I’ve been trying to remember. I think I had just changed one of the templates and was puzzled that sometimes my static page showed up and sometimes it didn’t –because I mistakenly thought any kind of page which gave listings of posts used the same template.

As regards this:

when I moved both files (li.html, list.html) from theme directory to local layout directory, any idea why?

I’d imagine that it’s to do with how Hugo prioritises generic templates vs theme templates [or vice versa] but it would need someone better versed in Hugo’s internals to say for sure.

Thanks for all your help.

This was a problem with priority when rendering a home page,. The template that I use is also listing posts on the home page so I had to apply this change in index.html file as well.


Glad it worked out for you, but not sure I understand what solved it, so I should just let it be – but note this:

There is one paginator per Node (home page, section, taxonomy page), a reuse of the same template shouldn’t mess with that fact.

Sorry for the late reply.

Basically due to the fact that this template is also listing posts on the home page I had to make this change in two places:

  • layouts/_default/list.html
  • layouts/index.html



With your help I managed to exclude static pages from pagination on the pages where all the excerpts are shown. But they are still paginated when you have opened a single blog post at the bottom (navigating to newer or older posts).

On https://blog.mdosch.de/ the static page https://blog.mdosch.de/chat/ is not shown (although it would be the second latest created) so it works so far.
But when you open same_domain_only_two_links_allowed/2017/11/20/testweise-umstellung-auf-hugo/ it links to the chat static page and not to the next older blog post.

I added the checking for Type=Post almost everywhere now where it could have an impact but now I don’t know anymore what else to try.

Blog posts are in content/post and static pages are in content/page.

grep -ri -A1 -B1 Pagi layouts
layouts/index.html-    <section id="main" class="outer">
layouts/index.html:        {{ $Paginator := .Paginate (where .Data.Pages "Type" "post") }}
layouts/index.html:        {{ range $Paginator.Pages }}
layouts/index.html-        <article class="article article-type-post" itemscope itemprop="BlogPosting">
layouts/index.html:        {{ partial "pagination.html" . }}
layouts/index.html-    </section>
layouts/taxonomy/tag.html-            <div class="archives">
layouts/taxonomy/tag.html:                {{ $Paginator := .Paginate (where .Data.Pages "Type" "post") }}
layouts/taxonomy/tag.html:                {{ range $Paginator.Pages }}
layouts/taxonomy/tag.html-                {{ partial "li.html" . }}
layouts/taxonomy/tag.html-            </div></section>
layouts/taxonomy/tag.html:        {{ partial "pagination.html" . }}
layouts/taxonomy/tag.html-    </section>
layouts/_default/list.html-            <div class="archives">
layouts/_default/list.html:                {{ $Paginator := .Paginate (where .Data.Pages "Type" "post") }}
layouts/_default/list.html:                {{ range $Paginator.Pages }}
layouts/_default/list.html-                    {{ partial "li.html" . }}
layouts/_default/list.html-        </div></section>
layouts/_default/list.html:        {{ partial "pagination.html" . }}
layouts/_default/list.html-    </section>
layouts/partials/pagination.html:{{ $Paginator := .Paginate (where .Data.Pages "Type" "post") }}
layouts/partials/pagination.html:{{ $pag := $Paginator }}
layouts/partials/pagination.html-{{ if gt $pag.TotalPages 1 }}

Does anyone have an idea what I am doing wrong?