Gå til indhold

XML sitemaps generering

Ecreo.Essentials.Seo pakken indeholder en standard implementering af et XML sitemap over Umbraco noder, samt værktøjer til registrering af øvrige sitemaps.

Et XML sitemap er i grove træk en xml fil, med en liste over alle url’er på alle sider på et site. Det er typisk begrænset til at kunne indeholde 50.000 rækker, så på store sites kan vi have brug for at splitte det ud i flere.

Standard-sitemap’et genereres udfra Umbraco-indholdet i en løsning, og kan fanges på /xml-sitemap stien på et site. Generatoren finder så ud af hvorhenne i Umbraco-træet den skal starter ud fra domænet på requestet.

Har du fx. i Umbraco et site på ecreo.dk og er særskilt site på edl.dk, så vil ecreo.dk/xml-sitemap og edl.dk/xml-sitemap være forskellige. Er både ecreo.dk og edl.dk koblet på det samme site i Umbraco, så vil deres sitemaps være éns. I dette tilfælde bør du sørge for at det ene domæne viderestiller til det andet - men det er en anden sag.

Sitemap’et genereres ved at finde alle noder for det aktuelle domæner, der har en template, samt propertyen umbracoSitemapHide, denne property må så ikke være true).

Standard-sitemap’et understøtter også Umbraco-sites, der er bundet til en sti under samme hostname. Det kan fx være et multisite setup hvor domænerne i Umbraco er sat op som relative paths:

Umbraco domain Sitemap URL
/dk https://example.com/dk/xml-sitemap
/en https://example.com/en/xml-sitemap
/segment/subsegment https://example.com/segment/subsegment/xml-sitemap

Når sitemap’et requests, matcher pakken både host og path for at finde den rigtige site root. Det betyder at /segment/xml-sitemap og /segment/subsegment/xml-sitemap kan pege på forskellige rødder, hvis Umbraco-domænerne er sat sådan op.

Det færdige sitemap XML output caches i runtime cache i 5 minutter. Cache-nøglen består af scheme, host, request path og page query parameteren. Andre query parameters ignoreres, så fx ?utm_source=... ikke skaber ekstra cache entries.

Sitemap’et caches først efter site root og Examine index er fundet. Fejl som “site root not found” og “Examine index not found” caches derfor ikke.

Store sitemaps splittes stadig ud fra MaxRecordsPerSitemapXml, og hver page caches separat:

/xml-sitemap?page=1
/xml-sitemap?page=2

Magic properties

Standard sitemap genereringen via Umbraco kan styres via en håndfuld “magic properties”. Det er fx. ovennævnte umbracoSitemapHide, som bestemmer om en node overhovedet inkluderes i sitemappet. Herudover kan indsættes propertien umbracoSitemapChangeFreq til at styre changeFreq attributten påd en enkelte sitemap node (skal være en string og enten never, yearly, monthly, weekly, daily eller always). Priority attributen kan styres med en property med aliaset umbracoSitemapPriority. Denne skal returnere en decimal mellem 0 og 1.

Property aliaserne, og indstillingerne for fx. changeFreq og priority, kan konfigureres, enten via kode (Ecreo.Essentials.Seo.SeoOptions) eller i appsettings (Ecreo:Essentials:Seo).

Fra projekt til projekt kan der være behov for at lave et eller flere custom sitemaps. Det kunne fx være et sitemap over kategorier eller produkter i en webshop. Hvordan sitemappet genereres er op til projektet, reelt skal man bare lave noget der for en given url, returnerer det ønskede XML-sitemap. Dette kan være en API-controller, en statisk XML-fil eller noget helt tredje.

Pakken indeholder en generisk XML helper, så custom sitemaps ikke behøver at bygge XML med string interpolation. Helperen kræver ikke Examine eller Umbraco-indhold, men tager almindelige SitemapXmlItem objekter.

using Ecreo.Essentials.Seo;
using Microsoft.AspNetCore.Mvc;
[Route("/sitemap-products.xml")]
public class ProductSitemapController : Controller
{
[HttpGet]
public IActionResult Index()
{
var items = new[]
{
new SitemapXmlItem(
Location: "https://example.com/products/red-chair",
LastModified: DateTimeOffset.UtcNow,
ChangeFrequency: "weekly",
Priority: 0.8M
),
new SitemapXmlItem(
Location: "https://example.com/products/blue-chair"
),
};
var xml = SitemapXmlGenerator.GenerateSitemap(items);
return Content(xml, "text/xml");
}
}

SitemapXmlGenerator.GenerateSitemap(...) renderer et <urlset> med:

Felt XML element Påkrævet
Location <loc> Ja
LastModified <lastmod> Nej
ChangeFrequency <changefreq> Nej
Priority <priority> Nej

Helperen bruger XmlWriter, så URL’er og værdier escapes korrekt i XML outputtet.

Har du flere sitemap-filer, kan du også generere et sitemap index:

var xml = SitemapXmlGenerator.GenerateSitemapIndex(
new[]
{
"https://example.com/sitemap-products.xml",
"https://example.com/sitemap-categories.xml",
}
);

Søgemaskinerobotter finder automatisk sitemaps der ligger i /sitemap.xml, men denne bruges til vores standard sitemap. Så et kategori-sitemap vil måske ligge i /sitemap-xml-categories. For at gøre søgemaskinerobotterne opmærksom på dette sitemap, kan vi tilføje en reference til det i robots.txt filen.

Dette kan gøres via vores automatisk robots.txt generator. Ligesom der er mulighed for at tilføje custom regler til robots.txt filen, er der også mulighed for at tilføje custom xml-sitemap referencer.

Dette sker ved at lave en klasse der implementerer interfacet ISitemapXmlReference, som fx nedenstående:

using Ecreo.Essentials.Seo.Interfaces;
using System;
namespace MyProject.Seo.Rules
{
public class CategoriesSitemapXmlReference : ISitemapXmlReference
{
public bool IsEnabledInDisallowedDomains() => false;
public bool IsEnabled(Uri requestUri) => true;
public string[] SitemapReferences(Uri requestUri)
{
return new[] { new Uri(requestUri, "/sitemap-xml-categories").ToString() };
}
}
}

ISitemapXmlReference kræver at man implementerer nogle bestemte metoder, beskrevet herunder:

  • IsEnabledInDisallowedDomains() Denne angiver om den aktuelle reference skal bruges på testdomæner. I ovenstående tilfælde gælder referencen for livedomænet, og metoden returnerer derfor false
  • IsEnabled(Uri requestUri) Denne angiver om den aktuelle reference skal bruges på produktionsdomæner. Du får her den aktuelle request URI med, så du kan filtrere yderligere om referencen skal bruge. I dette tilfælde har vi ikke brug for at filtrere yderligere på fx. domæne, så vi returner blot true, for at referencen gælder på alle produktionsdomæner.
  • SitemapReferences(Uri requestUri) Denne angiver linksne til alle de xml-sitemaps der skal inkluderes i robots.txt filen. I ovenstående eksempel er det bare en enkelt url, men du får i metoden den aktuelle request URI med, så du kan filtrere og generere yderligere med den.

Nu har vi defineret vores reference, men den skal også tilføjes til den collection som robots.txt generatoren bruger. Det gøres i en IComposer.

using Ecreo.Essentials.Seo.Extensions;
using Umbraco.Cms.Core.Composing;
using Umbraco.Cms.Core.DependencyInjection;
public class SitemapComposer : IComposer
{
public void Compose(IUmbracoBuilder builder)
{
builder.SitemapXmlReferences()
.Append<MyProject.Seo.Rules.CategoriesSitemapXmlReference>();
}
}

SitemapXmlReferences() er en extension method i Ecreo.Essentials.Seo.Extensions og giver adgang til collectionen af sitemap references.