WordPress Plugins

WPML: The Complete Guide to a Multilingual WordPress Site

WPML lets you translate every part of your WordPress site into any language. This complete guide covers setup, translation workflows, dev hooks, and real-world tips.

WPML: The Complete Guide to a Multilingual WordPress Site review on GPL Times

WPML is the plugin that turns a single WordPress install into a fully translated, multilingual site. It handles everything from URL structure and language switchers to translation workflows and WooCommerce product pages across 65+ languages, out of the box.

If you’ve ever tried to go multilingual with WordPress and ended up in a tangle of duplicate sites or manual hacks, this guide is for you. I’ll walk through how WPML works, how to set it up, how to use its translation management system, and (for developers) how to integrate with its hooks and filters.

Table of Contents

What is WPML?

WPML (WordPress Multilingual Plugin) is a premium plugin developed by OnTheGoSystems. It’s been around since 2008, which makes it one of the oldest and most battle-tested solutions in the WordPress ecosystem. The official WPML documentation covers the full API surface; this guide focuses on getting you productive quickly. The core plugin is called "WPML Multilingual CMS" and it handles the translation scaffolding for posts, pages, custom post types, taxonomies, menus, widgets, and theme strings.

What sets WPML apart from free alternatives like Polylang is the depth of its translation management system. You can translate content manually (typing translations yourself in the WordPress editor), use WPML’s built-in Translation Editor with automatic translation powered by DeepL, Google Translate, or Amazon Translate, or send content to professional translators, all from within the same interface.

WPML stores translations in its own database tables rather than duplicating posts under the same post type. Each translatable element gets a Translation ID (trid) that groups all language versions together. This means your URL structure, canonical tags, and hreflang links are all managed automatically.

Key features

  • 65+ languages out of the box. Add any language from the built-in list or define a custom one. Right-to-left languages (Arabic, Hebrew, Persian) are supported.
  • Flexible URL structure. Run languages as subdirectories (/es/), subdomains (es.example.com), or separate domains (example.es), or use a query parameter (?lang=es).
  • Multiple translation modes. Choose "Translate Everything" to queue all new content automatically, "Translate Some" for selective translation, or "Display All Languages" to show untranslated content in the default language.
  • Automatic translation credits. WPML’s ATE (Advanced Translation Editor) connects to DeepL, Google Translate, and Amazon Translate. You buy translation credits and machine-translate in bulk, then review and publish.
  • Translation Management Dashboard. Assign content to translators (external contractors or team members), track status, and manage delivery, without leaving WordPress admin.
  • String Translation add-on. Translates theme and plugin strings that don’t live in posts: navigation labels, widget titles, footer text, email subjects, anything registered with icl_register_string().
  • Media Translation add-on. Attach language-specific images to posts. Useful when your images contain text (infographics, banners).
  • WooCommerce Multilingual add-on. Translates products, product categories, attributes, and checkout emails. Also handles per-currency pricing per language.
  • Language switcher. Fully customizable widget, menu item, shortcode, or footer bar. Shows flags, native language names, or both.
  • Elementor, Divi, Bricks compatibility. WPML ships with built-in translation configs for major page builders so custom modules and widgets get translated properly.

How WPML works

Under the hood, WPML intercepts WordPress’s content queries and rewrites them based on the active language. When a visitor loads /es/about/, WPML resolves the language as Spanish, fetches the translated post that corresponds to the original "About" page, and returns it. If no Spanish version exists, the behavior depends on the translation mode you’ve chosen. It either shows the original or skips the post entirely.

The core database table is icl_translations. Every translatable element (post, page, category, custom field group) gets a row here that maps its element_id (post ID / term ID) to a language code and a shared trid (Translation ID). All language variants of the same content share the same trid, so WPML always knows which Spanish post corresponds to which English original.

Language resolution happens early, at init. Once WPML determines the active language, it sets the constant ICL_LANGUAGE_CODE and the global language state. From that point, WordPress’s standard functions (get_permalink(), get_the_title(), WP_Query, get_terms()) return results in the current language automatically.

For URL routing:

  • Directory mode (default): /es/about/ (cleanest for SEO, easiest to set up), easiest to set up
  • Subdomain mode: es.example.com/about/ (requires wildcard DNS)
  • Different domain: example.es/about/ (full domain separation, requires server config)
  • Query parameter: example.com/about/?lang=es (not recommended for SEO)

WPML also outputs <link rel="alternate" hreflang="..."> tags automatically for each active language, which is critical for telling Google which version to index for which locale. Google’s own multilingual site guidance explains the full spec if you want to go deeper.

Installation and setup

Step 1: Install the plugin. Upload and activate the WPML Multilingual CMS plugin. On first activation, the Setup Wizard launches automatically.

