Private pages

Is there a way to have a category or page private?

I made a category for #birds in my blog, where I wish to collect birding pictures that I find and like, for example from mastodon. But I don’t necessarily have permission to publicly share these pictures nor I want to share them publicly. I want to collect them, make a post with a few notes about the bird (scientific name and wikipedia page, for example) and keep them for myself.

Could I have a category private or make a private page with a particular category?

Thanks in advance.

You should be able to use the Feeds page (https://micro.blog/account/feeds) to achieve this. If all of your posts are in distinct categories, and you have a birding category, you can remove you default feed and add each individual category feed, but not the birding category feed. But you would need to make sure all posts were assigned a category, and also I assume it would double post if you had two categories assigned to a post, etc.

Working out what your feeds are called is explained elsewhere in help.

This does not make the posts truly private, but there would be no public links to the posts - you could bookmark the category list page for personal access.

Thanks a lot, I will try this. I do have two distinct categories with their own feed that I use to cross-post to different social networks (linkedin or mastodon) but I never thought about deleting the general feed. I don’t know if that will prevent the bird category posts from showing up in my blog’s home page, though. I will report back. Thanks!

To exclude a category from your homepage, you’ll want to look here:

Thank you, Jason. I tried, I really did. I was not able to make a layouts/index.html file without errors, though :smiling_face_with_tear:

If you paste your index in here and tell me what categories you want to exclude, I can probably write something that will work.

This is going to be quite embarrassing, Jason, please have mercy :)) This is all I was able to copy/paste.

The categories I’d like to exclude are blog-legal, blog-personal, birds. Actually, these are the three categories that have their own pages, and in the home page I’d only want to show posts without a category.

{{ define "main" }}
    {{ $posts := where site.Pages "Type" "post" }}
    {{ $hidden_posts := where $posts "Params.categories" "intersect" (slice "blog-legal" "blog-personal" "birds") }}
    {{ $posts = $posts | symdiff $hidden_posts }}
    {{ $grouped := $posts.GroupByDate "2006-01-02" }}
    {{ $paginated := (.Paginate ($grouped)) }}
    <main class="content" role="main">
      {{ range $paginated.PageGroups }}
      {{ $thedate := (time .Key) }}
      <h3 class="post-group"> {{ $thedate. Format "January 2, 2006" }}</h3>
      {{range .Pages.Reverse }}
      {{ if eq .Type "post" }}
        {{.Render "article" }}
    {{- end }}
  {{ end }}
{{ end }}
</div>
{{ partial "pagination.html" . }}
{{ end }}

I think the only problem here is that you should do:

{{ $posts := $posts | symdiff $hidden_posts }}

(note the added :)

I might be wrong. I’d try using {{ $filtered := $posts | symdiff $hidden_posts }} just in case. In Hugo, I’m somewhat paranoid about reusing variable names.

Something wrong. I tried both $filtered and $posts and they both gave the same error:

Error: Error building site: failed to render pages: render of “home” failed: “/umerez_ac0900/layouts/index.html:18:3”: execute of template failed: template: index.html:18:3: executing “main” at <partial “pagination.html” .>: error calling partial: partial “pagination.html” not found

Well that just says that your theme doesn’t have pagination. So you can go ahead and remove that line for

{{ partial "pagination.html" . }}

It’s pretty unusual for a theme not to have a pagination partial-- which one are you using?

I use Paper Theme. And something went wrong haha look at my homepage now: https://umerez.eu

I give up for today, I’m going to bed. Tomorrow, I will most probably just delete the layouts/index.html template and move on.

What I would really like is have a homepage with a small text introduction about myself and then a list of posts without any category. That should be easy with a bit of HTML knowledge, but I will need some time for that.

Thanks for your help, Jason, a lot. Good night.

If by Paper you mean @amit’s theme, then you don’t have an index.html by default (which is somewhat unusual, but certainly supported).

