Grouping and sorting archives by year and month

I’ve been trying to change my archives page to group and sort the posts by year and month, but everything I’ve read and tried so far hasn’t worked. I’m assuming it’s because they’re relying on taxonomies and front matter from standard Hugo that isn’t accessible in Micro.blog.

I’m hoping to have a setup as follows:

2021
     Month1
             - post 1
             - post 2
             - …
     Month2
             - post 1
             - …

Anyone know how I can implement this?

1 Like

you can do something like what I do for reverse chron by day, but chronological within day:

{ define "main" }}  

{{ $posts := where site.RegularPages "Type" "post" }}
{{ $grouped := $posts.GroupByDate "2006-01-02" }}
{{ $paginated := (.Paginate ($grouped)) }}
<div class="content list h-feed">
{{ range $paginated.PageGroups }}
{{ $thedate := (time .Key) }}
<h1 class="day"> {{ $thedate.Format "January 2, 2006" }}</h1>
  {{ range .Pages.Reverse }}
    {{ if eq .Type "post" }}
      {{ partial "post_header.html" . }}
       <div class = "post-content e-content">
         {{ .Content }}
       </div>
     {{ partial "post_footer.html" . }}
    {{- end }}
  {{ end }}
<hr>
{{ end }}
</div>
{{ partial "paginator.html" . }}
{{ end }}

Note the $posts.GroupByDate — that’s the format for daily groups, but you can choose to use monthly or annually. Basically, I’d filter to a year of posts and then group those by month, and then do a range over those groupings. I’m pretty sure you could also group by year, range over those, group by month, range over those inside to do the whole thing as nested for loops but not 100% sure.

This is what the Ink theme has in layouts/_default/list.html

<!DOCTYPE html>
<html>
{{ partial "header.html" . }}

<body>
	<div class="container wrapper list">
		{{ partial "head.html" . }}

		{{ if isset .Data "Term" }}
			<h2>{{ .Data.Term }}</h2>
		{{ else }}
		<h2 class="page-title">{{ .Name }}</h2>
		{{ end }}
		
		{{ .Content }}

		<ul class="posts flat">
			{{- range .Data.Pages -}}
			{{- if (in (.Site.Params.excludedTypes | default (slice "page")) .Type) -}}
			{{- else -}}
			<li class="post">
				{{ partial "post-preview.html" . }}
			</li>
			{{- end -}}
			{{- end -}}
		</ul>
	</div>
	{{ partial "footer.html" . }}
</body>
</html>

I think you want this to be replacing layouts/index.html— but if this is just for archives, the part you want to replace is where it says {{ range .Data.Pages - }}.

So the whole ul element should work looking like this:

<ul class=“posts flat”>
{{ $posts := where site.RegularPages "Type" "post" }}
{{ $grouped := $posts.GroupByDate "2006-01-02" }}
{{ $paginated := (.Paginate ($grouped)) -}}
{{ range $paginated.PageGroups }}
  {{ range .Pages.Reverse }}
    <li class="post">
      {{ partial "post-preview.html" . }}
    </li>
  {{ end }}
{{ end }}
</ul>

The first line is substantially similar to the {{ if }} statement after the range over .Data.Pages, but I don’t filter for exclusions set in the site params. I’m not 100% sure how to do that with a where statement but it’s probably pretty simple if you still need that filtering.

So in layouts/index.html, I see the following code:

{{ partial "header.html" . }}
{{ partial "head.html" . }}
	<div class="recent-posts section">
		<div class="posts">
			{{ $pages := where .Site.Pages.ByDate.Reverse "Type" "post" }}
			{{ $paginator := .Paginate (where $pages "Params.hidden" "ne" true) }}
			{{ range $paginator.Pages }}
				<div class="post">
					{{ partial "post-preview.html" . }}
				</div>
			{{ end }}
			{{ template "partials/paginator.html" . }}
		</div>
	</div>
</div>
{{ partial "footer.html" . }}

Getting this error message:

Error: "/layouts/index.html:12:1": parse failed: template: index.html:12: unrecognized character in action: U+201C

This is a curly quote. Copying and pasting into some programs with “smart quotes” can do that. Hand replace the quotes directly in the text box on micro.blog will fix that.

On the index it’s the same code pretty much— although it shows how to do the filtering if you need it.

Nope, that didn’t fix it either. Getting the same error.

BTW do I change both /layouts/index.html and layouts/_default/list.html or just one of them?

I’m 100% positive the issue is the quotes around the date in the above post. I edited it to fix.

This diff should show how it would work https://github.com/jsonbecker/theme-ink/pull/1/files

Thanks. This made sense. However, I don’t know why it doesn’t work on the Ink theme. I like how you have done it on your homepage. Date in a larger font with hyperlinked timestamp. Also, I like how if your post has a title, it still displays in full although most of my posts, micro or macro may not have titles.

Wish I could steal that :slight_smile:

That’s all a part of the post-partial and how it works. I’ve never really tried to make my theme not super specific to me, but I could look into it if there’s interest.

I think the structure of post-partial and the surrounding HTML would have to be adjusted. Just for comparison, here’s what my index page looks like:

{{ define "main" }}  
{{ $posts := where .Site.Pages "Type" "post" }}
{{ $grouped := $posts.GroupByDate "2006-01-02" }}
{{ $paginated := (.Paginate ($grouped)) }}
<div class="content list h-feed">
{{ range $paginated.PageGroups }}
{{ $thedate := (time .Key) }}
<h1 class="day"> {{ $thedate.Format "January 2, 2006" }}</h1>
{{ range .Pages.Reverse }}
    {{ if eq .Type "post" }}
<article class = "h-entry">
 <div class="title-area">
       {{ if .Title }}
        <h2 class = "p-name  post-title">
          <a class = "u-url" href = "{{ .Permalink }}">{{ .Title }}</a>
        </h2>
        {{ end }}
    <time class = "date dt-published" datetime = "{{ .Date.Format "January 02, 2006 15:04:05  -0700" }}" {{ if not .Title }} style="justify-content:flex-end;" {{ end }}>
      <a class = "u-url" href = "{{ .Permalink }}">{{ .Date.Format "3:04PM" }} </a>
    </time>
</div>
       <div class = "post-content e-content">
         {{ .Content }}
       </div>
     {{ partial "post_footer.html" . }}
    {{- end }}
  {{ end }}
{{ end }}
 </div>
{{ partial "paginator.html" . }}
{{ end }}

Yup, I think I’ve reached the end of my current capabilities. I tried modifying the code in the index page but as you said, it may need adjusting elsewhere. I wish I could modify it for the existing MB themes (Ink, Lanyon, etc.) coz those suit the way I blog (similar to yours).

If you ever think of porting such a theme, color me interested. I think David (@crossingthethreshold) may also be interested.

It’s lunchtime here and I’m just checking in to see where things are at. Looking at what @pratik has done, I don’t think that I would be capable to do anymore. I also like how the post timestamps work on your site @jsonbecker. I might still tinker, but I would be interested if you, Jason, do port a theme like yours.

Thank you for all of your help.

I built a test archive to match the original post, btw. (hi @pimoore )

Check this

layouts/archive/single.html

{{ define "main" }}
{{$pages := where .Site.Pages "Type" "post" }}
  {{ range $pages.GroupByDate "2006" }}
        <div class="group">
            <h2 class="key">
                {{ .Key }}
            </h2>
            {{ range .Pages.GroupByDate "January" }}
               <h3 class="key">
                {{ .Key }}
                </h3>
             {{ range .Pages }}
              {{ partial "li.html" . }}
            {{ end }}
   {{ end }}
{{ end }}
{{ end }}

content/testarchive.md

---
title: History
description: Archive of posts
type: archive
---

To make this show up in /archive you’ll have to delete that page from the micro.blog interface and rename content/testarchive.md to content/archive.md.

2 Likes

Oh that’s perfect, exactly what I was looking for! I’m also doing some thinking around various layouts for the index page posts, including your setup, with relation to themes. I’m not a huge fan of having the index page just be a pagination through the whole site, and I much prefer how Hitchens is implemented in this regard compared to Tufte.

I like the index being just the recent or current day’s posts, or even just a single post like I’ve seen on many with a link to the archive instead. I’m also looking into a couple of ideas @JohnPhilpin mentioned around date links, and setting them up to show all the posts for that date as opposed to that specific post only.

1 Like

:nerd_face:

cockles duly warmed !

1 Like

Pretty easy to do that on the index page-- but the date links are actually very tricky on Hugo.

What makes them so challenging out of curiosity?

Hugo doesn’t really have a great way of generating pages from your post data-- it either wants to show a collection on a page based on your filtering or show a single one on a page, but the idea of generated paths and files that have lists with filters in an automated way is not really a supported use case. Lots of stuff on the Hugo forums about this-- but there’s no way to tell Hugo make a folder like /yyyy/mm and there filter to those posts. The only way I think this can be done is making custom pages for every /yyyy/mm you have, add those as page parameters in the front matter, then filter posts to that.

1 Like