17: SEO

De seo resource centraliseert de zoek- en deelmetadata die een app nodig heeft: sitemap.xml, robots.txt, hreflang-alternatieven, de canonieke link, en een <head> blok met <meta> beschrijving plus Open Graph en Twitter kaarten. Het haalt alles af van props die je al hebt ingesteld, zodat een uniforme, complete maar beheersbare set vanuit één plek wordt geleverd.

17.1: Activatie

Voeg de resource toe (het heeft output nodig):

{
	"resources": [..., "seo", "output"]
}

Dat alleen dient twee routes:

Route Output
GET /sitemap.xml Een meertalige sitemap opgebouwd uit %app->pages en %app->langs
GET /robots.txt Allow of Disallow, afhankelijk van de indexable constant (zie X.4)

De <head> metadata is opt-in per pagina: render %seo->head waar je het wilt (X.3).

17.2: De sitemap en hreflang

De sitemap doorloopt %app->pages en geeft voor elke pagina een hreflang alternatief per invoer in %app->langs plus een x-default. Gelokaliseerde paden komen van %app->slugs (een uri => gelokaliseerde-uri map) wanneer je ze hebt; anders wordt het pad voorafgegaan door de taalcodes.

In je <head> horen dezelfde alternatieven als <link rel=alternate hreflang> tags. De resource geeft je één view daarvoor, dus je doorloopt je talen en laat seo elke link formatteren:

view head:
<foreach array_keys(%app->langs) AS $lang>
	{{ %seo->link($lang, $lang === %app->lang ? %req->uri : "/$lang".%req->uri) }}
</foreach>
{{ %seo->head }}

De app bezit welke URL's alternatieven zijn (het kent zijn eigen routing en lokalisatie); seo bezit de markup.

17.3: De head block

%seo->head rendert de conventionele metadata set, allemaal afgeleid van bestaande props:

Het is samenstelbaar, geen vervanging: houd de eigen head-tags van je app (titel, CSRF, stijlen) en voeg %seo->head ernaast toe. Er zijn geen zoekwoorden en geen marketingvulling; de set bestaat uit Open Graph, Twitter kaart, canoniek, hreflang, beschrijving en robots, wat de gebruikelijke complete maar beperkte basislijn is.

De standaardwaarden worden gelezen uit props die je al hebt:

Eigenschap Standaardbron
og:title De documenttitel
og:description / beschrijving %app->description
og:image %app->image, met als fallback /icon.webp op de site root
og:url / canoniek De huidige aanvraag-URL
og:site_name De app id
og:locale Afgeleid van %app->lang (bijvoorbeeld nl wordt nl_NL)
og:type website

17.4: robots.txt en de indexeerbare constante

robots.txt wordt gegenereerd en is veilig per standaard. Tenzij de app de indexable constant op een waarheidsgetrouwe waarde instelt, levert de resource:

User-agent: *
Disallow: /

Dus dev, stage en elke niet-publieke host worden eenvoudigweg niet geïndexeerd door indexable niet te declareren. Stel het alleen in op de echte productie-entrypoint, waar je ook de echte host instelt:

phlo_app(
	id: 'Example',
	host: 'example.com',
	indexable: true,
);

Met indexable: true dient de resource een Allow: /, één Disallow: regel per invoer in %app->robotsDisallow, en een Sitemap: regel. Omdat robots.txt afkomstig is van de route, is er geen statische robots.txt die onderhouden of per ongeluk van een dev-host gedeployed moet worden.

17.5: Per-app en per-pagina overrides

De standaardinstellingen dekken de meeste apps. Overschrijf de rest met het cross-class injection idiom (zie het hoofdstuk Geavanceerd), dat de prop instelt tijdens de build-tijd:

prop %seo.twitterCard = true
prop %seo.ogType = 'article'
prop %seo.siteName = 'Example Co'

twitterCard kiest voor de Twitter samenvattingskaart, ogType overschrijft het Open Graph-type, en siteName overschrijft de sitenaam (standaard: %app->title, met als fallback de app-id).

Er worden twee opt-outs per verzoek gelezen uit de app props, zodat een enkele pagina uit de index kan worden gehaald zonder de rest van de site aan te raken:

Eigenschap Effect
%app->image De standaard Open Graph-afbeelding voor de hele app
%app->noIndex (of %app->noLink) Markeert de huidige pagina als noindex,follow en verwijdert de canonieke link

Stel %app->noIndex in een route in voordat je rendert om die ene pagina uit de zoekresultaten te houden terwijl de rest van de app indexeerbaar blijft.

We gebruiken essentiële cookies om deze site te laten werken. Met uw toestemming gebruiken we ook analytics om de site te verbeteren.