I would delete the index layout, then go to /layouts/_default/list.html has linked to above, then go to line’s 4-6 and delete them. Replace them with:

{{ $posts := where site.Pages "Type" "post" }}
{{ $hidden_posts := where $posts "Params.categories" "intersect" (slice "blog-legal" "blog-personal" "birds") }}
{{ $posts = $posts | symdiff $hidden_posts }}

and you should be good to go. FWIW, if you look at lines 31-41, that’s essentially the code that most themes place in a pagination partial. Nothing wrong with inlining though.

Yes, it is the theme by @amit that you linked, in my plug-ins it’s called Paper Theme.

I did as you suggested, I deleted the index.html template and edited the /layouts/_default/list.html template. I have a new error:

Error: Error building site: “/umerez_34baa2/layouts/_default/list.html:9:1”: parse failed: template: _default/list.html:9: undefined variable “$pages”

This is the content of my edited /layouts/_default/list.html

{{ define "main" }}

<!-- $pages -->
{{ $posts := where site.Pages "Type" "post" }}
{{ $hidden_posts := where $posts "Params.categories" "intersect" (slice "blog-legal" "blog-personal" "birds") }}
{{ $posts = $posts | symdiff $hidden_posts }}

<!-- Articles -->
{{ $paginator := .Paginate $pages }} {{ range $index, $page := $paginator.Pages }}
  {{ if .Site.Params.full_content_on_homepage }}
    <article class="post-entry-content">
      {{ if .Title }}
        <h2>{{ .Title }}</h2>
      {{ end }}
      <time><a href="{{ .Permalink }}">{{ .Date.Format "2006-01-02" }} </a></time>
      <p class="post-meta"><time class="dt-published">{{ if gt .ReadingTime 1 }} Tiempo de lectura: {{ .ReadingTime }} minutos{{ end }}</time></p>
      <section class="post-content">{{ .Content }}</section>
    </article>
    <hr class="post-separator">
  {{ else }}
    <article class="post-entry">
      {{ if .Title }}
        <h2>{{ .Title }}</h2>
      {{ end }}
      <time>{{ .Date.Format "2006-01-02" }}</time>
      <p class="post-meta"><time class="dt-published">{{ if gt .ReadingTime 1 }} Tiempo de lectura: {{ .ReadingTime }} minutos{{ end }}</time></p>
      <p>{{ .Summary | truncate 300 }}</p>
      <a href="{{ .Permalink }}"></a>
    </article>
  {{ end }}
{{ end }}

<!-- Main Nav -->
{{ if gt $paginator.TotalPages 1 }}
<nav class="main-nav">
  {{ if $paginator.HasPrev }}
  <a class="prev" href="{{ $paginator.Prev.URL }}">← Prev Page</a>
  {{ end }}<!---->
  {{ if $paginator.HasNext }}
  <a class="next" href="{{ $paginator.Next.URL }}">Next Page →</a>
  {{ end }}
</nav>
{{ end }}<!---->

{{ end }}

Let’s read the error message:

Error: Error building site: “/umerez_34baa2/layouts/_default/list.html:9:1”: parse failed: template: _default/list.html:9: undefined variable “$pages”

That says on line 9 there’s a variable $pages that you didn’t set. We can see in the original link that Amit’s theme uses $pages instead of $posts. I also failed to correct when copy and pasting the missing : I pointed out before. So on this line:

{{ $posts = $posts | symdiff $hidden_posts }}

Make it:

{{ $posts := $posts | symdiff $hidden_posts }}

And on line 9, rather than using $pages switch it to $posts.

{{ $paginator := .Paginate $pages }}

Should be

{{ $paginator := .Paginate $posts }}

Finally, no errors. Finally, no category-posts in my home page. And then… neither in my category pages!

All my category pages are showing the same posts as the home page. So, in my legal, personal and birds pages, none of their respective category-posts show up and there’s only non-category posts.

