import type { CollectionBeforeChangeHook } from 'payload' /** * When a document's slug changes, appends the OLD slug to a `slugHistory` array * field. The project reads slugHistory to serve a 301 redirect from old URLs to * the current one — so changing a slug doesn't 404 the old address (a real SEO * loss / audit finding). * * Requires a `slugHistory` field on the collection: * { name: 'slugHistory', type: 'array', fields: [{ name: 'slug', type: 'text' }], * admin: { readOnly: true } } * * hooks: { beforeChange: [trackSlugHistoryHook] } * * The project then, in resolveRoute or a redirect check, looks up slugHistory and * 301s to the current slug. See docs/hooks.md. */ export const trackSlugHistoryHook: CollectionBeforeChangeHook = ({ data, originalDoc }) => { const oldSlug = originalDoc?.slug const newSlug = data.slug if ( typeof oldSlug === 'string' && typeof newSlug === 'string' && oldSlug !== newSlug && oldSlug.length > 0 ) { const history: Array<{ slug: string }> = Array.isArray(data.slugHistory) ? data.slugHistory : Array.isArray(originalDoc?.slugHistory) ? originalDoc.slugHistory : [] // Avoid duplicates; don't record the new slug itself. if (!history.some((h) => h?.slug === oldSlug)) { data.slugHistory = [...history, { slug: oldSlug }] } } return data }