Step 2: Run the Setup Wizard. The wizard walks through:

  • Selecting your site’s primary language
  • Choosing which languages to add
  • Selecting a URL structure (directory / subdomain / domain / parameter)
  • Choosing a language switcher style and placement (header, footer, navigation)
  • Selecting which post types and taxonomies to make translatable

Once registered, automatic translation credits become available.

Step 4: Install companion add-ons. The core plugin handles content translation. For theme strings, install WPML String Translation. For WooCommerce, install WooCommerce Multilingual. You don’t need to activate add-ons you don’t use.

Step 5: Configure translatable types. Go to WPML > Settings and scroll to "Post Types Translation" and "Taxonomies Translation." Check every type you want to translate. Custom post types from third-party plugins appear here automatically once WPML detects them.

Step 6: Translate menus. Go to Appearance > Menus, select a language in the top-right language switcher, and build the translated version. Or in WPML > Theme and Plugins Localization, set menus to "Translated" so WPML creates a linked translation of each menu automatically.

Translating your content

There are three ways to translate content with WPML, and you’ll probably end up using all three depending on the content type.

The Classic Translation Editor. Click the language flag next to any post in the post list (or the language box in the post editor sidebar). This opens a side-by-side editor showing the original on the left and an empty translation field on the right. Translate field by field. Straightforward, works with any post type.

The Advanced Translation Editor (ATE). A more capable translation interface that opens in a new tab. It shows all translatable strings from the post in a structured list: title, excerpt, custom fields, and blocks. Fill translations one by one. It also you fill translations one by one.

Translation Management. In WPML > Translation Management, you select posts (one or many), set the target languages, and send them as translation jobs. If you’ve set up external translators (via Translation Proxy or the WPML Marketplace), the job goes to them. Otherwise it stays in the queue for you or a team member to pick up. This workflow is designed for sites managing dozens of languages and hundreds of pieces of content.

For short theme strings (a button label,, a form placeholder, a widget title) you’ll use WPML > String Translation (requires the String Translation add-on). Strings are registered by plugins and themes at runtime; once they appear in the String Translation screen, you translate them language by language directly in the admin.

Language switcher options

WPML gives you four places to add a language switcher, and you can use as many simultaneously as you want.

Shortcode. Drop [wpml_language_switcher] anywhere in a post, page, or widget text. Accepts arguments to control which flags to show, whether to include the current language, and the display style:

[wpml_language_switcher type="list" flags="0" native="1" translated="1"]

Widget. Add the "WPML Language Switcher" widget to any sidebar. Customizable in the widget panel.

Navigation menu. In Appearance > Menus, add "Language Switcher" from the available menu items on the left. This inserts an inline language dropdown or list into any registered menu location.

Footer bar. Configure in WPML > Languages > Footer Language Selector. A thin bar at the bottom of every page, flags or text.

The switcher appearance is controlled in WPML > Languages > Language Switcher Options. You can show flags, native-language names, translated names, or all three. You can also hide specific languages from the public switcher while keeping them active (useful for staging a new language).

Real-world use cases

Tourism company with regional sites. A travel agency running a single WordPress install serves visitors in English, Spanish, French, and German. WPML serves each language at /en/, /es/, /fr/, /de/. Same CMS, translated posts, separate menus, and localized contact form labels. Google indexes all four versions with proper hreflang so the right version ranks in each country.

SaaS startup going international. A plugin company translating its marketing site uses the Translation Management Dashboard to send all landing pages to professional translators on a per-language basis. New blog posts get machine-translated via ATE, reviewed by a junior editor, then published. The String Translation add-on handles their newsletter signup widget text and footer copy.

WooCommerce store with per-currency pricing. An online retailer sells in English (USD) and Japanese (JPY). With WPML + WooCommerce Multilingual, product names and descriptions are translated, product images swapped for locale-specific versions via Media Translation, and prices set per currency. Checkout emails also go out in the buyer’s language.

Multilingual learning management system. An e-learning platform built with LearnDash delivers courses in four languages. WPML handles course and lesson translation. The String Translation add-on localizes the quiz UI strings. The language switcher sits in the header so students can toggle mid-session.

WordPress network with localized blogs. A publishing group uses a single WP install with WPML’s "Different Domain" URL mode to run region-specific news sites (example.de, example.fr), all managed from one admin panel with shared plugins and a shared theme.

WPML and WooCommerce

