From f5857f12987e2ba9ea928d6581ec45b6fd4fed58 Mon Sep 17 00:00:00 2001 From: Jeffrey Date: Wed, 18 Feb 2026 12:27:55 +0100 Subject: [PATCH] feat: dynamic sitemap and robots.txt at app root --- public/robots.txt | 11 -------- public/sitemap.xml | 5 ---- src/app/robots.ts | 22 +++++++++++++++ src/app/sitemap.ts | 70 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 92 insertions(+), 16 deletions(-) delete mode 100644 public/robots.txt delete mode 100644 public/sitemap.xml create mode 100644 src/app/robots.ts create mode 100644 src/app/sitemap.ts diff --git a/public/robots.txt b/public/robots.txt deleted file mode 100644 index 5b34ada..0000000 --- a/public/robots.txt +++ /dev/null @@ -1,11 +0,0 @@ -# * -User-agent: * -Disallow: /admin/* - -# Host -Host: http://localhost:3000 - -# Sitemaps -Sitemap: http://localhost:3000/sitemap.xml -Sitemap: http://localhost:3000/pages-sitemap.xml -Sitemap: http://localhost:3000/posts-sitemap.xml diff --git a/public/sitemap.xml b/public/sitemap.xml deleted file mode 100644 index 69b81e0..0000000 --- a/public/sitemap.xml +++ /dev/null @@ -1,5 +0,0 @@ - - -http://localhost:3000/pages-sitemap.xml -http://localhost:3000/posts-sitemap.xml - \ No newline at end of file diff --git a/src/app/robots.ts b/src/app/robots.ts new file mode 100644 index 0000000..c5af6e2 --- /dev/null +++ b/src/app/robots.ts @@ -0,0 +1,22 @@ +import type { MetadataRoute } from 'next' + +export default function robots(): MetadataRoute.Robots { + const siteUrl = process.env.NEXT_PUBLIC_SERVER_URL || 'https://fiberdirekt.se' + + return { + rules: [ + { + userAgent: '*', + allow: '/', + disallow: [ + '/admin', + '/admin/', + '/api/', + '/_next/', + ], + }, + ], + sitemap: `${siteUrl}/sitemap.xml`, + host: siteUrl, + } +} diff --git a/src/app/sitemap.ts b/src/app/sitemap.ts new file mode 100644 index 0000000..626534c --- /dev/null +++ b/src/app/sitemap.ts @@ -0,0 +1,70 @@ +import type { MetadataRoute } from 'next' +import { getPayload } from 'payload' +import config from '@payload-config' + +export const dynamic = 'force-dynamic' + +export default async function sitemap(): Promise { + const payload = await getPayload({ config }) + const siteUrl = process.env.NEXT_PUBLIC_SERVER_URL || 'https://fiberdirekt.se' + + // ── Fetch all published pages ────────────────────────────────────────── + const pages = await payload.find({ + collection: 'pages', + draft: false, + limit: 1000, + overrideAccess: false, + select: { + slug: true, + updatedAt: true, + }, + }) + + // ── Fetch all published posts ────────────────────────────────────────── + const posts = await payload.find({ + collection: 'posts', + draft: false, + limit: 1000, + overrideAccess: false, + select: { + slug: true, + updatedAt: true, + }, + }) + + // ── Static routes ────────────────────────────────────────────────────── + const staticRoutes: MetadataRoute.Sitemap = [ + { + url: siteUrl, + lastModified: new Date(), + changeFrequency: 'weekly', + priority: 1.0, + }, + { + url: `${siteUrl}/posts`, + lastModified: new Date(), + changeFrequency: 'weekly', + priority: 0.8, + }, + ] + + // ── Dynamic page routes ──────────────────────────────────────────────── + const pageRoutes: MetadataRoute.Sitemap = pages.docs + .filter((page) => page.slug !== 'home') // home is already the root URL + .map((page) => ({ + url: `${siteUrl}/${page.slug}`, + lastModified: new Date(page.updatedAt), + changeFrequency: 'monthly' as const, + priority: 0.8, + })) + + // ── Dynamic post routes ──────────────────────────────────────────────── + const postRoutes: MetadataRoute.Sitemap = posts.docs.map((post) => ({ + url: `${siteUrl}/posts/${post.slug}`, + lastModified: new Date(post.updatedAt), + changeFrequency: 'monthly' as const, + priority: 0.6, + })) + + return [...staticRoutes, ...pageRoutes, ...postRoutes] +}