Can a post be "Pinned?"

Hello Forum,

Is there a way to “pin” a blog post to the top of your timeline, meaning that particular post is always shown as the most recent – first post on the blog? I am using the Arabica Theme.

Cheers!

There isn’t a mechanism for this, but I played around with rolling my own via theme customization. If you don’t plan on changing the pinned post very often I could probably help you modify your theme to show a particular post followed by the list as usual.

{{- range first 1 (where .Site.Taxonomies.category.featured.Pages) }}
 <div class = "post-content e-content">
   {{ .Content }}
 </div>
{{- end }}

Something like that should work, with the post having a category of “featured”. You can then follow up with the normal index stuff. This will have the effect of showing that post twice (probably) if it’s the newest post. There’s certainly away around that, but not up for thinking through that at the moment.

2 Likes

I actually started playing around with this concept again. As soon as I can confirm I am pulling up my “personal-favorites” and intersecting them with the category in my new layouts/_default/taxonomy.html template. I should be able to use this information to pull out posts to be pinned; and, perform some sort of minus set operation to remove the pinned posts from what I will pass to the list partial.

Update: the point being that I may be able to help others do the same kind of customization.

Another update: confirmed the intersection is working. Probably finish up tomorrow.

Also not obvious: I am working on pinned posts per category page.

Wow. Pinned posts per category would be very cool!

As @Moondeer is hinting, you can do this with an intersect between categories. intersect | Hugo

Thought I would layout what I have found so far in case others want to tinker.

The trick to controlling your category pages lies in creating layouts/_default/taxonomy.html

Mine, upon waking, looks like this (I successfully tested the intersection but haven’t done anything with it).

{{ define "main" }}
<div style="margin-bottom: 8vw; line-height: 26px;"  class="category-content">
<em>{{ .Content }}</em>
{{ $favorites := .Site.Taxonomies.categories.Get "personal-favorites" }}
{{ printf "<!--\nfavorites = %v\n-->" $favorites | safeHTML }}
{{ $pages := where .Data.Pages.ByDate.Reverse "Type" "post" }}
{{ printf "<!--\npages = %v\n-->" $pages | safeHTML }}
{{ $pinned := $favorites.Pages | intersect $pages }}
{{ printf "<!-- pinned: %v -->" $pinned | safeHTML }}
</div>
  {{ partial "post-list.html" . }}
{{ end }}```

Also of note is the `.Content` up there. I noticed in documentation that the *content* markdown files I introduced to control category front matter could also be used to inject per-category introductory content. An example would be the following, for my *Critters* category, which is located within my theme at `content/categories/critters/_index.md`

``` markdown
---
title: "Critters"
description: "All things critter-related."
aliases: [/critters/]
menu:
  main:
    name: "Critters"
    title: "Critters"
    identifier: "critters"
    url: "/critters/"
    weight: -50
---

All things critter-related.

Anything after the second --- is available to the taxonomy template as .Content

How the div up there currently renders:

<div style="margin-bottom: 8vw; line-height: 26px;" class="category-content">
<em><p>All things critter-related.</p>
</em>

<!--
favorites = [WeightedPage(0,"") WeightedPage(0,"") WeightedPage(0,"Chord Finder") WeightedPage(0,"On Pet Loss") WeightedPage(0,"So long Twitter, and thanks for all the fish") WeightedPage(0,"On Dragons") WeightedPage(0,"On Cycles") WeightedPage(0,"On Bright Futures") WeightedPage(0,"On Raging Bulls") WeightedPage(0,"On Moving the Needle") WeightedPage(0,"On F$&king Up Careers") WeightedPage(0,"Perpetual Groove") WeightedPage(0,"") WeightedPage(0,"Electronic Pipe") WeightedPage(0,"Dugan’s Collar") WeightedPage(0,"") WeightedPage(0,"On Political Analysis")]
-->

<!--
pages = Pages(82)
-->

<!-- pinned: Pages(1) -->
</div>

I see what you’re going for here, but it does seem a little overly complex, no? To show the top page that’s pinned you should just need something similar to what I have above:

{{- range first 1 (where .Site.Taxonomies.categories.personal-favorites.Pages) }}
<div class = "post-content e-content">
   {{ .Content }}
 </div>
{{- end }}

Would print the full post of the first page with a category of personal-favorites.

You could then list the remaining pages with:

{{ range after 1 (where .Site.Taxonomies.categories.personal-favorites.Pages)  }}
    {{ partial "post-list.html" . }}
{{ end }}

Or something similar.