WooCommerce support is one of the most common reasons people reach for WPML over lighter multilingual solutions. The WooCommerce Multilingual add-on (free from the WPML site, separate plugin) handles:

  • Product translation. Name, description, short description, and attributes translate per language. Product variation labels translate separately.
  • Product category and tag translation. Category pages get their own translated slugs (/es/categoria/camisetas/ instead of /es/category/t-shirts/).
  • Multi-currency. Set different prices per currency per language. Handles exchange rates, price formatting, and currency display in the cart and at checkout.
  • Checkout and order emails. Checkout text, "My Account" strings, and order confirmation emails all go to the buyer in their browsing language. Requires String Translation.
  • Payment gateway compatibility. Standard WooCommerce gateways (Stripe, PayPal) work fine. WPML doesn’t intercept payment processing.

One thing to be aware of: each translated product is a separate post in WordPress (linked via trid), so orders for the Spanish product and orders for the English product both map to the same WooCommerce product inventory. Stock is shared automatically across language versions.

Developer reference

WPML exposes a large surface area of hooks and filters. Here are the most useful ones for theme and plugin authors.

Getting and setting the current language

// Read the current language (returns 'en', 'es', 'fr', etc.)
$lang = apply_filters( 'wpml_current_language', null );

// Read the default language
$default = apply_filters( 'wpml_default_language', null );

// Get all active languages with details
$languages = apply_filters( 'wpml_active_languages', null, [
 'skip_missing' => 0,
 'orderby' => 'code',
 'order' => 'ASC',
] );
// $languages is an array keyed by language code with 'name', 'translated_name',
// 'flag_url', 'url', 'active' fields

Translating a string registered via WPML

// Translate a string that was registered with icl_register_string()
$translated = apply_filters( 'wpml_translate_single_string', $original, 'my-plugin', 'My String Name' );

Getting the translated version of a post

// Get the post ID of the Spanish translation of post 42
$translated_id = apply_filters( 'wpml_object_id', 42, 'post', true, 'es' );
// Third arg: return original if translation missing (true) or false/null

Checking if a post has translations

$has_translations = apply_filters( 'wpml_element_has_translations', null, $post_id, 'post' );

Switching language context programmatically

// Switch to Spanish for a query, then restore
do_action( 'wpml_switch_language', 'es' );
$posts = get_posts( [ 'post_type' => 'product', 'posts_per_page' => 10 ] );
do_action( 'wpml_switch_language', null ); // restore original language

Registering a string for translation (from code)

// Register a string so it appears in WPML > String Translation
do_action( 'wpml_register_single_string', 'my-plugin', 'Button label', __( 'Buy Now', 'my-plugin' ) );

Hooking into post save

// Fires after a post and its translation data are saved
add_action( 'wpml_after_save_post', function( $original_post_id, $original_post, $translations ) {
 // $translations: array of [ 'lang' => 'es', 'post_id' => 567 ]
 foreach ( $translations as $translation ) {
 // do something with each translated version
 }
}, 10, 3 );

Controlling which post types are translatable

// Add a custom post type to WPML's translatable list programmatically
add_filter( 'wpml_translatable_documents', function( $post_types ) {
 $post_types['my_cpt'] = (object) [ 'labels' => (object) [ 'name' => 'My CPT' ] ];
 return $post_types;
} );

Filtering hreflang output

// Add or remove language from hreflang links in <head>
add_filter( 'wpml_alternate_hreflang', function( $languages ) {
 // $languages is an array of [ 'hreflang' => 'de', 'href' => '...' ]
 // Remove a language from hreflang without deactivating it
 return array_filter( $languages, fn( $l ) => $l['hreflang'] !== 'x-default' );
} );

Controlling custom field duplication

// Prevent a specific meta key from being copied when duplicating a post
add_filter( 'wpml_duplicate_custom_fields_exceptions', function( $fields ) {
 $fields[] = '_my_private_key';
 return $fields;
} );

WP-CLI

# Clear WPML's internal cache from the command line
wp wpml clear-cache

Language switcher shortcodes

// Drop a language switcher inline
[wpml_language_switcher]

// Add a hidden language field to any form so submissions carry the language
[wpml_language_form_field]

Working with the icl_register_string() legacy API

Some older integrations still use the direct function rather than the filter-based approach. Both work:

// Legacy
icl_register_string( 'my-plugin', 'Footer copyright', 'All rights reserved.' );

// Modern filter-based
do_action( 'wpml_register_single_string', 'my-plugin', 'Footer copyright', 'All rights reserved.' );

Use the action-based version in new code. It doesn’t create a hard dependency on WPML being present.

Performance, compatibility, and gotchas

Database overhead. Every translatable item creates multiple rows in icl_translations and other WPML tables. On a very large site (50k+ posts) with several languages, the translation tables can grow substantially. WPML’s queries are indexed, but you’ll want to watch query counts in a profiler if you’re adding languages to an existing large site.

Caching. WPML works with all major caching plugins (WP Rocket, LiteSpeed Cache, W3 Total Cache) but needs cache to be cleared per-language on post update. Most caching plugins handle this automatically when they detect WPML. If you’re seeing stale content after translation, a manual cache purge usually fixes it.

URL structure migration. Changing the URL structure (e.g., from directory to subdomain) after you’ve indexed content is risky. It changes every URL on your site. WPML handles the internal redirect chain, but you’ll need to update external links, social profiles, and inform Google via Search Console.

Page builders. WPML ships built-in compatibility configs for Elementor, Divi, Bricks, Beaver Builder, Cornerstone, and others. These configs tell WPML which widget fields contain translatable text. If you’re using a niche or custom page builder, you may need to manually define field mappings in WPML > Theme and Plugins Localization or via a wpml-config.xml file.

The wpml-config.xml file. If you’re building a theme or plugin you want to be WPML-compatible, you can ship a wpml-config.xml in your plugin root. This file declares which custom fields, post meta, and Gutenberg block attributes WPML should translate. No hooks required. WPML reads the config file on activation. OnTheGoSystems maintains the wpml-config.xml specification with full examples.

Automatic translation limits. WPML’s machine translation is credit-based. Running out of credits mid-publish doesn’t break the site; content just stays in the original language until credits are replenished or you translate manually.

Compatibility with Yoast and Rank Math. WPML plays well with both major SEO plugins. Yoast SEO Premium and Rank Math SEO Pro both have WPML compatibility built in. Meta title, meta description, and OG tags are stored per-language and can each be translated independently.

Gutenberg and block content. WPML translates block content at the field level, not the raw HTML level. This means each block’s text fields are extracted and shown in the Translation Editor individually. The wpml_update_strings_in_block filter lets you hook into this if you’re building custom blocks.

Pricing and licensing

WPML uses a subscription model: the Multilingual Blog plan (posts/pages, basic features), the Multilingual CMS plan (full access including custom post types, WooCommerce, String Translation), and an Agency plan for unlimited sites. All plans include one year of updates and support.

The core plugin and most companion add-ons are GPL-licensed. You can get the full WPML Multilingual CMS build (including companion add-ons like String Translation and WooCommerce Multilingual) from GPL Times. This is the same plugin, same code, GPL-distributed.

FAQ

Does WPML work with custom post types?
Yes. Any registered post type shows up in WPML’s translation settings. Just check it in WPML > Settings > Post Types Translation, and from that point WPML tracks translation status for every post in that type.

Can I use WPML without the String Translation add-on?
You can, but you’ll only be able to translate post content. Theme strings, plugin strings, widget titles, and email text won’t be translatable until you add WPML String Translation.

Does WPML create separate posts for each language?
Yes and no. WPML stores translations as separate WordPress posts internally (each with its own ID), but they’re linked via a shared Translation ID (trid) in WPML’s database tables. From a user’s perspective, you manage all languages from the same original post.

Will WPML slow down my site?
On a typical WordPress site, the overhead is small: a handful of extra queries per page load. On very large sites with many languages, the impact is more noticeable. Use object caching (Redis or Memcached) and a page cache plugin to keep response times fast.

Can I switch between translation modes later?
Yes. You can change the "Translation mode" in WPML > Translation Management > Multilingual Content Setup at any time. Switching from "Translate Some" to "Translate Everything" doesn’t retroactively queue already-published posts. It only applies to new content going forward.

How does WPML handle menus?
Each menu can have a separate translated version per language. WPML lets you link translated menus to their originals so they share the same location. Menu items that point to translatable pages automatically redirect to the translated page when the language is active.

Is there a free alternative to WPML?
Polylang has a free version with similar URL and language-switcher features. The paid Polylang Pro adds WooCommerce and ACF support. TranslatePress is another alternative with a front-end translation interface. WPML’s advantages are its Translation Management Dashboard, automatic translation credits, and deeper page builder support.

Does WPML work with multisite?
Yes, WPML has specific multisite support. In a network setup, you can configure WPML at the network level or per subsite. The "Different Domain" URL mode maps naturally to multisite’s domain mapping.

Final thoughts

WPML is the kind of plugin that reveals its value gradually. The basic setup takes an hour; the language switcher is live, posts are translating, and everything works. Then you start hitting the edge cases: product catalog translations, menu localization, SEO meta per language, custom field duplication rules. WPML has a feature or a hook for each one.

It’s not the cheapest multilingual option, and the add-on ecosystem means the full feature set requires multiple plugins. But for anyone running a serious multilingual operation on WordPress, the breadth of what WPML covers is hard to beat. The Translation Management Dashboard alone is worth it if you’re working with a team or sending content to external translators.

Set up a staging environment, run through the wizard, and translate a few pages. That’s the fastest way to know if it fits your workflow.