From 8ffb5967d39575d3f0ac1e144cd9f288a2a7d175 Mon Sep 17 00:00:00 2001 From: Marc Mintel Date: Mon, 16 Mar 2026 23:15:04 +0100 Subject: [PATCH] fix(seo): correct canonical tags and localized blog post hreflang --- app/[locale]/blog/[slug]/page.tsx | 38 ++++++++++++++-------- app/[locale]/layout.tsx | 7 ---- lib/blog.ts | 54 +++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 21 deletions(-) diff --git a/app/[locale]/blog/[slug]/page.tsx b/app/[locale]/blog/[slug]/page.tsx index e2601738..2f378fa1 100644 --- a/app/[locale]/blog/[slug]/page.tsx +++ b/app/[locale]/blog/[slug]/page.tsx @@ -6,6 +6,7 @@ import { getAdjacentPosts, getReadingTime, extractLexicalHeadings, + getPostSlugs, } from '@/lib/blog'; import { Metadata } from 'next'; import Link from 'next/link'; @@ -33,12 +34,21 @@ export async function generateMetadata({ params }: BlogPostProps): Promise{getReadingTime(rawTextContent)} min read {(new Date(post.frontmatter.date) > new Date() || post.frontmatter.public === false) && ( - <> - - - Draft Preview - - - )} + <> + + + Draft Preview + + + )} @@ -171,13 +181,13 @@ export default async function BlogPost({ params }: BlogPostProps) { {getReadingTime(rawTextContent)} min read {(new Date(post.frontmatter.date) > new Date() || post.frontmatter.public === false) && ( - <> - - - Draft Preview - - - )} + <> + + + Draft Preview + + + )} diff --git a/app/[locale]/layout.tsx b/app/[locale]/layout.tsx index eeb055b6..5d451dcb 100644 --- a/app/[locale]/layout.tsx +++ b/app/[locale]/layout.tsx @@ -35,13 +35,6 @@ export async function generateMetadata(props: { }, metadataBase: new URL(baseUrl), manifest: '/manifest.webmanifest', - alternates: { - canonical: `${baseUrl}/${locale}`, - languages: { - de: `${baseUrl}/de`, - en: `${baseUrl}/en`, - }, - }, icons: { icon: [ { url: '/favicon.ico', sizes: 'any' }, diff --git a/lib/blog.ts b/lib/blog.ts index 7ff0f011..6725d5ef 100644 --- a/lib/blog.ts +++ b/lib/blog.ts @@ -136,6 +136,60 @@ export async function getPostBySlug(slug: string, locale: string): Promise> { + try { + const payload = await getPayload({ config: configPromise }); + + // First, find the post in the current locale to get its ID + let { docs } = await payload.find({ + collection: 'posts', + where: { + slug: { equals: slug }, + ...(!config.showDrafts ? { _status: { equals: 'published' } } : {}), + }, + locale: locale as any, + draft: config.showDrafts, + limit: 1, + }); + + if (!docs || docs.length === 0) { + // Fallback: search across all locales + const { docs: crossLocaleDocs } = await payload.find({ + collection: 'posts', + where: { + slug: { equals: slug }, + ...(!config.showDrafts ? { _status: { equals: 'published' } } : {}), + }, + locale: 'all', + draft: config.showDrafts, + limit: 1, + }); + docs = crossLocaleDocs; + } + + if (!docs || docs.length === 0) return {}; + + const postId = docs[0].id; + + // Fetch the post with locale 'all' to get all localized fields + const { docs: allLocalesDocs } = await payload.find({ + collection: 'posts', + where: { + id: { equals: postId }, + }, + locale: 'all', + draft: config.showDrafts, + limit: 1, + }); + + if (!allLocalesDocs || allLocalesDocs.length === 0) return {}; + return (allLocalesDocs[0].slug as unknown as Record) || {}; + } catch (error) { + console.error(`[Payload] getPostSlugs failed for ${slug}:`, error); + return {}; + } +} + export async function getAllPosts(locale: string): Promise { try { const payload = await getPayload({ config: configPromise });