Skip to content

fix(seo): sitemap-[lang].xml emits doubled locale prefix and broken hreflang #54

@JohnRDOrazio

Description

@JohnRDOrazio

Symptom

app/api/sitemap/[lang]/route.ts emits malformed URLs and incorrect hreflang alternates for any locale that has Polylang-translated pages (currently affects all non-English).

For an Italian translated page like governance-2/governanza-del-progetto:

  • <loc> becomes https://catholicdigitalcommons.org/it/it/governance-2/governanza-del-progetto (doubled locale).
  • The <xhtml:link rel="alternate" hreflang="en" ...> is built from the same Italian-prefixed URI, so the English alternate also points to a non-existent IT URL.

Root cause

In app/api/sitemap/[lang]/route.ts:

function buildUrl(locale: string, path: string): string {
  const prefix = localePrefix(locale)
  // ...
  return `${baseUrl}${prefix}${cleanPath}`
}

for (const page of pages) {
  const uri = page.uri === '/' ? '/' : page.uri
  // ...
  entries.push(urlEntry(buildUrl(lang, uri), ..., uri))
}

page.uri from getAllPages(lang) already includes the Polylang language prefix (/it/...) in directory mode. buildUrl then prepends the prefix again. And buildAlternateLinks(uri) reuses that locale-specific URI for every hreflang, so English/Spanish/etc. alternates all point at the IT URL.

Suggested fix

Fetch and use slug (or a parent-slug chain) from WP instead of uri — same fix shape as #53. Then buildUrl(lang, '/governance-2/governanza-del-progetto') produces the right result. For hreflang alternates, you need the per-locale path (each language has its own translated slug), so either:

  • query pages once per locale and build a translation map keyed by canonical post ID, or
  • include translations { language { slug } slug } in the GraphQL query so a single fetch per locale carries all hreflang variants.

Notes

  • GET_ALL_PAGES in lib/wordpress/queries.ts:418 returns slug and uri; only slug is needed once this is fixed.
  • This affects every non-English sitemap and degrades multilingual SEO. Worth fixing before more languages are added.

Related

Same page.uri misuse as #53.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions