Install @payloadcms/plugin-redirects, configure for 'pages' collection with 301/302 types. Create src/middleware.ts that reads the redirects collection via REST API (cached 5 min) and applies them before Next.js renders — editors can manage redirects from the CMS admin. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
47 lines
1.4 KiB
TypeScript
47 lines
1.4 KiB
TypeScript
import type { NextRequest } from 'next/server'
|
|
import { NextResponse } from 'next/server'
|
|
|
|
let redirectsCache: { from: string; to: string; type: string }[] | null = null
|
|
let cacheExpiry = 0
|
|
|
|
async function getRedirects(siteURL: string) {
|
|
if (redirectsCache && Date.now() < cacheExpiry) return redirectsCache
|
|
|
|
try {
|
|
const res = await fetch(`${siteURL}/api/redirects?limit=100&depth=1`, {
|
|
next: { revalidate: 300 },
|
|
})
|
|
if (!res.ok) return []
|
|
const data = (await res.json()) as {
|
|
docs: { from: string; to: { url?: string }; redirectType: string }[]
|
|
}
|
|
redirectsCache = data.docs.map((r) => ({
|
|
from: r.from,
|
|
to: r.to?.url ?? '/',
|
|
type: r.redirectType,
|
|
}))
|
|
cacheExpiry = Date.now() + 5 * 60 * 1000
|
|
return redirectsCache
|
|
} catch {
|
|
return []
|
|
}
|
|
}
|
|
|
|
export async function middleware(request: NextRequest) {
|
|
const siteURL = process.env['NEXT_PUBLIC_SITE_URL'] ?? 'http://localhost:3000'
|
|
const pathname = request.nextUrl.pathname
|
|
|
|
const redirects = await getRedirects(siteURL)
|
|
const match = redirects.find((r) => r.from === pathname)
|
|
|
|
if (match) {
|
|
const status = match.type === '302' ? 302 : 301
|
|
return NextResponse.redirect(new URL(match.to, request.url), status)
|
|
}
|
|
|
|
return NextResponse.next()
|
|
}
|
|
|
|
export const config = {
|
|
matcher: ['/((?!_next/static|_next/image|favicon.ico|api/|admin/).*)'],
|
|
}
|