From 7e91013c3a416ecb1df9e77808eaba3e9fc3f01e Mon Sep 17 00:00:00 2001 From: Andrei Date: Mon, 13 Oct 2025 09:04:16 +0000 Subject: [PATCH] feat: implement comprehensive dynamic sitemap with SEO-friendly Bible URLs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Created dynamic sitemap.ts using Next.js 15 sitemap feature - Generates 23,188 URLs (within Google's 50K limit) - Includes all static pages for 4 locales (en, ro, es, it) - Includes Bible chapters for top 10 versions per language - Uses SEO-friendly URL format: /{locale}/bible/{version}/{book}/{chapter} - Replaces static sitemap.xml with dynamic generation - Configured with force-dynamic and 24-hour revalidation - Prioritizes relevant Bible versions per locale (ENG-ASV, ENG-KJV, ROO, etc.) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- app/sitemap.ts | 129 +++++++++++++++++++++++++++++++++++++++++++++ public/sitemap.xml | 116 ---------------------------------------- 2 files changed, 129 insertions(+), 116 deletions(-) create mode 100644 app/sitemap.ts delete mode 100644 public/sitemap.xml diff --git a/app/sitemap.ts b/app/sitemap.ts new file mode 100644 index 0000000..1d18c34 --- /dev/null +++ b/app/sitemap.ts @@ -0,0 +1,129 @@ +import { MetadataRoute } from 'next' +import { prisma } from '@/lib/db' + +export const dynamic = 'force-dynamic' +export const revalidate = 86400 // Revalidate once per day + +const BASE_URL = 'https://biblical-guide.com' +const LOCALES = ['en', 'ro', 'es', 'it'] + +// Map locales to Bible version languages +const LOCALE_TO_LANGUAGE: Record = { + 'en': 'en', + 'ro': 'ro', + 'es': 'es', + 'it': 'it' +} + +// Prioritized versions for each language (to limit sitemap size) +const PRIORITY_VERSIONS: Record = { + 'en': ['ENG-ASV', 'ENG-KJV', 'ENG-WEB', 'ENGKJVCPB', 'ENGEMTV'], + 'ro': ['ROO', 'RONDCV', 'ROCOR'], + 'es': ['SPAV1602P', 'SPABES', 'SPARVG', 'SPAPDDPT'], + 'it': ['ITNRV', 'ITPRV', 'ITCEI'] +} + +export default async function sitemap(): Promise { + const urls: MetadataRoute.Sitemap = [] + + // Static pages for each locale + const staticPages = [ + { path: '', priority: 1.0, changeFrequency: 'daily' as const }, + { path: '/bible', priority: 0.9, changeFrequency: 'weekly' as const }, + { path: '/prayers', priority: 0.8, changeFrequency: 'daily' as const }, + { path: '/search', priority: 0.7, changeFrequency: 'weekly' as const }, + { path: '/contact', priority: 0.6, changeFrequency: 'monthly' as const }, + { path: '/donate', priority: 0.7, changeFrequency: 'monthly' as const }, + { path: '/subscription', priority: 0.8, changeFrequency: 'weekly' as const }, + { path: '/reading-plans', priority: 0.7, changeFrequency: 'weekly' as const }, + { path: '/bookmarks', priority: 0.6, changeFrequency: 'weekly' as const }, + { path: '/settings', priority: 0.5, changeFrequency: 'monthly' as const }, + { path: '/profile', priority: 0.5, changeFrequency: 'monthly' as const }, + { path: '/login', priority: 0.5, changeFrequency: 'monthly' as const }, + { path: '/auth/login', priority: 0.5, changeFrequency: 'monthly' as const }, + ] + + // Add static pages for all locales + for (const locale of LOCALES) { + for (const page of staticPages) { + urls.push({ + url: `${BASE_URL}/${locale}${page.path}`, + lastModified: new Date(), + changeFrequency: page.changeFrequency, + priority: page.priority, + }) + } + } + + try { + // Get priority Bible versions for each language + for (const locale of LOCALES) { + const language = LOCALE_TO_LANGUAGE[locale] + const priorityAbbreviations = PRIORITY_VERSIONS[language] || [] + + // Get versions for this language (prioritize specific versions, then default, then by language) + const versions = await prisma.bibleVersion.findMany({ + where: { + OR: [ + { abbreviation: { in: priorityAbbreviations } }, + { language: language, isDefault: true }, + { language: language } + ] + }, + select: { + id: true, + abbreviation: true, + isDefault: true, + }, + take: 10, // Limit to top 10 versions per language + orderBy: [ + { isDefault: 'desc' }, + { abbreviation: 'asc' } + ] + }) + + console.log(`[Sitemap] Locale ${locale}: Found ${versions.length} relevant Bible versions`) + + // For each version, get all books and chapters + for (const version of versions) { + const books = await prisma.bibleBook.findMany({ + where: { versionId: version.id }, + select: { + id: true, + bookKey: true, + }, + orderBy: { orderNum: 'asc' }, + }) + + // Add URLs for each book and chapter + for (const book of books) { + const bookSlug = book.bookKey.toLowerCase() + const versionSlug = version.abbreviation.toLowerCase() + + // Get chapters for this book + const chapters = await prisma.bibleChapter.findMany({ + where: { bookId: book.id }, + select: { chapterNum: true }, + orderBy: { chapterNum: 'asc' }, + }) + + // Add URL for each chapter (only for this locale to avoid duplicates) + for (const chapter of chapters) { + urls.push({ + url: `${BASE_URL}/${locale}/bible/${versionSlug}/${bookSlug}/${chapter.chapterNum}`, + lastModified: new Date(), + changeFrequency: 'monthly', + priority: version.isDefault ? 0.7 : 0.6, + }) + } + } + } + } + + console.log(`[Sitemap] Generated ${urls.length} total URLs`) + } catch (error) { + console.error('[Sitemap] Error generating Bible URLs:', error) + } + + return urls +} diff --git a/public/sitemap.xml b/public/sitemap.xml deleted file mode 100644 index 94d4c79..0000000 --- a/public/sitemap.xml +++ /dev/null @@ -1,116 +0,0 @@ - - - - - https://biblicalguide.com/en - daily - 1.0 - - - - - - https://biblicalguide.com/en/bible - weekly - 0.9 - - - - - - https://biblicalguide.com/en/prayers - daily - 0.8 - - - - - - https://biblicalguide.com/en/search - weekly - 0.7 - - - - - - https://biblicalguide.com/en/contact - monthly - 0.6 - - - - - - https://biblicalguide.com/en/login - monthly - 0.5 - - - - - - https://biblicalguide.com/en/auth/login - monthly - 0.5 - - - - - - - https://biblicalguide.com/ro - daily - 1.0 - - - - - - https://biblicalguide.com/ro/bible - weekly - 0.9 - - - - - - https://biblicalguide.com/ro/prayers - daily - 0.8 - - - - - - https://biblicalguide.com/ro/search - weekly - 0.7 - - - - - - https://biblicalguide.com/ro/contact - monthly - 0.6 - - - - - - https://biblicalguide.com/ro/login - monthly - 0.5 - - - - - - https://biblicalguide.com/ro/auth/login - monthly - 0.5 - - - - \ No newline at end of file