Skip to content

fix: make per-type page switches consistent - #2106

Merged
markdumay merged 8 commits into
mainfrom
fix/switch-placement
Aug 1, 2026
Merged

fix: make per-type page switches consistent#2106
markdumay merged 8 commits into
mainfrom
fix/switch-placement

Conversation

@markdumay

Copy link
Copy Markdown
Collaborator

Three defects that share one shape: a switch is honored in one place and ignored in another.

1. readingTime and wordCount had no per-type cascade

site.Params.pages has three consumers. Two cascaded per content type; the third did not.

Consumer Param Per-page Per-type
utilities/GetMetadata.html metadata yes yes
utilities/GetIncludeTOC.html includeToc yes* yes
page/metadata.html readingTime, wordCount no no

So "reading time on blog, off elsewhere" was inexpressible. The neighbouring metadata
param cascades but is all-or-nothing — none drops the date and word count too.

A new utilities/GetPageFlag.html resolves a bool through page front matter, then per-type,
then global, then the caller's default. Both params gain per-page overrides as well.

* see 3 — that "yes" was not true either.

2. metadata = "original" was accepted and documented but inert

GetMetadata.html validated original as a supported value and the documentation stated it
omits the modification date. Nothing read it, so full and original rendered identically.
Now implemented as documented.

3. The includeToc cascade was broken in both directions

GetIncludeTOC.html tested isset .Params "includeToc" in mixed case. Hugo lowercases
front-matter keys to includetoc, and isset is case-sensitive — unlike index and
field access, which go through maps.Params.Get. So the per-page branch was never taken.

Meanwhile the mobile TOC dropdown re-derived the value inline in header.html and
docs/header.html, consulting the page parameter but never the per-type value.

per-page per-type
Sidebar TOC ignored honored
Mobile dropdown honored ignored

Neither path honored both. Both now resolve through GetIncludeToc.html.

Fixing the dead branch exposed a second bug behind it: the per-page tier had no bool type
check, harmless while it was unreachable. Hugo parses YAML as 1.2, so includeToc: no is a
string, and every consumer tests truthiness. It is now type-checked like its per-type
sibling.

Upgrade notes

  1. Front-matter includeToc now works. Pages setting includeToc: false that still
    showed a sidebar TOC will lose it; pages setting includeToc: true under a per-type
    includeToc = false will gain one. Rendering changes in both directions — the
    largest visible delta in this release.
  2. The mobile dropdown honors the full cascade. Its condition is strictly narrower than
    before, so it can only disappear, never newly appear.
  3. navigation.toc must be present. A site that deleted the key rather than setting it
    to false previously still got the dropdown; it no longer does. Set it explicitly.
  4. readingTime and wordCount cascade per page and per type, matching metadata and
    includeToc. Sites setting them globally are unaffected; a stray readingTime in front
    matter will take effect for the first time.
  5. Mistyped values now fail the build. readingTime, wordCount and includeToc must
    be booleans wherever they are set. Note YAML 1.2 parses yes/no as strings — use
    true/false.
  6. metadata = "original" behaves as documented, showing the publication date instead
    of the modification date. Pages using it rendered identically to full before.

Tests

Extends the template harness added in #2104: 35 assertions, including one per cascade tier
for both resolvers. Each was verified to discriminate by deleting the tier it covers and
confirming only that assertion fails.

markdumay and others added 7 commits August 1, 2026 17:51
The original steps built a second scratch site with symlinks. Symlinks do
not work on Hugo's layouts mount, and the harness is now committed, so
GetPageFlag's assertions belong beside TitleCase's. Also records why this
branch is cut from PR 1 rather than main, and that it must be rebased
before opening: workflows filter on base main/beta, so a stacked PR gets no
CI and retargeting does not revive it.
Both were read only from the global site parameter, while the neighbouring
metadata and includeToc parameters already cascaded per type. They now
resolve through page frontmatter, then per-type, then global, so reading
time can be kept for one content type and dropped for another.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Row 2 of the GetPageFlag assertions passed default=true against a want of
true, coinciding with the fixture's configured global wordCount value. A
resolver with the global-tier lookup deleted entirely still returned true
for that call, so the assertion proved nothing about that tier. Switching
its default to false forces a pass to depend on the resolver actually
reading site.Params.pages.wordCount.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
GetIncludeTOC.html tests isset with a mixed-case key; Hugo lowercases front
matter and isset is case-sensitive, so per-page includeToc has never worked.
The two TOC paths are broken in opposite directions and the original task
would have regressed the half that still worked, with every verification
step passing.
GetMetadata.html accepted "original" as a valid value and the docs
described it as suppressing the modification date, but nothing read it.
It rendered identically to "full".

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…opdown

GetIncludeTOC.html tested `isset .Params "includeToc"` in mixed case.
Hugo lowercases front-matter keys and isset is case-sensitive, so the
per-page branch was never taken and front-matter includeToc was silently
ignored by the sidebar table of contents.

The mobile dropdown had the mirror-image defect: it read the page
parameter directly and never consulted the per-type value. Setting
pages.<Type>.includeToc = false hid the sidebar TOC while leaving the
dropdown visible. Both paths now resolve through GetIncludeToc.html, which
honors the global toggle, the per-page parameter, and the per-type value.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…g errors correctly

The per-page includeToc tier went live for the first time in this branch (Hugo
lowercases front-matter keys, and the isset check was fixed to match), but it had
no type check, unlike the per-type tier right below it. YAML 1.2 parses `no`/`yes`
as strings, so `includeToc: no` propagated a truthy string past every consumer's
truthiness check and rendered a TOC that should have been suppressed. Mirror the
existing per-type check into the per-page branch, following the page-scoped
wording precedent in GetSidebarIcons.html.

GetPageFlag.html blamed every bad-type error on the page, even when the bad value
came from the global or per-type site config. Track which tier supplied the value
alongside each assignment and name that tier in the error, using the caller's
original key spelling instead of the lowercased lookup form.

Also fix the test fixture that set includeToc's per-type override with an
all-lowercase key: this branch is about key-casing bugs, so the fixture should use
the camelCase spelling a real author writes, proving normalisation instead of
avoiding it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@netlify

netlify Bot commented Aug 1, 2026

Copy link
Copy Markdown

Deploy Preview for gethinode-demo ready!

Name Link
🔨 Latest commit cd3e783
🔍 Latest deploy log https://app.netlify.com/projects/gethinode-demo/deploys/6a6e3359db2e2a0008a73576
😎 Deploy Preview https://deploy-preview-2106--gethinode-demo.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@markdumay
markdumay enabled auto-merge August 1, 2026 17:56
@markdumay
markdumay merged commit eb4f7ae into main Aug 1, 2026
17 checks passed
@markdumay

Copy link
Copy Markdown
Collaborator Author

🎉 This PR is included in version 3.15.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant