From 2b2de66b5dcaa8e82f6e2a70700a0af20f39a84b Mon Sep 17 00:00:00 2001 From: Danijel Martinek Date: Mon, 4 May 2026 20:37:00 +0200 Subject: [PATCH] feat(core-shared): add slugifyIfMissing hook --- .../payload/hooks/slugify-if-missing.test.ts | 44 +++++++++++++++++++ .../src/payload/hooks/slugify-if-missing.ts | 19 ++++++++ 2 files changed, 63 insertions(+) create mode 100644 packages/core-shared/src/payload/hooks/slugify-if-missing.test.ts create mode 100644 packages/core-shared/src/payload/hooks/slugify-if-missing.ts diff --git a/packages/core-shared/src/payload/hooks/slugify-if-missing.test.ts b/packages/core-shared/src/payload/hooks/slugify-if-missing.test.ts new file mode 100644 index 0000000..0d75e22 --- /dev/null +++ b/packages/core-shared/src/payload/hooks/slugify-if-missing.test.ts @@ -0,0 +1,44 @@ +import { describe, expect, it } from "vitest"; +import { slugifyIfMissing } from "./slugify-if-missing"; + +describe("slugifyIfMissing", () => { + it("derives slug from title on create when slug is empty", () => { + const result = slugifyIfMissing({ + data: { title: "Hello World" }, + operation: "create", + }); + expect(result?.slug).toBe("hello-world"); + }); + + it("does not overwrite an existing slug", () => { + const result = slugifyIfMissing({ + data: { title: "New Title", slug: "kept-slug" }, + operation: "create", + }); + expect(result?.slug).toBe("kept-slug"); + }); + + it("does nothing on update", () => { + const result = slugifyIfMissing({ + data: { title: "Hello World" }, + operation: "update", + }); + expect(result?.slug).toBeUndefined(); + }); + + it("strips non-alphanumerics and trims hyphens", () => { + const result = slugifyIfMissing({ + data: { title: " Hello, World!! 2026 " }, + operation: "create", + }); + expect(result?.slug).toBe("hello-world-2026"); + }); + + it("returns data unchanged when title is missing", () => { + const result = slugifyIfMissing({ + data: {}, + operation: "create", + }); + expect(result?.slug).toBeUndefined(); + }); +}); diff --git a/packages/core-shared/src/payload/hooks/slugify-if-missing.ts b/packages/core-shared/src/payload/hooks/slugify-if-missing.ts new file mode 100644 index 0000000..891c525 --- /dev/null +++ b/packages/core-shared/src/payload/hooks/slugify-if-missing.ts @@ -0,0 +1,19 @@ +export function slugifyIfMissing({ + data, + operation, +}: { + data?: { title?: string; slug?: string }; + operation?: string; +}) { + if (!data) return data; + if (operation !== "create") return data; + if (data.slug) return data; + if (!data.title) return data; + + data.slug = data.title + .toLowerCase() + .replace(/[^a-z0-9]+/g, "-") + .replace(/^-+|-+$/g, ""); + + return data; +}