Skip to content
tbsch Theme
Basics

Front matter and SEO

The theme reads a whole set of its own front-matter parameters. Almost every one has a global default in params.yaml and can be overridden per page (or per section via cascade). The resolution order is: front matter → global default → theme fallback.

Theme parameters go in the params: block

Everything the theme evaluates goes into the params: block - keeping it clear what comes from Hugo and what from the theme. Every example here does exactly that.

Some toggles are flipped on this page on purpose

This post sets showReadingTime: false and showWordCount: false (so both are hidden in the hero, though they show on every other post) and showLikes: true (so the like button appears at the end - it is off by default).

Front-matter layout #

---
title: "My post"             # read by Hugo
date: 2026-02-16
draft: false
description: "…"
categories: ["Features"]     # taxonomies
tags: ["hugo"]

params:                      # everything theme-specific in this block
  showReadingTime: false
  featureimage: cover.webp
  discovery:
    noindex: true
---

Display toggles #

Boolean toggles - the value shown is the default; set the parameter in your params: block to override it (an explicit false always wins):

params:
  showDate: true            # default: on   publication date in the hero
  showDateUpdated: true     # default: on   "Updated" date from lastmod in the hero
  showReadingTime: true     # default: on   reading time in the meta row
  showWordCount: true       # default: on   word count in the meta row
  showTaxonomies: true      # default: on   tags & categories in the hero
  showTableOfContents: true # default: on   floating table of contents (on the left)
  showHeadingAnchors: true  # default: on   direct-link anchor on every heading
  showAuthor: true          # default: on   author box at the end
  showLikes: false          # default: off  like button (heart) at the end - opt-in
  showSharingLinks: true    # default: on   sharing bar
  showComments: true        # default: on   reactions/comments at the end
  showPagination: true      # default: on   prev/next within the section
  showRelatedContent: true  # default: on   "Related posts" below the article
  showDraftLabel: true      # default: on   "Draft" badge while draft: true
  seriesOpened: true        # default: on   series box starts expanded

Value parameters #

Parameters that take a value rather than a toggle:

params:
  # Show only these networks in the sharing bar (keys from data/sharing.yaml);
  # overrides the global set from params.yaml.
  sharingLinks: ["bluesky", "mastodon", "email"]

  # Number of "Related posts" (default 3) when showRelatedContent is on.
  relatedContentLimit: 5

  # Author name for this page's structured data (Person/JSON-LD) ONLY;
  # overrides the default author from params.yaml.
  author: "Guest author"

Social tags for cross-posting (socialTags) #

socialTags is not a flat list but a block with hashtags and mentions (per network). It is not rendered on the page; it is written into the JSON Feed under a _social extension - from there a cross-posting service picks it up and appends the hashtags and @-mentions when auto-posting to Mastodon or Bluesky.

params:
  socialTags:
    hashtags:
      - SelfHosted
      - DNS
      - PiHole
    mentions:
      mastodon: ["selfhosted@lemmy.world"]
      bluesky: ["mariushosting.com"]

Feature image (featureimage) #

The theme resolves the hero/feature image in this order:

  1. params.featureimage (local path or absolute URL),
  2. an image named *background*/*feature*/*cover*/*thumbnail* in the bundle,
  3. the site’s defaultBackgroundImage from params.yaml.
params:
  featureimage: cover.webp         # image in the post bundle …
  # featureimage: https://…/og.png # … or an absolute URL

For SEO the theme brings its own discovery: block - Hugo has no equivalent. All toggles have a sensible default; you only set the deviation:

params:
  discovery:
    noindex: true   # default false → <meta name="robots" content="noindex">
    nofollow: true  # default false → appends nofollow
    sitemap: false  # default true  → drop the page from sitemap.xml
    search: false   # default true  → drop the page from the Pagefind search
    llms: false     # default true  → drop the page from llms.txt

partials/seo-robots.html is the single source of the robots directive (front matter → 404 → default index, follow); it emits only the opt-out tokens (noindex/nofollow), never the implicit index, follow. The sitemap is coupled to it: any noindex page drops out of the sitemap automatically.

The thin tag term pages set exactly that via a cascade in content/tags/_index.md; the legal pages (see Privacy) combine noindex with search: false + llms: false and outputs: ["HTML"].

Curated tag hubs (linkTitle + discovery) #

A tag term page is thin and noindex by default (the cascade above). To turn a tag into an indexable evergreen hub - a curated landing page that owns the head term while its individual posts keep their long-tails - give the tag its own _index.md under content/tags/<tag>/:

# content/tags/seo/_index.md
---
title: "Search engine optimization"  # page <h1> + SEO title
linkTitle: "seo"                      # short label shown in the tag chips
description: "…"                      # hero lede + meta description
discovery:
  noindex: false                     # opt back in, overriding the thin-tag cascade
  sitemap: true
---

Intro paragraph(s), rendered above the list of tagged posts.

The page’s own discovery overrides the kind: term cascade from content/tags/_index.md, so this one term goes index, follow and returns to the sitemap; the body renders as an intro above the posts.

title vs. linkTitle

The tag chips (the #tag pills in a post hero and in the /tags/ cloud) render .LinkTitle, while the hub page renders .Title as its <h1>. So a descriptive title: "Search engine optimization" can head the page while linkTitle: "seo" keeps every chip a tidy #seo - without linkTitle the full title would leak into each chip. (Chips are lower-cased in CSS, so linkTitle only needs to be the short form, not the exact casing.)

Author profile (authorProfile) #

On an “About me” page, authorProfile: true emits ProfilePage and Person JSON-LD (with sameAs links from params.author.links) - see the About me page.

params:
  authorProfile: true

Category icon (categoryIcon) #

In a category’s _index.md (content/categories/<name>/), categoryIcon sets the Tabler icon shown on the category card (default tag):

# content/categories/features/_index.md
params:
  categoryIcon: rocket

Hugo’s own keys #

Hugo reads these itself, not the theme:

  • title, date, lastmod, draft - title and dates. lastmod is shown as the “Updated” date (when showDateUpdated is on).
  • description, summary - meta description and lede/teaser.
  • categories, tags, series - the theme’s three taxonomies.
  • translationKey - links the language variants of a post.
  • slug, url - URL control. outputs - output formats (e.g. HTML only).
  • aliases - client-side redirect stubs (automatically noindex), handy for old or short URLs:
aliases:
  - /old-url/
  - /l/shortlink

The full list of these keys lives in the Hugo front matter documentation.

Did you enjoy this post?

Join the conversation

Reactions

 1k+ views ·  42 likes ·  5 shares

Read more

Related posts