---
title: "SEO - Hreflang, Schema and Sitemaps - PerfLocale"
description: "Hreflang, sitemap alternates, JSON-LD schema, Content-Language header, fallback nosnippet guard, Speculation Rules, and View Transitions."
canonical: "https://perflocale.com/docs/seo/"
source: "https://perflocale.com/docs/seo/"
format: "markdown"
---
# SEO

PerfLocale ships a full modern-SEO stack designed specifically for multilingual sites. Hreflang, sitemap alternates, schema enrichment, the Content-Language header, and the fallback nosnippet guard are on by default; the two experimental features — Speculation Rules prerender and View Transitions — are opt-in and disabled out of the box to keep the plugin lightweight. Configure all of it at **Settings → SEO**.

## Hreflang alternates

Every frontend page automatically emits `<link rel="alternate" hreflang="...">` tags for every translation that exists, plus `hreflang="x-default"` pointing at the default-language version. Generated from the translation group and cached per-request. The supported SEO plugins (Yoast, Rank Math, AIOSEO, SEOPress, Slim SEO, The SEO Framework) don’t emit head-stage hreflang of their own, so there is never a second set fighting PerfLocale’s. Nothing to configure.

Tag values use canonical BCP 47 form — lowercase language + UPPERCASE region (`en-US`, `en-GB`, `de-DE`, `pt-BR`). The HTML5 spec is case-insensitive at match time, but every reference site, SEO validator, and Google Search Central example uses the canonical form, and lowercase region codes (`en-us`) trigger soft warnings in Screaming Frog and Ahrefs Site Audit. The same canonical form is used across the `<html lang>` attribute, the `Content-Language` response header, JSON-LD `inLanguage`, sitemap alternates, and the REST API `hreflang` field, so all surfaces agree.

### Coexistence with SEO plugins

PerfLocale registers **no hreflang-suppression filters** against the supported SEO plugins, because none of them emit head- or header-stage hreflang natively for it to collide with:

-   **Yoast SEO** — has never output hreflang; it defers to the multilingual plugin.
-   **Rank Math** — only emits hreflang through a multilingual integration, which PerfLocale is not registered as.
-   **AIOSEO 4.x** — emits none in the head or headers; only in its sitemap, which is exactly where PerfLocale wants alternates to appear.
-   **SEOPress, Slim SEO, The SEO Framework** — the addons register only sitemap-stage alternates; head-stage hreflang is left to PerfLocale.

Earlier builds did call `wpseo_output_hreflang`, `rank_math/frontend/disable_hreflang` and `aioseo_conflicting_shortcodes` defensively. Those calls were removed: the first two gate hooks no current version of either plugin fires, and the AIOSEO one was actively harmful — it force-executed every shortcode during meta and sitemap generation.

PerfLocale’s own hreflang HTTP `Link` header is emitted at `send_headers` priority 1, so its headers land before any other plugin’s on the same hook.

If you want to keep the SEO plugin’s hreflang and disable PerfLocale’s, toggle _Hreflang Tags_ off at **Settings → SEO**.

## Sitemap alternates

PerfLocale hooks into WordPress core’s XML sitemap and attaches `<xhtml:link rel="alternate">` entries for translations of every listed URL. If your SEO plugin supplies the sitemap instead, PerfLocale detects that and integrates via its extension point rather than emitting a competing sitemap. No setup needed.

### Choosing the sitemap source

The `seo_sitemap_source` setting selects which sitemap tree carries the `xhtml:link` alternates when both WP core and an SEO plugin’s native sitemap could serve them. It has no field on the Settings screen — the default (`auto`) is right for almost every site; override it with the `perflocale/sitemap/inject_into_core` filter below, or write the key directly with `wp option patch update perflocale_settings seo_sitemap_source core`:

-   **`auto`** (default) — if a supported SEO plugin (Yoast, Rank Math, AIOSEO) is detected, PerfLocale skips the WP core sitemap injection. The SEO plugin’s own sitemap receives the alternates via the per-addon integration. This is the right answer for almost every site.
-   **`core`** — always inject into the WP core sitemap, even when an SEO plugin is active. Use this if your SEO plugin’s native sitemap is disabled in its own settings and the core sitemap is the only one being served.
-   **`plugin`** — never inject into the WP core sitemap. Use this if you serve a custom or third-party sitemap that PerfLocale doesn’t auto-detect and you want to handle alternates exclusively through it.

For unusual setups, override the auto-detection programmatically with the `[perflocale/sitemap/inject_into_core](https://perflocale.com/docs/hooks/#perflocale-sitemap-inject-into-core)` filter.

Independent of the source choice, the three SEO sitemap addons (Yoast, Rank Math, AIOSEO) register their entry-capture filters at `PHP_INT_MAX` so third-party URL-rewriting plugins between priorities 10–999 (canonical-URL plugins, CDN rewriters, etc.) can no longer break PerfLocale’s URL-keyed lookup and silently emit alternates pointing at pre-rewrite URLs.

## JSON-LD Schema Enrichment

Adds two small pieces of structured data to whatever JSON-LD your SEO plugin is already emitting: `inLanguage` (the current page’s language, BCP-47 normalised) and `workTranslation` (array of URLs pointing at sibling translations). Helps Google surface the right language in search results and lets AI crawlers understand your site’s structure. On by default. See [SEO Schema Enrichment](https://perflocale.com/docs/seo-schema/) for the deep-dive.

## Content-Language header

Emits the W3C-standard `Content-Language` HTTP response header on every frontend request, BCP-47 normalised (`de_DE` → `de-DE`). Honoured by Google, Yandex, CDN layers, and some assistive tech in addition to the `<html lang>` attribute. On by default; filter `perflocale/content_language/value` customises the value.

## data-nosnippet fallback guard

When the Missing Translation Action is set to _Show default language_, a visitor to `/de/mypost/` might see the English content. Without protection, Google indexes that English text under the `/de/` URL and shows English snippets in German SERPs. PerfLocale wraps the fallback content with `<div data-nosnippet>` so Google keeps the URL indexed but omits the mismatched snippet. Only activates when fallback is actually happening. On by default.

## Speculation Rules prerender

When a visitor hovers a language-switcher link, Chromium prerenders the target translation in the background so clicking it feels instant. On WP 6.8+, integrates with Core’s native Speculation Rules API (our rule lands inside Core’s single output script); on older WP, emits a standalone script. Moderate eagerness - prerenders fire only on hover/focus, so visitors who never interact with the switcher never trigger a fetch. Disabled by default.

## View Transitions

Smooth 240 ms crossfade between languages using the cross-document [View Transitions API](https://developer.mozilla.org/en-US/docs/Web/API/View_Transition_API) (Chrome 126+, Safari 18.2+). Progressive enhancement - unsupported browsers navigate normally. The emitted CSS respects `prefers-reduced-motion`, zeroing the animation for users with that OS preference (WCAG 2.1 SC 2.3.3). Disabled by default; enable when your theme doesn’t run its own on-navigation animations.

## Related

-   [SEO Schema Enrichment](https://perflocale.com/docs/seo-schema/) - JSON-LD details.
-   [Hooks Reference](https://perflocale.com/docs/hooks/) - every SEO feature is filterable.
-   [Language Fallbacks](https://perflocale.com/docs/language-fallbacks/) - fallback SEO tradeoffs.

[← Back to Docs](https://perflocale.com/docs/)
