route-manager-plugin
v1.0.12
Published
Plugin for managing routes and redirects.
Readme
Route Manager Plugin
A Strapi 5 plugin for managing URL routes, redirects, sitemaps, and public preview links in a multi-tenant environment. Automatically syncs routes when content entries are created, updated, or deleted.
Features
- Navigation Menu Builder — Visual tree editor for creating and managing navigation menus with drag-and-drop reordering and re-parenting
- Automatic Route Sync — Routes are auto-created/updated/deleted when content entries with a
uid(slug) field change - Collection Base Paths — Configure a base path per collection (e.g.,
/blogfor blog entries →/blog/my-post) - Redirect Management — Automatic 301 redirects on slug changes, with loop detection and prevention
- Public Preview — Shareable preview URLs with rotating cryptographic tokens (24h expiry)
- Sitemap Generation — XML sitemap with per-route priority, changefreq, and include/exclude controls
- Multi-Domain Support — Full integration with
@sensinum/strapi-plugin-multi-domainfor domain-scoped routes - Path Details Panel — Content Manager side panel showing path, full URL, and preview URL with copy buttons
- URL Picker Custom Field — Custom field type for selecting internal routes in content entries
Installation
The plugin lives in src/plugins/route-manager-plugin and is configured in config/plugins.ts:
// config/plugins.ts
export default () => ({
'route-manager-plugin': {
enabled: true,
resolve: './src/plugins/route-manager-plugin',
},
});Build the plugin:
cd src/plugins/route-manager-plugin
npx strapi-plugin buildConfiguration
Plugin Config Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| baseUrl | string | http://localhost:1337 | Base URL for full URL display and sitemap generation |
| siteName | string | '' | Site name displayed in admin UI |
| frontendBaseUrl | string | http://localhost:3000 | Frontend URL used for preview link construction |
| previewTokenCronInterval | string | 0 * * * * | Cron schedule for preview token rotation |
Environment Variables
# Used by the plugin's default config
FRONTEND_BASE_URL=https://yourdomain.com
# Used by the webhook system (in the Strapi app, not the plugin)
BFF_WEBHOOK_URL=http://localhost:8080/webhook/strapi-tenant
BFF_WEBHOOK_SECRET=your-webhook-secretMulti-Domain Integration
When used with the multi-domain plugin, baseUrl is resolved per-domain via an extension service override in the app's src/index.ts. The plugin does not need explicit baseUrl config — it's derived from the domain's customFields.url.
Architecture
Two Auth Systems
The plugin exposes routes on two separate APIs:
| API | URL Pattern | Auth | Consumer |
|-----|-------------|------|----------|
| Admin API | /route-manager-plugin/... | Admin JWT | Strapi admin panel |
| Content API | /api/route-manager-plugin/... | API Token | BFF / external services |
Admin JWT tokens cannot access content API routes and vice versa. The admin panel uses getFetchClient from @strapi/admin/strapi-admin which handles admin auth automatically.
Content Types
Navigation Menu (plugin::route-manager-plugin.navigation-menu)
| Field | Type | Description |
|-------|------|-------------|
| title | string | Menu display name |
| maxDepth | integer (1–5) | Maximum allowed nesting depth |
| placement | enum | standard, global_nav, or global_footer |
| logo | media (single) | Optional logo image |
| items | JSON | Nested tree of navigation items (structured JSON) |
Route (plugin::route-manager-plugin.route)
| Field | Type | Description |
|-------|------|-------------|
| path | string (required) | URL path (e.g., /blog/my-post) |
| contentType | string (required) | Strapi UID (e.g., api::page.page) or virtual |
| contentId | integer (required) | Entry ID (0 for virtual routes) |
| entryTitle | string | Display title for the route |
| isActive | boolean | Whether the route is live |
| isParentRoute | boolean | Whether this is a collection base route |
| applyToAllEntries | boolean | Collection-level base path marker |
| sitemapInclude | boolean | Include in sitemap generation |
| sitemapPriority | decimal | Sitemap priority (0.0–1.0) |
| sitemapChangefreq | string | Sitemap change frequency |
Redirect (plugin::route-manager-plugin.redirect)
| Field | Type | Description |
|-------|------|-------------|
| source | string | Source path (from) |
| destination | string | Destination path (to) |
| statusCode | integer | HTTP status code (301, 302) |
| isActive | boolean | Whether redirect is active |
Preview Token (plugin::route-manager-plugin.preview-token)
| Field | Type | Description |
|-------|------|-------------|
| token | string (unique) | 64-char base64url cryptographic token |
| expiresAt | datetime | Expiration timestamp |
API Reference
Content API (requires API token)
| Method | Path | Description |
|--------|------|-------------|
| GET | /api/route-manager-plugin/navigation-menus | All navigation menus (domain-scoped) |
| GET | /api/route-manager-plugin/navigation-menus/:documentId | Single menu with resolved images |
| GET | /api/route-manager-plugin/routes | All routes (domain-scoped) |
| GET | /api/route-manager-plugin/routes/root | Root-level routes only |
| GET | /api/route-manager-plugin/routes/children/:parentPath | Child routes of a path |
| GET | /api/route-manager-plugin/routes/tree | Full route tree structure |
| GET | /api/route-manager-plugin/routes/breadcrumbs/:path | Breadcrumb trail for a path |
| GET | /api/route-manager-plugin/routes/search | Search/paginate routes |
| GET | /api/route-manager-plugin/redirects | All redirects (domain-scoped) |
| GET | /api/route-manager-plugin/sitemap.xml | Generated XML sitemap |
Content API (public, no auth)
| Method | Path | Description |
|--------|------|-------------|
| GET | /api/route-manager-plugin/config | Plugin config (baseUrl, siteName) |
| GET | /api/route-manager-plugin/preview/token | Current valid preview token |
| GET | /api/route-manager-plugin/preview/validate?token=... | Validate a preview token |
| GET | /api/route-manager-plugin/preview/url?path=... | Full preview URL for a path |
Admin API (requires admin JWT)
Full CRUD for routes, redirects, collections, sitemap settings, and all utility endpoints (validate-path, generate-slug, bulk operations). See server/src/routes/admin/index.ts for the complete list.
Automatic Behaviors
Route Lifecycle
When a content entry with a uid-type field is:
- Created → A route is auto-created at
/{collection-base-path}/{slug}or/{slug}if no base path - Updated (slug change) → Route path is updated + a 301 redirect is created from old → new path
- Deleted → The route is removed
Redirect Loop Prevention
When a slug is changed back to a previous value (A → B → A), the plugin:
- Removes any existing redirect FROM the new destination (would cause a loop)
- Removes any existing redirect TO the old path (stale chain)
- Creates the new redirect
Slug Validation
A Koa middleware validates slugs on create/update/publish to prevent duplicate route paths. Returns a 400 error with a user-visible message if a conflict is detected.
Preview Token Rotation
A cron job (configurable via previewTokenCronInterval) generates new tokens and cleans up expired ones. Default: every hour.
Admin Panel Features
Path Details Panel
Injected into the Content Manager edit view via addEditViewSidePanel. Shows:
- Path — The route path with copy button
- Full URL — Domain + path with copy button
- Public Preview — Shareable preview URL (token auto-fetched from server)
- Edit Path — Link to the route manager plugin page
Plugin Page (Tabs)
- Menus — Create and manage navigation menus with a visual tree builder. Drag-and-drop reordering and re-parenting with depth enforcement.
- Routes — Search, filter, create, edit, delete routes. Bulk operations supported.
- Redirects — Manage redirect rules with source/destination/status code.
- Sitemap — Configure per-route sitemap settings (include, priority, changefreq). Preview/download XML.
Navigation Menu Builder
The Menus tab provides a full navigation management UI:
- Menu Settings — Title, max nesting depth (1–5), placement (Standard / Global Navigation / Global Footer), and optional logo upload
- Visual Tree Editor — Card-based tree with connector lines, inspired by strapi-plugin-navigation (VirtusLab)
- Side Panel Editing — Click the edit icon on any nav item to open the editing form in a right-side panel (label, URL, type, image)
- Drag-and-Drop — Reorder items within siblings or re-parent by dragging horizontally. Depth limits enforced.
- CTA Support — Click a nav item label to mark it as CTA (blue badge). Only one CTA per menu. Click the badge to remove.
- Media Picker — Upload images for nav items and logo directly to a dedicated "Navigation Menus" folder in the Media Library
- Placement Uniqueness — Only one menu per domain can be set as Global Navigation or Global Footer
- Multi-Domain Aware — Menus are scoped to the active domain via manual domain link insertion
- Bulk Delete — Checkbox selection with bulk delete for cleanup
URL Picker Custom Field
Register in your content types to let editors pick internal routes from a dropdown:
{
"type": "customField",
"customField": "plugin::route-manager-plugin.url-picker"
}Webhook Integration
The plugin fires database lifecycle hooks that the Strapi app's src/webhooks/bff-cache-invalidation.ts listens to. On route/redirect/page changes, a webhook is sent to the BFF for cache invalidation.
Tracked models: page, route, redirect
Webhook payload:
{
"event": "entry.create|entry.update|entry.delete",
"model": "page",
"tenantCode": "primax",
"entry": { "id": 14, "documentId": "abc123" }
}Development
# Build the plugin
cd src/plugins/route-manager-plugin
npx strapi-plugin build
# Watch for changes during development
npx strapi-plugin watch
# Type-check
npm run test:ts:front
npm run test:ts:backFile Structure
route-manager-plugin/
├── admin/src/
│ ├── components/ # UI components (NavigationTab, NavigationEditor, RoutesTab, etc.)
│ ├── hooks/ # usePluginConfig, useRoutes
│ ├── pages/ # HomePage (plugin main page)
│ └── utils/
│ ├── api.ts # Authenticated fetch helpers (getFetchClient)
│ ├── navTreeUtils.ts # Navigation tree manipulation (add, remove, move, reorder)
│ ├── flattenTree.ts # Tree flattening and DnD projection utilities
│ └── routeUtils.ts # Slug generation, validation, bulk ops
├── docs/
│ └── NAVIGATION-MENUS-API.md # BFF integration guide for navigation menus
├── server/src/
│ ├── bootstrap.ts # Lifecycle hooks registration, slug validation middleware
│ ├── config/index.ts # Default config and validation
│ ├── content-types/ # Route, Redirect, PreviewToken, NavigationMenu schemas
│ ├── controllers/ # Main controller + preview + navigation-menu controllers
│ ├── middlewares/ # Route lifecycle (auto-create/update/delete routes)
│ ├── routes/
│ │ ├── admin/ # Admin API routes (JWT auth)
│ │ └── content-api/ # Content API routes (token auth)
│ └── services/ # Preview service, navigation-menu service
└── package.json