From c0d90fc33b4c1c91c8886e4bea78de9c46a8e7ae Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 22 Jul 2026 22:58:03 +0000 Subject: [PATCH] Fix multi-word category pages never matching their own articles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit /category/x-news filtered by the raw URL slug ("x-news") instead of the real category name ("X News"), so it never matched merged_articles.category values for any multi-word category — only worked for the seeded defaults because they're all single words where the slug and name happen to be identical once lowercased. Now resolves the slug back to the actual category name via the site's own category list before filtering. --- frontend/src/routes/category/[name]/+page.ts | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/frontend/src/routes/category/[name]/+page.ts b/frontend/src/routes/category/[name]/+page.ts index c83a4df..91366ea 100644 --- a/frontend/src/routes/category/[name]/+page.ts +++ b/frontend/src/routes/category/[name]/+page.ts @@ -1,14 +1,25 @@ import type { PageLoad } from './$types'; import { getFeed } from '$lib/api'; +import { slugify } from '$lib/format'; const PAGE_SIZE = 15; // Every category page (including "Local") filters by its category name — sources are // assigned categories directly via checkboxes in the admin Sources tab, so a source // tagged "Local" shows up here the same way one tagged "Tech" shows up on /category/tech. -export const load: PageLoad = async ({ params, fetch }) => { - const name = params.name; - const filters = { category: name }; +// +// The URL param is a slug (e.g. "x-news" from slugify("X News")), not the real category +// name — for single-word categories those happen to be the same lowercased, but for a +// multi-word name like "X News" the slug's hyphen never matches the stored "X News" +// (with a space) in a merged_articles.category LIKE match. Resolve the slug back to the +// real category name via the site's own category list (already loaded by the root +// layout) before filtering, rather than passing the raw slug straight through. +export const load: PageLoad = async ({ params, fetch, parent }) => { + const { categories } = await parent(); + const match = categories.find((c) => slugify(c.name) === params.name); + const categoryName = match?.name ?? params.name; + + const filters = { category: categoryName }; const initial = await getFeed({ ...filters, limit: PAGE_SIZE }, fetch); - return { initial, filters, name, pageSize: PAGE_SIZE }; + return { initial, filters, name: categoryName, pageSize: PAGE_SIZE }; };