Here is what I went with (I am converting the personal-favorites category to a new pinned category that won’t be in the menu; but, it is taking forever for my favorite posts to show up in the new category so the code still pulls from personal-favorites). I believe your suggestion would pull the latest post from a category while I am pulling posts from a particular combination of categories, one of which being the category for which the list page is being generated. The code to follow grabs the posts identified for pinning, removes them from pagination, and then the paginator is checked to determine whether the current page is not the first page (in which case the pinned posts are not shown).

The current contents of layouts/_default/taxonomy.html:

{{ define "main" }}
<div style="margin-bottom: 8vw;line-height: 26px; text-align: left;"  class="category-content">
{{ .Content }}
</div>
{{ $pinned := .Site.Taxonomies.categories.Get "personal-favorites" }}
{{ $all_pinned_pages := $pinned.Pages }}
{{ $pages := where .Data.Pages.ByDate.Reverse "Type" "post" }}
{{ $pinned_pages := $all_pinned_pages | intersect $pages }}
{{ $remaining_pages := $pages | symdiff $pinned_pages }}
<ul id="post-list">
{{- if .Site.Params.paginate_categories -}}
  {{- $paginator := .Paginate $remaining_pages -}}
  {{- if not $paginator.HasPrev -}}
    {{- range $pinned_pages -}}
      {{ partial "truncated-post-item.html" . }}
    {{- end -}}
  {{- end -}}
  {{- range $paginator.Pages -}}
    {{ partial "truncated-post-item.html" . }}
  {{- end -}}
{{- else -}}
  {{- range $pinned_pages -}}
    {{ partial "truncated-post-item.html" . }}
    {{ end }}
  {{- range $remaining_pages -}}
    {{ partial "truncated-post-item.html" . }}
  {{- end -}}
{{- end -}}
</ul>

{{- if .Site.Params.paginate_categories -}}
  {{ partial "pagination" . }}
{{ end }}
{{ end }}

If you wrap it in {{- range .Paginator.Pages }} ... {{- end }} in layouts/_default/taxonomy.html, you’ll already get just the pages in the category for the page you’re on.

Intersect and symdiff are good uses though, I see what you mean by having both. See what you’re trying, but I think it’s worth showing a slightly simpler method for others reading.

If your layouts/_default/taxonomy.html layout is something like this:

{{ $pinned = first 1 (intersect .Paginator.Pages .Site.Taxonomies.categories.personal-favorites.Pages) }}
{{- range $pinned.Pages }}
<div class = "post-content e-content">
  {{ .Content }}
 </div>
{{- end }}
{{- range  .Paginator.Pages | symdiff $pinned.Pages }}
  {{ partial "post-list.html" . }}
{{-end }}

What that says is “grab the first page only that is on the list of pages for this page (your category) that also has the category personal-favorites (make that whatever you want)”, then it says “iterate over that collection now called pinned and post the content of that post” (you can access other page variables things like .Title etc). Then once it’s done, it says "Go back and get every page that’s on the list for this page except the one that we just posted, and render the partial for that called “post-list” (you may have this setup differently).

1 Like

I always appreciate seeing more code that works. I am still all trial and error (and trying to remember to check versions functions are introduced before going down the rabbit hole. Either Hugo is releasing like crazy or our underlying Hugo version is looking long in the tooth).

This is really exciting stuff. OK, caveat, I’m not a UX guy AT ALL, but I’ve been perusing the Hugo documentation and it occurred to me that a lot of things could be done by the user if you could include a Front Matter section in your post(s). The question is, when you publish a post on Micro.blog, if your post included Front Matter, will that be appended to the Front Matter that is generated by Micro.blog at post time? Hopefully this makes sense. If that is the current behavior, that seems likely to open a lot of customization doors… (?)

1 Like

Accessing/setting custom front matter is not currently supported on Micro.blog.

1 Like

There is much we can get at (and @manton knows we want to get at the rest). @jsonbecker is spot on. We can; however, create front matter for our category pages or any fully custom pages. I am always tinkering and have made my repository public for any that might want to browse for ideas. The one thing to keep in mind while browsing the Hugo documentation is that we are currently constrained to version 0.54 (otherwise you’ll get excited about stuff like menu entry parameters only to find out you can’t use them>.<).

I appreciate the work that others have done on this. I don’t know much about Micro.blog plugins, but could this be turned into a plugin at some point, for those of us who don’t have the same tinkering proficiency?

I would love to be able to pin posts, as well. A plugin seems like a good idea.

I think for this to be a plug-in, any theme that would load that plug in would need to support defining block from the plug in on their index layout. Otherwise, I think the plug in would have to replace the index page itself, which might be possible, but I can imagine doing so in a way that would work with all themes would be quite hard.

Thanks Jason. I’m not super concerned about it. More of a nice to have. At this point, I’m mostly hoping to get more stability and reliability on the platform. It has gotten to a nice level of features.