I feel like I’m taking too much of your time, Jason, but I would really appreciate one last help from you. How can I override the “main” page setting for the rest of the pages?

This is the last code I’m using, after the last corrections. Please note than I had to write the categories with a space, not a hyphen (“blog legal” and “blog personal”, instead of “blog-legal” and “blog-personal”), just like I have them in the Categories section.

Each of my category-pages have the URL for their own category, just like before, nothing changed there. But, for some reason, they all show the same view now, only non-category posts.

Again, thank you, Jason.

{{ define "main" }}

<!-- $pages -->
{{ $posts := where site.Pages "Type" "post" }}
{{ $hidden_posts := where $posts "Params.categories" "intersect" (slice "blog legal" "blog personal" "birds") }}
{{ $posts := $posts | symdiff $hidden_posts }}

<!-- Articles -->
{{ $paginator := .Paginate $posts }} {{ range $index, $page := $paginator.Pages }}
  {{ if .Site.Params.full_content_on_homepage }}
    <article class="post-entry-content">
      {{ if .Title }}
        <h2>{{ .Title }}</h2>
      {{ end }}
      <time><a href="{{ .Permalink }}">{{ .Date.Format "2006-01-02" }} </a></time>
      <p class="post-meta"><time class="dt-published">{{ if gt .ReadingTime 1 }} Tiempo de lectura: {{ .ReadingTime }} minutos{{ end }}</time></p>
      <section class="post-content">{{ .Content }}</section>
    </article>
    <hr class="post-separator">
  {{ else }}
    <article class="post-entry">
      {{ if .Title }}
        <h2>{{ .Title }}</h2>
      {{ end }}
      <time>{{ .Date.Format "2006-01-02" }}</time>
      <p class="post-meta"><time class="dt-published">{{ if gt .ReadingTime 1 }} Tiempo de lectura: {{ .ReadingTime }} minutos{{ end }}</time></p>
      <p>{{ .Summary | truncate 300 }}</p>
      <a href="{{ .Permalink }}"></a>
    </article>
  {{ end }}
{{ end }}

<!-- Main Nav -->
{{ if gt $paginator.TotalPages 1 }}
<nav class="main-nav">
  {{ if $paginator.HasPrev }}
  <a class="prev" href="{{ $paginator.Prev.URL }}">← Prev Page</a>
  {{ end }}<!---->
  {{ if $paginator.HasNext }}
  <a class="next" href="{{ $paginator.Next.URL }}">Next Page →</a>
  {{ end }}
</nav>
{{ end }}<!---->

{{ end }}

OK. Never mind, It’s fixed now!

Don’t kill me. I was doing all these changes in the layouts/_default/list.html template. I had saved a backup but fortunately the theme itself maintains the original template. So I deleted the one I had edited and created a new layouts/index.html. Now it works as expected. The home page shows non-category posts and each category-page shows its proper category posts.

It sometimes feels a bit slower, but it works well enough. Thanks again, Jason, I really appreciate your help.

Keeping open secrets on the web can be quite a challenge. Humans and robots can figure out where pages reside on your blog in lots of different ways, for example via the:

  • homepage
  • archive page
  • categories page
  • RSS and JSON feeds
  • sitemap.xml
  • and also by making educated guesses (if this site has a search page, maybe it’s located at /search/ or /search.html?)

If you want to do everything you can to hide a public page, you must make sure there’s no link to it anywhere. It’s not enough just to change the homepage template. Also, you would want to publish your secret pages on URLs that are hard for humans and robots to guess. (Think /4bde80e6-9988-4230-8acc-e6bbee2e1419.html rather than /search.html.)

And in the end, there’s never a 100 % guarantee that nobody will find the page. So, it’s not a great solution for publishing stuff that really needs to be kept secret.

You are right, @sod. And I did abandon the idea of keeping private pages. This thread finally turned up being about building a custom home page.