WPML: remember user’s language choice

There is no built-in function to remember a user’s language choice in WPML, and redirect him accordingly. WPML can only redirect returning visitors according to their browser language. I figured out a way to store the user’s language choice, and redirect the user to his preferred language when he revisits your website.

There are 3 main steps:

  1. Add ?switch_lang=nl to your WPML language switcher
  2. Store the language in a cookie when the user chooses his language
  3. Redirect the user to his chosen language when certain conditions are met

1. Add ?switch_lang={lang} to your WPML language switcher

We need to append ?switch_lang={lang} to each url in WPML’s language switcher. We rely on the switch_lang variable for two reasons:

  1. In the next step, we will intercept requests with this variable
  2. WP Rocket and other caching plugins will not cache requests with query strings

You can rename switch_lang to any string you want, just make sure to replace the string in the next step as well.

/**
 * Add ?switch_lang=lang to all url's in the languaqe switcher
 */
add_filter( 'icl_ls_languages', function( $languages ){
    global $sitepress;
    foreach( $languages as $lang_code => $language ){
        $languages[$lang_code]['url'] = add_query_arg( array( 'switch_language' => $lang_code ), $languages[$lang_code]['url'] );
    }
    return $languages; 
} );

2. Store the user’s preferred language in a cookie

This piece of code runs on the ‘plugins_loaded’ hook. We need the WPML’s icl_get_languages() function to check if the value for switch_lang is a registered language.

If the switch_lang variable is present, and the value is registered as a language, we create a cookie with the value, and a far-future expiry date.

The redirect is not mandatory, but as explained in step 1, requests with query strings are not cached, so the server would serve an uncached page. We strip the query string from the request uri, and redirect the user. This will also result in prettier URL’s.

/**
 * Update wp-wpml_user_selected_language cookie when user switches language
 */
add_action( 'plugins_loaded', function (){
    // GET variables
    $switch_language = filter_input(INPUT_GET, 'switch_language', FILTER_SANITIZE_STRING);
    if( $switch_language ) {
        $languages = icl_get_languages();

        // Check if the switch_language variable is a registered language
        if( array_key_exists( $switch_language, $languages ) ) {
            // Create a cookie that never expires, technically it expires in 10 years
            setcookie( 'wp-wpml_user_selected_language', $switch_language, time() + (10 * 365 * 24 * 60 * 60), '/' );

            // Let's redirect the users to the request uri without the querystring, otherwise the server will send an uncached page
            wp_redirect( strtok( $_SERVER['REQUEST_URI'], '?' ) );
            exit;
        }
    }
}, 1);

3. Redirect returning visitors to their preferred language

We use the wpml_switch_language action to redirect the user to his preferred language, which has been stored in the wp-wpml_user_selected_language cookie.

/**
 * Switch language if the user has selected his language before
 */
add_action( 'pre_get_posts', function ( $query ) {
    // Disable for admin area & only for main query
    if( is_admin() || !$query->is_main_query() ) {
        return;
    }

    // Disable for logged in users
    if( is_user_logged_in() ) {
        return;
    }

    // Check if requested webpage is /
    if( strtok( $_SERVER['REQUEST_URI'], '?' ) != '/' ) {
        return;
    }

    // GET & COOKIE variables
    $switch_language           = filter_input( INPUT_GET, 'switch_language', FILTER_VALIDATE_BOOLEAN );
    $user_selected_language    = filter_input( INPUT_COOKIE, 'wp-wpml_user_selected_language', FILTER_SANITIZE_STRING );

    // If user has selected his language before & user did not just change his language
    if ( $user_selected_language && !$switch_language ) {
        do_action( 'wpml_switch_language', $user_selected_language );
    }
}, 1);

In this case, we only redirect requests to the homepage. You could redirect all requests by commenting out:

if( strtok( $_SERVER['REQUEST_URI'], '?' ) != '/' ) {
    return;
}

Extra: Dynamic & mandatory cookie for WP Rocket

To be able to use this code in combination with WP Rocket, there is an extra step. We need to add the wp-wpml_user_selected_language cookie to the WP Rocket dynamic cookies. You can use WP Rocket cache dynamic cookie plugin for this, or implement the plugin in your functionality plugin. Don’t forget to replace your-cookie-id-here by wp-wpml_user_selected_language in line 21.

2 Replies to “WPML: remember user’s language choice”

  1. Hi Tom,

    Thank you for this function, but unfortunately, It doesn’t work for me. I’m using WPML with directory approach, example “/en”, “/fr”… So can I change the script so it supports directory approach in WPML?

    Thank you for your time!

    1. Hi Dejan,

      I have tested this on a fresh install with the directory approach & with the latest WPML version and this still works like it should.

      Here are some pointers:

      • Automatically switching to the correct language only works when a user visits the home page. If you want this to work with all pages, comment out the block // Check if requested webpage is /
      • Check out Maarten’s comment: https://wpml.org/forums/topic/remember-language-decision/#post-6608975
      • Make sure the “wp-wpml_user_selected_language” cookie is set, this is not a default wpml cookie. This cookie gets set only when you append the url’s of your language switcher with ?switch_language={lang}
      • I have noticed that this approach doesn’t work well when “Post Types Translation” -> pages is set to “Translatable – use translation if available or fallback to default language”.

      Kind regards,
      Tom

Leave a Reply

Your email address will not be published. Required fields are marked *

Overtuigd?

Neem dan contact op voor een offerte of vrijblijvend gesprek.
Stuur een e-mail naar [email protected] of maak gebruik van het contactformulier.