content_routes is a public registry path for articles, pages, and theme content. The registry separates old post/slug identities from public URLs that can change without losing redirect history.
Canonical and aka
For each post-locale pair only one row has is_canonical=1 And canonical_slot=1. When canonical is replaced, the old canonical is demoted to an alias. The alias resolver returns a canonical target so the router can provide a permanent redirect and maintain the query string safely.
Global namespace
Path is normalized lowercase ASCII without leading/ending slashes. Segments can be nested, for example docs/core/routing. Unique applies per locale. The validator also rejects collisions with content slugs/routes, old permalinks, Core prefixes, auth/list/category paths, plugin routes, archive years, and public files/directories. Because the default URL uses an empty locale, all content types share that global namespace.
Fallback
Old content that does not yet have a canonical route can still be resolved via legacy permalinks and slugs. Fallback is not a saved alias: after the route is created, use the registry as the canonical URL source. Theme content menu selects the canonical route; Canonical sitemaps also depend on the registry.
Locale and translation plugin
Core stores the locale column and can generate URLs /{locale}/{path}/, but Core does not provide a native translation editor. The translation plugin is responsible for versioning content, determining locales, synchronizing canonical/aliases, handling cross-locale redirects, and adding locale sitemaps. Plugins must use helper routes so that collisions, transactions, and canonical history remain consistent.
Before changing the path, check the plugin's internal links and routes, save the new canonical atomically, then test the new URL, old alias, query string, 404, menu, canonical tag, and sitemap.