diff --git a/docs/authoring/redirects.mdx b/docs/authoring/redirects.mdx index bdea39fd..9b8d40cc 100644 --- a/docs/authoring/redirects.mdx +++ b/docs/authoring/redirects.mdx @@ -29,7 +29,7 @@ When you change a published URL, update three things: the file at the new path, - Keep the stub file at the old path even after the content lives elsewhere. Deleting the stub removes the old URL entirely. + Keep the stub file at the old path even after the content lives elsewhere. Deleting the stub removes the old URL entirely — unless you forward it from the `redirects` map in `docs.json` (see [Forward deleted pages in bulk](#forward-deleted-pages-in-bulk)). ## Add a redirect stub @@ -64,6 +64,21 @@ Leave a minimal file at the **old** path and set `redirect` in frontmatter to th Do not rely on query strings or hash anchors in `redirect` values. They are not part of the redirect contract. +## Forward deleted pages in bulk + +Stubs work when you keep a file at the old path. When you **delete** pages outright — or need to forward many old URLs at once — add a centralized `redirects` map to `docs.json` instead of leaving a file behind for each one: + +```json title="docs.json" +"redirects": { + "/installation": "/getting-started", + "/old-api": "https://api.example.com/reference" +} +``` + +Keys are the old root-relative paths; values are internal paths or external `https://` URLs. docs.page consults this map **only when no file exists at the requested path**, so it is the tool for URLs whose files were removed. Keep frontmatter stubs for the case where a file still lives at the old path. + +See [`redirects`](/reference/docs-json#redirects) and [Redirects → The centralized redirects map](/features/redirects#the-centralized-redirects-map). + ## Verify the redirect After you add or change redirect stubs: diff --git a/docs/features/redirects.mdx b/docs/features/redirects.mdx index 046f5db7..42b32702 100644 --- a/docs/features/redirects.mdx +++ b/docs/features/redirects.mdx @@ -11,7 +11,7 @@ redirect: /getting-started --- ``` -docs.page returns a **307 Temporary Redirect** to the destination before any page body renders. Redirects are **per page file**, not a central table in `docs.json` — one old URL, one stub. +docs.page returns a **307 Temporary Redirect** to the destination before any page body renders. You can declare redirects two ways: a per-page `redirect` in frontmatter (above) for URLs whose file you keep, or a centralized `redirects` map in `docs.json` for old URLs whose files were removed. See [The centralized redirects map](#the-centralized-redirects-map). For step-by-step rename workflows, see [Redirects](/authoring/redirects). Field syntax and other frontmatter options live in [Page frontmatter](/reference/page-frontmatter). @@ -37,6 +37,23 @@ redirect: https://example.com/docs/new-location The file body can be empty. Only `redirect` is required for the HTTP redirect. Other frontmatter fields are ignored at request time. Do not rely on query strings or hash anchors in `redirect` values. They are not part of the redirect contract. +### The centralized redirects map + +A per-page stub covers one old URL each. When you **delete** a page and still want its old URL to forward somewhere, add an entry to the top-level `redirects` object in `docs.json` instead of leaving a file behind: + +```json title="docs.json" +"redirects": { + "/old-guide": "/guides/getting-started", + "/legacy-api": "https://api.example.com/reference" +} +``` + +Keys are old root-relative doc paths; values are the destinations. Keys and values are matched tolerant of leading and trailing slashes, and values follow the same internal/external rules as frontmatter `redirect`: root-relative paths resolve against the current routing mode and ref, while `http(s)://` and `//` URLs are returned unchanged. A match issues the same **307 Temporary Redirect**. + +The map is consulted **only on the 404 branch** — that is, only when no `.mdx` file exists at the requested path. If a file still lives at that path, docs.page renders it (or follows its own frontmatter `redirect`) and never looks at the config map. Use the map for old URLs whose files were removed; use a frontmatter stub when you keep a file at the old path. + +See [`redirects`](/reference/docs-json#redirects) in the docs.json reference. + ### How internal paths resolve across routing modes Internal redirects stay on the same site **mode** as the request. docs.page picks a base URL from the active route, appends the current ref segment when present, then appends your path. @@ -58,7 +75,7 @@ You do not hard-code `https://docs.page/owner/repo` in frontmatter for internal | Topic | Behavior | | --- | --- | -| Definition | Per-page `redirect` in frontmatter only; no wildcard or catch-all rules in `docs.json` | +| Definition | Per-page `redirect` frontmatter, or a centralized `redirects` map in `docs.json`; no wildcard or pattern matching — keys are exact paths (slash-tolerant) | | HTTP status | Temporary redirect (307), not permanent (308) | | Deleted files | Removing the stub removes the URL. Keep the old file to preserve the path | | Validation | [`docs check`](/features/cli#check-documentation) validates redirect targets the same way it validates in-page links | diff --git a/docs/reference/docs-json.mdx b/docs/reference/docs-json.mdx index 93705bdb..0242dfc5 100644 --- a/docs/reference/docs-json.mdx +++ b/docs/reference/docs-json.mdx @@ -20,6 +20,7 @@ Site configuration lives in `docs.json` or `docs.yaml` at the repository root. F | `logo`, `favicon`, `banner`, `theme` | [logo](#logo), [favicon](#favicon), [banner](#banner), [theme](#theme) | | `header`, `tabs`, `sidebar`, `anchors` | [header](#header), [tabs](#tabs), [sidebar](#sidebar), [anchors](#anchors) | | `content`, `seo`, `variables` | [content](#content), [seo](#seo), [variables](#variables) | +| `redirects` | [redirects](#redirects) | | `scripts`, `search`, `social`, `og` | [scripts](#scripts), [search](#search), [social](#social), [og](#og) | | `agent`, `mcp` | [agent](#agent), [mcp](#mcp) | @@ -323,6 +324,24 @@ See [Links](/features/links). Only **string** leaf values substitute. Intermediate objects are traversed; non-string leaves leave the placeholder unchanged. Variables do not apply inside frontmatter. See [Global variables](/features/global-variables). +## redirects + + + Centralized `{ "from": "to" }` map for forwarding old URLs whose page files were removed. Keys are old root-relative doc paths; values are the destinations. Keys and values are matched tolerant of leading and trailing slashes. + + ```json + "redirects": { + "/old-guide": "/guides/getting-started", + "installation/setup": "/getting-started", + "/legacy-api": "https://api.example.com/reference" + } + ``` + + Values may be internal root-relative paths (resolved against the current routing mode and ref, like frontmatter `redirect`) or external `http(s)://` / `//` URLs (returned unchanged). Each match issues a **307 Temporary Redirect**. + + This map is consulted **only when no `.mdx` file exists at the requested path** (a deleted or moved page). When a file is still present, its own frontmatter `redirect` governs instead. See [Redirects](/features/redirects). + + ## scripts Analytics and tag-manager injection on **published** pages only, not during local preview.