# Front matter and SEO

> Every front-matter parameter the theme reads, with its exact effect - display toggles, values, the discovery block and the feature image.

_Source: https://theme.docs.tbsch.de/post/2026-02-16-front-matter-and-seo/ · As of: 2026-03-01_


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**.

> [!important] 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.

> [!note] 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

```yaml
---
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):

```yaml
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:

```yaml
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.

```yaml
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`.

```yaml
params:
  featureimage: cover.webp         # image in the post bundle …
  # featureimage: https://…/og.png # … or an absolute URL
```

## The `discovery` block (crawling, indexing, search)

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

```yaml
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](/pages/privacy/)) combine `noindex` with
`search: false` + `llms: false` and `outputs: ["HTML"]`.

## Agent discovery (llms.txt v2)

Every page with a Markdown twin advertises it in `<head>` via
`<link rel="alternate" type="text/markdown" href="…/index.md">`, and every page
points at the `llms.txt` that covers it via `<link rel="describedby">` - the
discovery relations of the [llms.txt v2 proposal](https://llmstxt.org/). On a
multilingual site each language links its own file (`/de/llms.txt` for `/de/`).
Pages with `outputs: ["HTML"]` (the legal pages) have no Markdown twin, so they
get no `alternate` link.

## 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>/`:

```yaml
# 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.

> [!tip] 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](/me/) page.

```yaml
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`):

```yaml
# 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:

```yaml
aliases:
  - /old-url/
  - /l/shortlink
```

The full list of these keys lives in the
[Hugo front matter documentation](https://gohugo.io/content-management/front-matter/).

