mirror of
https://github.com/complexcaresolutions/cms.c2sgmbh.git
synced 2026-03-17 16:14:12 +00:00
fix: support slug and where[] query params in custom posts route
The custom /api/posts route intercepted all post queries but only supported listing parameters (category, type, page). Frontend detail pages sending where[slug][equals]=X got all posts back, always showing the latest post regardless of which article was clicked. Now parses slug from both ?slug=X and ?where[slug][equals]=X format. Replaced getPostsByCategory with direct payload.find using properly typed Where conditions. Detail queries (with slug) include content and readingTime in the response. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
6d13361ad4
commit
9e791648e9
1 changed files with 76 additions and 40 deletions
|
|
@ -3,8 +3,8 @@
|
|||
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { getPayload } from 'payload'
|
||||
import type { Where } from 'payload'
|
||||
import config from '@payload-config'
|
||||
import { getPostsByCategory } from '@/lib/search'
|
||||
import type { Category } from '@/payload-types'
|
||||
import {
|
||||
searchLimiter,
|
||||
|
|
@ -42,11 +42,12 @@ export async function GET(request: NextRequest) {
|
|||
)
|
||||
}
|
||||
|
||||
// Parse query parameters
|
||||
// Parse query parameters (supports both ?key=val and ?where[key][equals]=val formats)
|
||||
const { searchParams } = new URL(request.url)
|
||||
const category = searchParams.get('category')?.trim()
|
||||
const type = searchParams.get('type')?.trim() as 'blog' | 'news' | 'press' | 'announcement' | undefined
|
||||
const tenantParam = searchParams.get('tenant') || searchParams.get('where[tenant][equals]')
|
||||
const slugParam = searchParams.get('slug')?.trim() || searchParams.get('where[slug][equals]')?.trim()
|
||||
const pageParam = searchParams.get('page')
|
||||
const limitParam = searchParams.get('limit')
|
||||
const localeParam = searchParams.get('locale')?.trim()
|
||||
|
|
@ -90,47 +91,82 @@ export async function GET(request: NextRequest) {
|
|||
// Get payload instance
|
||||
const payload = await getPayload({ config })
|
||||
|
||||
// Get posts
|
||||
const result = await getPostsByCategory(payload, {
|
||||
tenantId,
|
||||
categorySlug: category,
|
||||
type,
|
||||
locale,
|
||||
// Build query: slug lookup uses direct payload.find for full where support
|
||||
const whereConditions: Where[] = [
|
||||
{ tenant: { equals: tenantId } },
|
||||
{ status: { equals: 'published' } },
|
||||
]
|
||||
if (slugParam) {
|
||||
whereConditions.push({ slug: { equals: slugParam } })
|
||||
}
|
||||
if (type) {
|
||||
whereConditions.push({ type: { equals: type } })
|
||||
}
|
||||
if (category) {
|
||||
// Category filter by slug: look up category first
|
||||
const catResult = await payload.find({
|
||||
collection: 'categories',
|
||||
where: {
|
||||
slug: { equals: category },
|
||||
...(tenantId ? { tenant: { equals: tenantId } } : {}),
|
||||
},
|
||||
locale: locale as 'de' | 'en',
|
||||
limit: 1,
|
||||
})
|
||||
if (catResult.docs.length > 0) {
|
||||
whereConditions.push({ categories: { contains: catResult.docs[0].id } })
|
||||
}
|
||||
}
|
||||
|
||||
const result = await payload.find({
|
||||
collection: 'posts',
|
||||
where: { and: whereConditions },
|
||||
locale: locale as 'de' | 'en',
|
||||
fallbackLocale: 'de',
|
||||
page,
|
||||
limit,
|
||||
sort: '-publishedAt',
|
||||
depth: slugParam ? 2 : 1,
|
||||
})
|
||||
|
||||
// Transform response
|
||||
// Transform response — slug lookup returns full post, listing returns summary
|
||||
const response = {
|
||||
docs: result.docs.map((post) => ({
|
||||
id: post.id,
|
||||
title: post.title,
|
||||
slug: post.slug,
|
||||
excerpt: post.excerpt || null,
|
||||
publishedAt: post.publishedAt || null,
|
||||
type: (post as typeof post & { type?: string }).type || 'blog',
|
||||
featuredImage: post.featuredImage && typeof post.featuredImage === 'object'
|
||||
? {
|
||||
url: post.featuredImage.url,
|
||||
alt: post.featuredImage.alt,
|
||||
width: post.featuredImage.width,
|
||||
height: post.featuredImage.height,
|
||||
}
|
||||
: null,
|
||||
category: Array.isArray(post.categories) && post.categories.length > 0
|
||||
? (() => {
|
||||
const firstCat = post.categories.find(
|
||||
(cat): cat is Category => cat !== null && typeof cat === 'object' && 'name' in cat
|
||||
)
|
||||
return firstCat ? { name: firstCat.name, slug: firstCat.slug } : null
|
||||
})()
|
||||
: null,
|
||||
categories: Array.isArray(post.categories)
|
||||
? post.categories
|
||||
.filter((cat): cat is Category => cat !== null && typeof cat === 'object' && 'name' in cat)
|
||||
.map((cat) => ({ name: cat.name, slug: cat.slug }))
|
||||
: [],
|
||||
})),
|
||||
docs: result.docs.map((post) => {
|
||||
const base = {
|
||||
id: post.id,
|
||||
title: post.title,
|
||||
slug: post.slug,
|
||||
excerpt: post.excerpt || null,
|
||||
publishedAt: post.publishedAt || null,
|
||||
type: (post as typeof post & { type?: string }).type || 'blog',
|
||||
featuredImage: post.featuredImage && typeof post.featuredImage === 'object'
|
||||
? {
|
||||
url: post.featuredImage.url,
|
||||
alt: post.featuredImage.alt,
|
||||
width: post.featuredImage.width,
|
||||
height: post.featuredImage.height,
|
||||
}
|
||||
: null,
|
||||
category: Array.isArray(post.categories) && post.categories.length > 0
|
||||
? (() => {
|
||||
const firstCat = post.categories.find(
|
||||
(cat): cat is Category => cat !== null && typeof cat === 'object' && 'name' in cat
|
||||
)
|
||||
return firstCat ? { name: firstCat.name, slug: firstCat.slug } : null
|
||||
})()
|
||||
: null,
|
||||
categories: Array.isArray(post.categories)
|
||||
? post.categories
|
||||
.filter((cat): cat is Category => cat !== null && typeof cat === 'object' && 'name' in cat)
|
||||
.map((cat) => ({ name: cat.name, slug: cat.slug }))
|
||||
: [],
|
||||
}
|
||||
// Include content and extra fields for detail queries (slug lookup)
|
||||
if (slugParam) {
|
||||
return { ...base, content: post.content, readingTime: (post as typeof post & { readingTime?: number }).readingTime }
|
||||
}
|
||||
return base
|
||||
}),
|
||||
pagination: {
|
||||
page: result.page,
|
||||
limit,
|
||||
|
|
@ -140,8 +176,8 @@ export async function GET(request: NextRequest) {
|
|||
hasPrevPage: result.hasPrevPage,
|
||||
},
|
||||
filters: {
|
||||
category,
|
||||
type,
|
||||
...(category ? { category } : {}),
|
||||
...(type ? { type } : {}),
|
||||
locale,
|
||||
tenant: tenantId,
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in a new issue