import { fetchCms } from "~/server/utils/cmsApi"; function slugify(text: string): string { return text .toLowerCase() .replace(/\s+/g, "-") .replace(/ü/g, "ue") .replace(/ä/g, "ae") .replace(/ö/g, "oe") .replace(/ß/g, "ss"); } interface ProductData { id: number; slug?: string; updatedAt?: string; cover?: { id: number } | { data: { id: number } }; attributes?: { slug: string; updatedAt: string; cover?: { data: { id: number } }; }; } interface CoverData { id: number; name?: string; sort?: number; updatedAt?: string; attributes?: { name: string; sort?: number; updatedAt: string; }; } interface ApiResponse { data: T[]; meta?: { pagination?: { total: number; pageSize: number; pageCount: number; }; }; } export default defineSitemapEventHandler(async (event) => { const config = useRuntimeConfig(event); const siteUrl = config.siteUrl || "https://muellerprints-paperwork.com"; const urls: { loc: string; lastmod?: string; priority?: number }[] = []; const allPageSize = 20; // must match notebooks/index.vue pageSize const coverPageSize = 24; // must match notebooks/[cover].vue pageSize try { // Fetch all products for detail page URLs const products = await fetchCms>("/products", { query: { "pagination[pageSize]": "1000", "fields[0]": "slug", "fields[1]": "updatedAt", "populate[cover][fields][0]": "id" } }); // Product detail pages for (const product of products.data || []) { const slug = product.slug || product.attributes?.slug; const updatedAt = product.updatedAt || product.attributes?.updatedAt; if (slug) { urls.push({ loc: `${siteUrl}/details/${slug}`, lastmod: updatedAt, priority: 0.8 }); } } // Fetch promo products count for pagination (matches what the page actually shows) const promoProducts = await fetchCms>("/promo-products", { query: { "pagination[pageSize]": "1", "pagination[page]": "1" } }); const totalPromoProducts = promoProducts.meta?.pagination?.total || 0; const totalNotebooksPages = Math.ceil(totalPromoProducts / allPageSize); // Add /notebooks pagination pages for (let page = 2; page <= totalNotebooksPages; page++) { urls.push({ loc: `${siteUrl}/notebooks?page=${page}`, priority: 0.7 }); } // Fetch all covers const covers = await fetchCms>("/product-covers", { query: { "fields[0]": "name", "fields[1]": "sort", "fields[2]": "updatedAt" } }); // Sort covers by sort field const sortedCovers = (covers.data || []).sort((a, b) => { const sortA = a.sort ?? a.attributes?.sort ?? 0; const sortB = b.sort ?? b.attributes?.sort ?? 0; return sortA - sortB; }); // Cover category pages with slugs and pagination for (const cover of sortedCovers) { const name = cover.name || cover.attributes?.name; const updatedAt = cover.updatedAt || cover.attributes?.updatedAt; if (name) { const slug = slugify(name); // Main category page urls.push({ loc: `${siteUrl}/notebooks/${slug}`, lastmod: updatedAt, priority: 0.7 }); // Fetch promo product count for this cover (matches page display) const coverId = cover.id; const coverPromo = await fetchCms>("/promo-products", { query: { "filters[cover]": String(coverId), "pagination[pageSize]": "1", "pagination[page]": "1" } }); const coverTotal = coverPromo.meta?.pagination?.total || 0; const coverPageCount = Math.ceil(coverTotal / coverPageSize); // Add pagination pages for this category for (let page = 2; page <= coverPageCount; page++) { urls.push({ loc: `${siteUrl}/notebooks/${slug}?page=${page}`, priority: 0.6 }); } } } } catch (error) { console.error("Error fetching sitemap data:", error); } // Static pages urls.push( { loc: `${siteUrl}/`, priority: 1.0 }, { loc: `${siteUrl}/notebooks`, priority: 0.9 }, // Info pages { loc: `${siteUrl}/about`, priority: 0.6 }, { loc: `${siteUrl}/kontakt`, priority: 0.5 }, { loc: `${siteUrl}/anfahrt`, priority: 0.4 }, { loc: `${siteUrl}/oeffnungszeiten`, priority: 0.4 }, // Legal pages { loc: `${siteUrl}/impressum`, priority: 0.2 }, { loc: `${siteUrl}/datenschutz`, priority: 0.2 }, { loc: `${siteUrl}/agb`, priority: 0.2 }, { loc: `${siteUrl}/versand`, priority: 0.3 }, { loc: `${siteUrl}/zahlung`, priority: 0.3 } ); return urls; });