How to replace Home Page with Posts?

Hello,
My posts are rendered using the layouts/posts/list.html for the list view and layouts/posts/single.html for individual posts, which are visible at localhost:1313/posts. I want the list page to appear as the home page instead. The only solution I’ve found is to copy the content of layouts/posts/list.html into layouts/index.html, but this feels redundant. Is there a more efficient way to achieve this?

If this feels redundant then move the identical parts of layouts/index.html and layouts/posts/list.html into a partial layouts/partials/blog-post-list.html (other than layouts/partials feel free to rename and put into subfolders as you wish) and remove those parts from your two templates and replace with {{ partial "blog-post-list.html" }}.

All else is the way it was intended. Showing the same on the frontpage as on a posts list is two features… so two layout files. If it looks the same, then put into partials and get the code from there. This way you save double work when you change things.

You will run into issues like mydomain.com showing the same as mydomain.com/posts, but that can be solved with aliases for your content/_index.md.

Two links with the concepts:

1 Like

That’s what I want. mydomain.com to show mydomain.com/posts.

I copied the content of layouts/posts/list.html into layouts/index.html. The problem is that it shows my About page as well which I don’t want. Only blog posts.

The About page has its own page type.

+ content
   + about
        + index.org

#+title: About
#+type: about
#+draft: false

Content

and layouts/about/single.html

{{ define "main" }}
  <h2>{{ .Title }}</h2>
  {{ .Content }}
{{ end }}

I don’t want these separate pages like “About”, “Contact” to appear among my blog posts on the home page.

This is my layouts/index.html:

{{ define "main" }}
<div class="blog">
  <div class="blog-container">
    <h2 class="screen-readers">{{ .Title }}</h2>
    {{ range $p := .Paginator.Pages }}
    <article class="blog-post">
      <header>
        <h2><a href="{{ .RelPermalink }}">{{ .Title }}</a></h2>
        </div>
      </header>
      {{ with or (.Resources.GetMatch "featured.*") (.Resources.Get .Params.featuredimage) }}
      <div class="featured-image">
        <a href="{{ $p.RelPermalink }}">
          <img src="{{ .RelPermalink }}" loading="lazy" width="{{ .Width }}" height="{{ .Height }}" alt="featuredimage">
        </a>
      </div>
      {{ end }}
      <div class="post-summary">
        {{ .Summary }}
      </div>
      <footer>
        {{- if .Truncated -}}
        <p><a class="read-more" href="{{ .RelPermalink }}">Read more&hellip;</a></p>
        {{- end -}}
      </footer>
    </article>
    {{ end }}
  </div>
</div>
{{ template "_internal/pagination.html" . }}
{{ end }}

I guess I need to limit the

{{ range $p := .Paginator.Pages }}

to blog posts only, but I don’t know how to do it.

I can fix it for now by using a dash in the name of content file for about, like so:

myhugosite/content/about/_index.org

If I use index.org the About page shows up among my blog posts as well on the home page.

UPDATE:

I tried this in the layouts/index.html and it seems to work:

{{ range $p := where .Paginator.Pages "Type" "posts" }}

Can someone confirm me if it’s okay to do it this way? Now only the blog posts appear on the home page which is what I wanted.

Disclaimer: I am really bad with org-mode.

Did you know that “root folders” in content always result in .Type = foldername? So no need to have content/about/index.md with type: about because it’s already of type about.

Then, there is a system where you define a “type” as default post type and then use site.RegularPages with that default post type to show only posts from that section (or slice of sections).

for instance:

in your config.toml:

[params]
mainSections = ["blog", "components", "music", "video"]

(makes the folders content/blog, content/components, etc the folders that your blog posts are about)

then in your post list:

{{- $pages := collections.Where site.RegularPages "Type" "in" site.Params.mainSections -}}

then range through this.

my blog posts are only located inside /content/posts/, nowhere else. I was wondering if my range condition is good in that case:

{{ range $p := where .Paginator.Pages "Type" "posts" }}
mainSections = ["posts"]

I see no reason to add a separate configuration section only for that but thank you.

yeah, that range is ok. Maybe use RegularPages instead of Pages. That will filter out home page and other pages that are not of any type.

I am doing that only for portability. If you are working only with one single website/theme and will never work with another website then yeah, your range is the best way to do it.

I’m trying this

{{ range $p := where .Paginator.RegularPages "Type" "posts" }}

but it throws an error:

executing "main" at <where>: wrong number of args for where: want at least 3 got 1

Ehm… stop listening to me. I overlooked that you are working with .Paginator - that one has only .Pages, not .RegularPages.

In general… I know only that one line, so I don’t know what you are doing before to configure your paginator. You might be able to set the .RegularPages part somewhere earlier on, but .Paginator has only .Pages. Use:

{{ range $p := where .Paginator.Pages "Type" "posts" }}

And stop trying to optimize… If it’s working, then good, if not, let’s fix that :slight_smile:

It’s working but what I find strange is that the paginator still counts the About page as a page, even though it’s no longer on my home page due to the range condition.

{{ range $p := where .Paginator.Pages "Type" "posts" }}

On the home page I get +1 in the paginator, and when I access mydomain.com/posts/ directly that one is not added which is the correct behavior.

Yeah, it’s a blackbox :wink: Your code somewhere defines the “dict” of “pages” that are part of your “paginator”. At that point it needs to know to use RegularPages instead of Pages, but we need to know more than single lines of code for that to be solved.

From the documentation:

Although simple to invoke, with the Paginator method you can neither filter nor sort the page collection. It acts upon the page collection received in context.

So, filter (aka “use where”) first, paginate then.

1 Like

I do not wish to confuse you anymore than you probably are, but this is my partial that is setting the $paginator variable globally in my website:

So, filter (aka “use where”) first, paginate then.
That’s a good point.

I tried this:

{{ $pages := where site.RegularPages "Type" "posts" }}
{{ $paginator := .Paginate $pages.ByTitle 10 }}

{{ range $paginator.Pages }} <-- the condition
...
  the rest of the template
...

and it works. The problem is that the previous code was:

{{ $p := range $paginator.Pages }}

and I need that page reference captured in a variable because it is used in the template in:

{{ with or (.Resources.GetMatch "featured.*") (.Resources.Get .Params.featuredimage) }}
<div class="featured-image">
   <a href="{{ $p.RelPermalink }}">
       <img src="{{ .RelPermalink }}" loading="lazy" width="{{ .Width }}" height="{{ .Height }}" alt="featuredimage">
   </a>
</div>
{{ end }}

@zoliky

Yes, but don’t worry about efficiency right now. Let’s get it working first. This thread has become unnecessarily complicated.

Replace this:

{{ range $p := .Paginator.Pages }}

With this:

{{ range $p := (.Paginate (where site.RegularPages "Type" "posts")).Pages }}
1 Like

Thank you very much. You are extraordinary. It works well!

Initially, I just wanted to change to have /posts on the home page, but in the meantime, the pagination issue came up, which I hadn’t noticed because I didn’t have at least 10 posts. This led me to stray from the original topic. I apologize for that. In the end, the problem was fixed thanks for your help. I’m copying the layouts/posts/list.html into layouts/index.html. It’s fine for me as long as it works.

1 Like

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.