Skip Navigation
Updated
October 16, 2024

Follow our step-by-step guide for making your plugins and themes compatible with WPML.

This guide is intended for theme and plugin authors who have already joined our compatibility program – Go Global. If you haven’t joined yet, please submit your application before following this guide. 

How to Become WPML Compatible

1. Create a Language Configuration File

A language configuration file tells WPML what texts to translate (and which not to) in your plugin or theme. This includes texts in custom post types, taxonomies, fields, admin screens, widgets, and more. 

If you already know how to create a language configuration file, follow the instructions below to test your setup. Otherwise, see our language configuration guide to learn how to create one.

Test Setup
1. Create a few posts and taxonomies
2. Send them for translation
3. Verify they appear translated on the front end

2. Prepare Strings for Translation

Strings are any texts that appear on the site and aren’t part of posts, pages, or taxonomies. To let WPML translate strings in your plugin or theme, follow the instructions below for each use case. 

As you configure your strings, use the Multilingual Tools Plugin to verify which strings are translatable, and which need additional configuration. 

Hard-Coded Strings

Hard-coded strings need to be registered with gettext functions. To learn more about using gettext, see our Gettext Guide.

Strings in wp_options

If your plugin or theme uses strings from the wp_options table, register them in the wpml-config.xml file. 

If your option keys aren’t fixed, and your theme uses an array of entries which may grow with user input, register these entries dynamically. You can use WPML’s API functions to do this.

Dynamic Strings

If none of the previous methods apply to your strings, follow these guides to prepare strings for translation: 

Test Setup
1. Scan your plugin / theme for strings in WPML Theme and Plugin Localization 
2. Create a page with strings
3. Check if the strings appear in String Translation
4. Translate a few strings and verify they appear translated on the front end

3. Register Custom Widgets and Blocks for Translation

If your theme or plugin includes custom widgets for page builders, like Elementor, you need to register them for translation.

See the following guides to learn more about registering page builder content: 

Test Setup
1. Create a page with all your custom widgets
2. Send the page for translation and verify widget texts appear in the Advanced Translation Editor
3. Check that translations display on the front-end
4. Repeat steps to test different widget settings

4. Automatically Fetch IDs From Different Languages

If your theme or plugin has features or options that load different post IDs in each language, use the wpml_object_id filter to automatically fetch the translated post ID. 

For example, consider a slider with slides in different languages, each with a unique ID. To automatically load the correct slide ID in each language, we can use the wpml_object_id filter:

// Loop posts
while (have_posts()): the_post();
$post = get_post( apply_filters( 'wpml_object_id', $post->ID, 'slide' ) );

Test Setup
1. Create the relevant post / template, etc., and add a text string
2. Set your feature to use that post
3. Translate the post and set a different value in the text string
4. Check the feature is loading the translated ID on the front-end

5. Become WooCommerce Compatible

WPML can translate WooCommerce content with its WooCommerce Multilingual addon. If your theme or plugin contains WooCommerce elements, follow our WooCommerce Multilingual compatibility guide to make it compatible with WPML.

6. Show or Hide The Admin Language Switcher

By default, WPML adds a language switcher to the WordPress admin bar. This switcher is visible to logged in users, both on the frontend and backend. 

Language switcher in the top admin bar
Language switcher in the top admin bar

In some cases, you may want to hide the language switcher on sensitive pages, like your settings area. To do this, add the following code to your functions.php file: 

//Make sure to rename the function before adding to your plugin
add_filter( 'wpml_show_admin_language_switcher', 'compsupp_disable_wpml_admin_lang_switcher' );
 
function compsupp_disable_wpml_admin_lang_switcher( $state ) {
    global $pagenow;
 
    // Add the admin pages that we need to hide the language switcher
    $admin_pages_to_hide_ls = array(
        'admin-page-slug', 'another-admin-page-slug', 'one-more-admin-page-slug'
    );
 
    // We can also have a filter here in case we need to add/remove pages later
    $admin_pages_to_hide_ls = apply_filters( 'compsupp_filter_disable_wpml_lang_switcher_in_admin', $admin_pages_to_hide_ls);
     
    if (
        $pagenow == 'admin.php'
        && isset( $_GET['page'] )
        && in_array( $_GET['page'], $admin_pages_to_hide_ls)
    ) {
        $state = false;
    }
    return $state;
}

Making Special Features Compatible

If your theme or plugin includes special features (like using custom tables) you’ll need to use custom code to make them compatible with WPML. 

See our developer resources for information about custom development. 

Common Problems & Solutions

Solution:

$label = esc_html( apply_filters('wpml_translate_single_string', $this->checkout_item->name, 'wpsc', '$this->checkout_item->name .'_checkout_form_label'' ) );

Solution:

If you use wp_query($args) or get_posts($args) you need to add “suppress_filters=0” to arguments.

Solution:

// Unset not translated slides
foreach( $slides as $k => $slide ) {
	$check = apply_filters( 'wpml_post_language_details', NULL, $slide->ID )
	$slide_language_code = substr( $check['locale'], 0, 2 );

	if( $check['different_language'] ) {
		unset( $slides[$k] );
	}
}

Solution:

// Loop posts
while (have_posts()): the_post();
$post = get_post( apply_filters( 'wpml_object_id', $post->ID, 'slide' ) );

Solution:

// Adding a new slide code
$slide_id = $this->slide->ID;
$url = $fields['url'];

// Register slide URL to translations
do_action( 'wpml_register_single_string', 'Slider', 'Slide_ID_' . $this->slide->ID, $url);

$this->add_or_update_or_delete_meta($this->slide->ID, 'url', $url);

Solution:

$taxonomy_id = apply_filters( 'wpml_object_id', $taxonomy_id, 'my_custom_taxonomy' );

Solution:

When building custom AJAX URLs, use the wpml_current_language hook and add the current language as a parameter for the AJAX URLs.

$ajax_url = 'http://my-site.com/wp-content/plugins/my-plugin/handle-ajax.php';
$my_current_lang = apply_filters( 'wpml_current_language', NULL ); 
if ( $my_current_lang ) {
	$ajax_url = add_query_arg( 'wpml_lang', $my_current_lang, $ajax_url );
	// $ajax_url will be something like 'http://my-site.com/wp-content/plugins/my-plugin/handle-ajax.php?wpml_lang=es'
}

When handling AJAX requests at the handle-ajax.php file, before generating the content output, use the wpml_switch_language hook to switch the content language.

if ( isset( $_GET[ 'wpml_lang' ] ) ) {
    do_action( 'wpml_switch_language',  $_GET[ 'wpml_lang' ] ); // switch the content language
}

// Run other content queries. 

Solution:

Using the “id” argument for the “field” parameter works for the default language but it does not work for the second language. The following is an example of an incorrect query:

$args = array(
    'post_type' => 'post',
    'tax_query' => array(
        array(
            'taxonomy' => 'people',
            'field'    => 'id',
            'terms'    => 'bob',
        ),
    ),
);
$query = new WP_Query( $args );

Developers should correct the “field” parameter.

'field'    => 'id',

to:

'field'    => 'term_id',

Reference: https://codex.wordpress.org/Class_Reference/WP_Query#Taxonomy_Parameters. There is no value “id” for the “field” parameter. Its default value is “term_id”.