Add a body class in single.html for the most recent post

I need to be able to add a <body> class for the most recent post on that posts’ single.html page.

I can do this in single.html

{{ $Len := len "posts" }}
{{ if gt $Len 1 }} Not First Post
{{ else }} First Post
{{ end}}

But how can I do the same thing in the body tag for the most recent post on single.html? I.e.,

<body class="{{ $Len := len "posts" }}
{{ if gt $Len 1 }}
{{ else }} first-post-class
{{ end}}
">

Do you mean you want to add a class when there is only one post, or on the first post ever created (assuming by date or some other sorted order)?

But looking at your code above, I don’t see why if the first is working, the second isn’t giving you want you want (maybe the empty if statement?). but a simpler way to do that would be the following (untested):

{{ $classList := "" }}
{{ /* append any number of classes to be included here */ }}
{{ $Len := len "posts" }}
{{ if eq $Len 1 }}
{{ $classList := print $classList " first-post-class" }}
{{ end}}

<body class="{{ $classList }}">

Thanks, I wasn’t very clear; I want to add the body class to the most recent single post; I don’t need the <body> class on the _index.html of posts, only in the <body> of the single.html of the most recent post. But the function needs to go in baseof.html, and thus will run on all pages. So the problem seems to be that $Len := len "posts" doesn’t work in baseof.html, only within single.html. Your function above crashes on any classed added within “append”.

My example didn’t use append, which is for slices etc. It uses print, which is how to concat strings. Is that what you mean?

I don’t need to concat or print. This is what I use now to output body classes in baseof.html:

<body class="
{{ .Type }} {{ with .File }}{{ .TranslationBaseName }}{{ end }}
{{ range (.GetTerms "tags") }}{{ urlize .LinkTitle }} {{ end }}
{{ range (.GetTerms "categories") }}{{ urlize .LinkTitle }}{{ end }}
{{ if eq .Kind "taxonomy" }}{{ urlize .Title }}{{ end }}
">

Somehow I need to add “first-post-class” to the body tag for the most recent post on single.html.

Again I haven’t tried this, but you might be able to use .Next or .Prev to check if it’s the first page (depending on sort order). If the appropriate function returns nil, then single.html is outputting the most recent page, and you could add your class.

.Next
Points up to the next regular page (sorted by Hugo’s default sort). Example: {{with .Next}}{{.Permalink}}{{end}}. Calling .Next from the first page returns nil.

.Prev
Points down to the previous regular page (sorted by Hugo’s default sort). Example: {{if .PrevPage}}{{.PrevPage.Permalink}}{{end}}. Calling .Prev from the last page returns nil.

I looked at that and it appears possible, but .Next is nil on all single.html posts, not just the most recent post.

Here’s how I would approach it, this could be more cleaner but I wanted to prioritize clarity.

{{ $first_post := "" }}
{{ with where site.RegularPages "Type" "posts" }} # this could be `"Section" "posts"
  {{ $first_post = index . 0 }}
{{ end }}

{{ $body_class := "" }}
{{ if eq $first_post $ }} # Should work but if not try comparing `.File.UniqueID`
  {{ $body_class = "first-post-class" }}
{{ end }}
<body class="{{ $body_class }}"></body> 
1 Like

Thanks! With your example, I got an error that $class was undefined, but I modified it and this works as a simpler version and outputs first-post on the first single.html post and not on _index or anywhere else.

 {{ with where site.RegularPages "Type" "posts" }}
 {{ $first_post = index . 0 }}
 {{ if eq $first_post $ }}
 first-post
 {{ end }}
 {{ end }}

That said, it would be cleaner to generate all the body classes as in my earlier example of what I use now:

 {{ .Type }} {{ with .File }}{{ .TranslationBaseName }}{{ end }}
 {{ range (.GetTerms "tags") }}{{ urlize .LinkTitle }} {{ end }}
 {{ range (.GetTerms "categories") }}{{ urlize .LinkTitle }}{{ end }}
 {{ if eq .Kind "taxonomy" }}{{ urlize .Title }}{{ end }}

and then output them in the body tag like your example

<body class="{{ $body_class }}"></body>

Well I would create a returning partial doing all the heavy lifting of building this class string and then:

<body class="{{ partial "func/GetBodyClasses" . }}"></body>

I wrote a piece about returning partials: https://regisphilibert.com/blog/2019/12/hugo-partial-series-part-2-functions-with-returning-partials/

That’s interesting; good idea. I’ll try a returning partial.

Any idea on how I would find the last post? I don’t see how to use https://gohugo.io/functions/last if that would work for posts.

last takes a integer, $last := last 1 $posts will return an array containing the one last post. Then you should index $last 0 to isolate the post in the array.

Just learning here :slight_smile:
Error “can’t iterate over *hugolib.pageState” using this:

{{ with where site.RegularPages "Type" "posts" }}
{{ $last_post := last 1 $ }}
{{ if eq $last_post $ }}
last-post
{{ end }}
{{ end }}

Learning is great, you should start here though: https://regisphilibert.com/blog/2018/02/hugo-the-scope-the-context-and-the-dot/

Thanks :slight_smile: But it’s still a mystery to me…