How to add hreflang tags in WordPress (the right way)

Updated Published 10 min read

In short

WordPress core does not output hreflang tags. You add them either by hooking into wp_head to print link rel="alternate" elements yourself, or — on any site with more than a handful of pages — by using a multilingual or translation plugin that generates a complete reciprocal set automatically for every page and language.

Key points

  • WordPress core has no hreflang support; nothing is emitted unless you add it or install a plugin that does.
  • The manual approach is a wp_head hook printing one link element per language version, including a self-reference and x-default.
  • Hand-maintained hreflang decays as soon as the site grows: pages multiplied by languages is the number of annotations you must keep reciprocal.
  • Verify after setup by loading a translated URL in a checker, then opening a referenced URL to confirm it points back.
  • Google Search Console's International Targeting report surfaces reciprocity errors on live sites over time.

If your WordPress site exists in more than one language, hreflang tags are how you tell search engines which version to serve which user. Get them right and German visitors land on your German pages; get them wrong and Google either guesses or ignores your annotations entirely.

Does WordPress add hreflang automatically?

No. WordPress core has no hreflang support of any kind. Installing WordPress in another language, or adding a language pack, changes the admin and theme strings — it does not create alternate URLs and it does not emit a single hreflang annotation. Core's own sitemaps do not carry alternate-language annotations either.

This surprises people because WordPress has genuinely good internationalization plumbing for interface strings, documented in the Plugin Handbook. But translating your theme's "Read more" button is a different problem from publishing your content in four languages at four URLs. hreflang belongs to the second problem, and you have to solve it yourself.

What you need before you start

hreflang annotates URLs, so you need the URLs first. Before adding a single tag, be able to answer:

  • What is the URL of each language version? Usually language-prefixed subdirectories: /de/about/, /fr/about/.
  • Which language codes are you using? ISO 639-1, optionally with an ISO 3166-1 Alpha 2 region — see the language-code reference.
  • What is your x-default? The page for visitors matching no specific version.

If you cannot list the URLs, you do not have a multilingual site yet — you have a plan for one. Start with making WordPress multilingual and come back.

The three rules that decide whether it works

1. Annotations must be reciprocal

If your English page links to the German page, the German page must link back. Google may ignore annotations that lack return links. In practice, every language version of a page carries the same complete set of hreflang tags, including a link to itself.

2. Use valid language and region codes

The value is an ISO 639-1 language code, optionally a hyphen and an ISO 3166-1 region: en, en-GB, pt-BR. Don't invent codes — the UK is en-GB, not en-UK — and never use a bare region code as if it were a language.

3. Always include x-default

Add an x-default entry pointing at your best neutral page for users who match none of your specific versions.

The complete hreflang explainer covers the reasoning behind each rule.

Option A: add hreflang manually with wp_head

For a small, fixed set of pages you can print the tags yourself. The standard approach is a function hooked to wp_head in your child theme's functions.php or a small site-specific plugin:

add_action( 'wp_head', function () {
  $alternates = [
    'en' => 'https://example.com/about/',
    'de' => 'https://example.com/de/about/',
    'fr' => 'https://example.com/fr/about/',
    'x-default' => 'https://example.com/about/',
  ];

  foreach ( $alternates as $lang => $url ) {
    printf(
      '<link rel="alternate" hreflang="%s" href="%s" />' . "\n",
      esc_attr( $lang ),
      esc_url( $url )
    );
  }
} );

Three things to note. The map includes the current page's own language — that is the required self-reference. Every URL is absolute and includes the protocol. And output is escaped with esc_attr() and esc_url(), which you should never skip when printing into markup.

The same block must appear on every language version of that page. For a page-by-page set of tags you can generate the markup with the free hreflang tag generator and paste it in.

Why manual breaks down

The example above hard-codes one page. A real site needs the map computed per request, which means a lookup table of every page in every language. The arithmetic is unkind: 50 pages in 4 languages is 200 annotation blocks that must all stay mutually consistent. Publish a page in English and forget to add it to the German set, and that set silently stops being reciprocal.

