Skip to content

Add pinned out-of-date banner and /latest/ canonicals for versioned docs - #437

Merged
miharp merged 3 commits into
OpenVoxProject:masterfrom
miharp:docs/outdated-version-banner
Aug 6, 2026
Merged

Add pinned out-of-date banner and /latest/ canonicals for versioned docs#437
miharp merged 3 commits into
OpenVoxProject:masterfrom
miharp:docs/outdated-version-banner

Conversation

@miharp

@miharp miharp commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Part of #320.

Addresses @binford2k's concern in #320 that bookmarks and search results will keep pointing at old versions once a product cuts a new major.

Pinned out-of-date banner

Every page of a frozen (non-latest) doc version now shows a notice pinned to the bottom of the viewport, linking to the product's /latest/ docs. Coverage is derived from _data/products.yml: nothing renders today (every numbered version is still its product's latest), but the moment a product gains a new version and its latest key moves, all pages of the older collections show the banner automatically — no per-page front matter. Like the version picker, the banners live outside the Turbo content frame and are re-synced on each frame load.

The banner links to the product's /latest/ root rather than the same page under /latest/, because we have no redirect mechanism and a same-page link would 404 whenever a page was renamed or removed in the newer version. Once the 404 page grows a "search for this page" affordance (tracked in #438), we can revisit a same-page link.

Update: the original version of this logic banner-ed any version that wasn't latest, which is wrong during a Phase 1 major-version cutover (see MAINTAINING.md) — a new version can sit ahead of latest in _data/products.yml as a beta preview, deliberately not yet promoted (this is exactly the shape #430's OpenVox 9 cutover takes). That preview version is not "no longer actively updated," so it must not get this banner. Fixed by tracking whether the loop has passed the latest entry in the (documented newest-first) versions list and only emitting the banner after that point.

Verified three ways:

  • A standalone Liquid render against synthetic 9x / 8x (latest) / 7x data: 9x and 8x render no banner, 7x renders one.
  • Live, merged locally against the real docs/openvox9-cutover branch (not part of this PR) via jekyll serve: no banner on /openvox/9.x/ or /openvox/8.x/.
  • A temporary synthetic older version confirmed the banner still renders correctly (and looks right) when a version genuinely is older than latest.

Screenshots below: OpenVox 9.x (preview, no banner), OpenVox 8.x (latest, no banner), and a synthetic older version (banner shown, for comparison).

1-openvox-9x-no-banner 2-openvox-8x-latest-no-banner 3-synthetic-older-version-banner-shown

CI check for products.yml consistency

The banner logic above (and the version selector) both depend on an unenforced convention: versions listed newest-first, and latest naming a real entry in that list. Nothing previously caught a violation of either — a misordered list or a typo'd latest would silently mis-derive every version's state. Added rake test:products_data, wired into the Rake Checks CI job, which validates: latest resolves to a real version id, version ids are unique, and ids sort newest-first (by leading version number). Verified it passes against both the current products.yml and the real docs/openvox9-cutover data, and correctly fails against injected bad-ordering, duplicate-id, and unknown-latest cases.

Canonical URLs for the numbered/latest duplicate pair

While latest points at a numbered version, that collection publishes byte-identical content under two URLs (e.g. /openvox/8.x/... and /openvox/latest/...). A small Jekyll hook (_plugins/canonical_latest.rb) now sets page.canonical_url on the numbered copy pointing at its /latest/ twin; the theme's head.html already honors that key, so search engines index the stable /latest/ URLs instead of splitting ranking across the pair. Frozen versions keep their default self-canonical, since their content is unique once latest moves on.

Note for #401: jekyll-seo-tag also honors page.canonical_url, so this composes with the SEO-tags work rather than conflicting with it.

Two follow-ups to the multi-version infrastructure, part of OpenVoxProject#320:

Banner: every page of a frozen (non-latest) doc version gets a notice
pinned to the bottom of the viewport linking to the product's /latest/
docs. Coverage is derived from _data/products.yml, so nothing renders
today; the moment a product gains a new version and its 'latest' key
moves, all pages of the older collections show the banner automatically.
Like the version picker, the banners persist outside the Turbo content
frame and are re-synced on each frame load.

Canonicals: a small Jekyll hook points each numbered-latest page (e.g.
/openvox/8.x/...) at its byte-identical /latest/ twin via
page.canonical_url, which the theme's head.html already honors, so
search engines index the stable /latest/ URLs instead of splitting
ranking across the duplicate pair. Frozen versions keep their default
self-canonical since their content is unique once 'latest' moves on.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Michael Harp <mike@mikeharp.com>
@miharp
miharp requested a review from a team as a code owner August 4, 2026 11:51
@miharp
miharp marked this pull request as draft August 4, 2026 12:54
The banner previously fired for any version that wasn't `latest`,
which is wrong during a Phase 1 major-version cutover (MAINTAINING.md):
a new version can sit ahead of `latest` in the versions list (newest
first) as a beta preview, deliberately not yet promoted. That version
is not "no longer actively updated" — it's the opposite.

Track whether the loop has passed the `latest` entry and only emit the
banner for versions after it, matching the documented newest-first
ordering in _data/products.yml.

Verified: a Liquid-only render against synthetic 9x/8x(latest)/7x data
confirmed 9x renders no banner, 8x renders no banner, 7x renders a
visible one. Also verified live against a merged-in OpenVox 9 cutover
branch (docs/openvox9-cutover) via jekyll serve + Playwright
screenshots: no banner on /openvox/9.x/ or /openvox/8.x/, and a
temporary synthetic older version confirmed the banner still renders
correctly when it should.

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Michael Harp <mike@mikeharp.com>
@miharp
miharp marked this pull request as ready for review August 4, 2026 13:14
@miharp
miharp marked this pull request as draft August 4, 2026 14:06
version-banner.html's out-of-date logic (and the version selector)
both rely on an unenforced convention: `versions` listed newest-first,
`latest` naming a real entry. Nothing caught a violation before this
would silently mis-derive version state. Add rake test:products_data,
checking latest resolves, ids are unique, and ids sort newest-first
(by leading version-id number), and wire it into the Rake Checks CI
job alongside rubocop.

Verified locally: passes on current products.yml and on the real
OpenVox 9 cutover branch's data (docs/openvox9-cutover), and correctly
fails on injected bad-ordering, duplicate-id, and unknown-latest cases.

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Michael Harp <mike@mikeharp.com>
@miharp
miharp force-pushed the docs/outdated-version-banner branch from 088b741 to 0918ade Compare August 4, 2026 14:07
@miharp
miharp marked this pull request as ready for review August 4, 2026 14:11
@binford2k

Copy link
Copy Markdown
Contributor

I suspect that you started by looking for an existing plugin for the CanonicalLatest functionality, but just wanted to double check.

@miharp

miharp commented Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

Off-the-shelf canonical plugins only emit self-referential URLs or pass through front matter; the part that needed code is computing the numbered-to-/latest/ mapping from _data/products.yml and the symlink layout, which is specific to this repo's version model. That mapping is all the hook does.

@miharp
miharp merged commit 4da4662 into OpenVoxProject:master Aug 6, 2026
5 checks passed
@miharp
miharp deleted the docs/outdated-version-banner branch August 6, 2026 10:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants