Added styled Xml
This commit is contained in:
Vendored
+57
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Serializes sitemap entries to an XML STRING with an XSL stylesheet reference,
|
||||
* so /sitemap.xml renders as a readable table in the browser (not raw XML) while
|
||||
* staying a valid sitemap for crawlers.
|
||||
*
|
||||
* Why this exists alongside the Next MetadataRoute sitemap: Next's app/sitemap.ts
|
||||
* (returning SitemapEntry[]) does NOT let you inject <?xml-stylesheet?>. To get
|
||||
* the styled table, serve a custom route that returns this string instead:
|
||||
*
|
||||
* // app/sitemap.xml/route.ts
|
||||
* import { buildSitemapXml } from '@intecion/ipal-kit'
|
||||
* import { sitemap } from '@/lib/content' // your entries source
|
||||
* export const dynamic = 'force-dynamic'
|
||||
* export async function GET() {
|
||||
* const entries = await sitemap()
|
||||
* const xml = buildSitemapXml(entries, { stylesheetUrl: '/sitemap.xsl' })
|
||||
* return new Response(xml, {
|
||||
* headers: { 'Content-Type': 'application/xml; charset=utf-8' },
|
||||
* })
|
||||
* }
|
||||
*
|
||||
* Put sitemap.xsl in the project's /public (copy from the plugin's assets, or
|
||||
* serve it from a route). The <?xml-stylesheet?> points browsers at it; crawlers
|
||||
* ignore it and read the XML. Include hreflang alternates as <xhtml:link>.
|
||||
*
|
||||
* NOTE: if you use this custom route, DON'T also keep app/sitemap.ts — pick one
|
||||
* (the styled route OR the Next MetadataRoute). Two sitemaps at different paths
|
||||
* confuse crawlers.
|
||||
*/ export function buildSitemapXml(entries, opts = {}) {
|
||||
const { stylesheetUrl } = opts;
|
||||
const esc = (s)=>s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, ''');
|
||||
const urls = entries.map((e)=>{
|
||||
const parts = [
|
||||
` <loc>${esc(e.url)}</loc>`
|
||||
];
|
||||
if (e.lastModified) {
|
||||
const iso = e.lastModified instanceof Date ? e.lastModified.toISOString() : String(e.lastModified);
|
||||
parts.push(` <lastmod>${esc(iso)}</lastmod>`);
|
||||
}
|
||||
if (e.changeFrequency) parts.push(` <changefreq>${e.changeFrequency}</changefreq>`);
|
||||
if (typeof e.priority === 'number') parts.push(` <priority>${e.priority}</priority>`);
|
||||
// hreflang alternates
|
||||
const alternates = e.alternates?.languages;
|
||||
if (alternates) {
|
||||
for (const [lang, href] of Object.entries(alternates)){
|
||||
if (typeof href === 'string') {
|
||||
parts.push(` <xhtml:link rel="alternate" hreflang="${esc(lang)}" href="${esc(href)}"/>`);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ` <url>\n${parts.join('\n')}\n </url>`;
|
||||
}).join('\n');
|
||||
const stylesheet = stylesheetUrl ? `<?xml-stylesheet type="text/xsl" href="${esc(stylesheetUrl)}"?>\n` : '';
|
||||
return `<?xml version="1.0" encoding="UTF-8"?>\n` + stylesheet + `<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" ` + `xmlns:xhtml="http://www.w3.org/1999/xhtml">\n` + urls + `\n</urlset>`;
|
||||
}
|
||||
|
||||
//# sourceMappingURL=buildSitemapXml.js.map
|
||||
Reference in New Issue
Block a user