Manual hreflang is defensible for a landing page or a five-page brochure site. Past that, it is a maintenance liability.

Option B: let a plugin generate it

On any site with real content, hreflang should be generated from the same source of truth that produces the translated URLs. A translation plugin such as Gloty emits a reciprocal set with x-default, per-language self-referencing canonicals, and translated meta for every page — including WooCommerce products, categories, and archives — with no tags to maintain by hand.

Multilingual plugins including Polylang, WPML and MultilingualPress also generate hreflang from their own language configuration. The approaches differ substantially in how the translations get created — see the comparisons — but on hreflang specifically, any of them beats hand-maintained tags.

A warning about running two plugins

If you have an SEO plugin (Yoast, Rank Math) and a multilingual plugin, check whether both are emitting hreflang. Duplicate or conflicting annotations for the same page are worse than one clean set. View source on a translated page and count the rel="alternate" elements before assuming everything is fine.

How to verify hreflang is working

Adding the tags is the easy half. Verify in three steps:

  1. Inspect the markup. Load a translated URL in the free hreflang checker to see every annotation, whether x-default is present, and whether any code appears twice.
  2. Test reciprocity by hand. Take one URL from those results, open it, and confirm it points back at the page you started on. This is the check that catches the most common failure, and no amount of single-page inspection substitutes for it.
  3. Watch Search Console. Google Search Console's International Targeting report accumulates hreflang errors — missing return links, unknown language codes — from real crawls over time. It is the only one of the three that catches a set which broke last week.

Also confirm your canonicals: each language version should have a self-referencing canonical, not one pointing at the source-language page. A cross-language canonical contradicts your hreflang and is a common reason translations never get indexed.

Summary

  • WordPress core emits no hreflang — you add it manually or via a plugin.
  • Manual means a wp_head hook printing an escaped, absolute, self-referencing set including x-default.
  • Annotations must be reciprocal and use valid codes, or they may be ignored outright.
  • Hand-maintenance stops being viable roughly where pages × languages exceeds what you can hold in your head.
  • Verify with a checker, confirm reciprocity by opening a referenced URL, and keep an eye on Search Console.

Sources

Technical claims in this guide are drawn from the primary documentation and specifications below, each confirmed live on the date shown.

  1. Tell Google about localized versions of your page Google Search Central. Accessed .
  2. How to specify a canonical URL with rel="canonical" and other methods Google Search Central. Accessed .
  3. Internationalization — Plugin Handbook WordPress Developer Resources. Accessed .
  4. How to Internationalize Your Plugin WordPress Developer Resources. Accessed .
  5. RFC 5646 — Tags for Identifying Languages (BCP 47) IETF. Accessed .

FAQ

Does WordPress add hreflang tags automatically?
No. WordPress core has no hreflang support, and core sitemaps do not include alternate-language annotations. Installing a language pack localises the interface but creates no alternate URLs. You add hreflang manually or via a multilingual/translation plugin.
Where do hreflang tags go in WordPress?
In the head of every language version of a page, normally printed by a function hooked to wp_head. Each version carries the same complete, reciprocal set — including a self-reference and x-default.
Can I add hreflang without a plugin?
Yes. Hook a function to wp_head that prints one link rel="alternate" element per language version, with absolute escaped URLs. This is practical for a handful of fixed pages; it becomes unmanageable once pages multiplied by languages grows, which is why most real sites delegate it to a plugin.
Do Yoast or Rank Math add hreflang tags?
Not on their own — they generate hreflang from a multilingual plugin's language data rather than inventing language versions. If you run both an SEO plugin and a multilingual plugin, check the page source for duplicate rel="alternate" elements, because two sets of conflicting annotations are worse than one clean set.
How do I check my hreflang tags are correct?
Load a translated URL in an hreflang checker to inspect the annotations, then open one of the URLs it lists and confirm it references your original page back — that is the reciprocity test. Finally, monitor Google Search Console's International Targeting report, which reports errors from real crawls over time.

Gloty makes WordPress multilingual automatically — AI translation, hreflang, and clean URLs, stored in your own database.

Try Gloty free
Go multilingual free
Open source · your data stays yours
Start free