[PR #5826] [CLOSED] feat(middleware): Page 404 to 301 | add redirect for old page slugs, caused by title change #6579

Closed
opened 2026-02-05 10:36:00 +03:00 by OVERLORD · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/BookStackApp/BookStack/pull/5826
Author: @oopen
Created: 10/8/2025
Status: Closed

Base: developmentHead: development


📝 Commits (2)

📊 Changes

2 files changed (+42 additions, -0 deletions)

View changed files

📝 app/Http/Kernel.php (+1 -0)
app/Http/Middleware/RedirectOldPageSlugs.php (+41 -0)

📄 Description

📝 Description

This PR introduces a new Laravel middleware, RedirectOldPageSlugs, that automatically redirects requests containing obsolete page slugs to the page’s stable permalink (/link/{id}), which then redirects to the current canonical URL.

🔍 Problem

When a user changes a page’s slug in BookStack:

  • The old URL becomes a 404.
  • BookStack does not store historical slugs for books or chapters (only pages have revisions via page_revisions).
  • External links, bookmarks, or search engine results pointing to the old URL break permanently.

This creates a poor user experience and harms SEO.

Solution

The new middleware:

  • Runs early in the web middleware stack (after TrustProxies, before PageViewCounter).
  • Extracts the last path segment from the request (e.g., /book/foo/barbar).
  • Checks if this segment exists as a non-current slug in page_revisions.
  • If found, issues a 301 redirect to /link/{page_id} — BookStack’s built-in, stable permalink route.
  • Skips API, asset, debug, and system routes to avoid interference.

This approach is:

  • 100% reliable for pages (uses real revision data).
  • Independent of book/chapter slug history (which BookStack doesn’t store).
  • Zero-config and fully automatic.
  • Safe: only redirects when an exact match is found in revisions.

🧪 Testing

  1. Create a page → note its slug.
  2. Edit the page and change its slug.
  3. Visit any URL ending with the old slug (e.g., /any/book/or/chapter/path/old-slug).
  4. Observe a 301 redirect to /link/{id}, then to the current page.

Note: The middleware matches any path ending with the old slug, because BookStack’s routing is dynamic and doesn’t enforce strict path structures. This ensures maximum compatibility.

📁 Files Changed

  • app/Http/Middleware/RedirectOldPageSlugs.php → new middleware
  • app/Http/Kernel.php → register middleware in web group

⚙️ Middleware Placement

Inserted after TrustProxies and before PageViewCounter to:

  • Avoid counting redirected requests as page views.
  • Ensure trusted proxy headers are processed first.

💡 Why /link/{id} and not the canonical URL?

  • /link/{id} is BookStack’s official, stable permalink mechanism.
  • It already handles final redirection to the current URL (including updated book/chapter slugs).
  • This avoids duplicating routing logic and ensures consistency.

Benefits

  • Restores broken links automatically.
  • Improves SEO by preserving link equity via 301s.
  • Requires no user intervention or configuration.
  • Minimal performance impact (indexed DB lookup on page_revisions.slug).

🙏 Final Note

This feature aligns with BookStack’s philosophy of usability and data integrity, and leverages existing systems (page_revisions, /link/{id}) without introducing redundancy.

Thank you for considering this contribution!


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/BookStackApp/BookStack/pull/5826 **Author:** [@oopen](https://github.com/oopen) **Created:** 10/8/2025 **Status:** ❌ Closed **Base:** `development` ← **Head:** `development` --- ### 📝 Commits (2) - [`819ed7e`](https://github.com/BookStackApp/BookStack/commit/819ed7e945cd20ee5d53700199677fdc25a06397) Update Kernel.php - [`380b5e0`](https://github.com/BookStackApp/BookStack/commit/380b5e0aed143ade342a204313151dd895fd322c) Create RedirectOldPageSlugs.php ### 📊 Changes **2 files changed** (+42 additions, -0 deletions) <details> <summary>View changed files</summary> 📝 `app/Http/Kernel.php` (+1 -0) ➕ `app/Http/Middleware/RedirectOldPageSlugs.php` (+41 -0) </details> ### 📄 Description ### 📝 Description This PR introduces a new Laravel middleware, `RedirectOldPageSlugs`, that automatically redirects requests containing **obsolete page slugs** to the page’s stable permalink (`/link/{id}`), which then redirects to the current canonical URL. #### 🔍 Problem When a user changes a page’s slug in BookStack: - The old URL becomes a 404. - BookStack **does not store historical slugs for books or chapters** (only pages have revisions via `page_revisions`). - External links, bookmarks, or search engine results pointing to the old URL break permanently. This creates a poor user experience and harms SEO. #### ✅ Solution The new middleware: - Runs early in the `web` middleware stack (after `TrustProxies`, before `PageViewCounter`). - Extracts the last path segment from the request (e.g., `/book/foo/bar` → `bar`). - Checks if this segment exists as a **non-current slug** in `page_revisions`. - If found, issues a **301 redirect** to `/link/{page_id}` — BookStack’s built-in, stable permalink route. - Skips API, asset, debug, and system routes to avoid interference. This approach is: - **100% reliable** for pages (uses real revision data). - **Independent of book/chapter slug history** (which BookStack doesn’t store). - **Zero-config** and fully automatic. - **Safe**: only redirects when an exact match is found in revisions. #### 🧪 Testing 1. Create a page → note its slug. 2. Edit the page and change its slug. 3. Visit any URL ending with the **old slug** (e.g., `/any/book/or/chapter/path/old-slug`). 4. ✅ Observe a 301 redirect to `/link/{id}`, then to the current page. > Note: The middleware matches **any path ending with the old slug**, because BookStack’s routing is dynamic and doesn’t enforce strict path structures. This ensures maximum compatibility. #### 📁 Files Changed - `app/Http/Middleware/RedirectOldPageSlugs.php` → new middleware - `app/Http/Kernel.php` → register middleware in `web` group #### ⚙️ Middleware Placement Inserted after `TrustProxies` and before `PageViewCounter` to: - Avoid counting redirected requests as page views. - Ensure trusted proxy headers are processed first. #### 💡 Why `/link/{id}` and not the canonical URL? - `/link/{id}` is BookStack’s official, stable permalink mechanism. - It already handles final redirection to the current URL (including updated book/chapter slugs). - This avoids duplicating routing logic and ensures consistency. --- ### ✅ Benefits - Restores broken links automatically. - Improves SEO by preserving link equity via 301s. - Requires no user intervention or configuration. - Minimal performance impact (indexed DB lookup on `page_revisions.slug`). --- ### 🙏 Final Note This feature aligns with BookStack’s philosophy of usability and data integrity, and leverages existing systems (`page_revisions`, `/link/{id}`) without introducing redundancy. Thank you for considering this contribution! --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
OVERLORD added the pull-request label 2026-02-05 10:36:00 +03:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/BookStack#6579