I know that it's possible to switch the WP locale by using URL paramaters, as described here, but I'm trying to build a method that would entirely rely on a custom "Language" taxonomy.

What I currently have is a simple plugin, that registers the language taxonomy and implements a locale switch if the taxonomy is present:

add_action( 'plugins_loaded', 'wpsx_register_taxonomies' );
function wpsx_register_taxonomies() {
register_taxonomy('wpsx_language', array (
                  0 => 'post',
                  1 => 'page',
                ), array( 
                    'hierarchical' => true, 
                    'label' => 'Languages',
                    'singular_label' => 'Language',
                    'show_ui' => true,
                    'rewrite' => false,
function wpsx_redefine_locale($locale) {
    global $post;
      if ( taxonomy_exists( 'wpsx_language' )) {
        $locale = 'de_DE'; // this does work !!
        if ( has_term( 'fr', 'wpsx_language' )) {
            $locale = 'fr_FR'; // this does not work yet :(
     return $locale;

So the little part that isn't working is the has_term() test. My impression is that the locale filter is running at an early step in the loading sequence, when the post content isn't retrieved yet, and therefore conditional tests like is_single() or has_term() won't return anything.

Can I force the post content to load earlier? Can I delay the locale filter?

I'm unable to figure out a solution for this. On the wp-hackers mailing list, a suggestion was to run global $post; but this didn't help.

Update: following the suggestion by david.binda, I found a workaround, dropping the taxonomy, and using the post slug as a trigger:

function wpsx89972_redefine_locale($locale) {
    $wpsx_url = $_SERVER['REQUEST_URI'];
    $wpsx_url_lang = substr($wpsx_url, -4); // test for the last 4 chars:
    if ( $wpsx_url_lang == "-fr/") {
        $locale = 'fr_FR';
    } else if ( $wpsx_url_lang == "-en/") { 
        $locale = 'en_US';
    } else { // fallback to default
        $locale = 'de_DE'; 
    return $locale;

This requires the user to rewrite the post slugs, such as "my-post-title-fr" for French, "my-post-title-en" for English, etc. A bit less user-friendly than using language tickboxes, but it keeps the code simple and just works.

So now I have a functional multi-language plugin, in only 13 lines of code :)

Still, I will leave this question open for a couple days, to see if anyone comes up with a solution that would make use of the taxonomy...

  • You don't have to relly on user's input to post slug. You can keep the taxonomy box on and hook into save_post action and based on term assigned, rewrite the slug: codex.wordpress.org/Function_Reference/… Mar 8, 2013 at 16:05
  • Right, maybe I will do that, if I find some good sample code :)
    – Manu
    Mar 8, 2013 at 19:10
  • See my updated answer below Mar 9, 2013 at 12:26
  • Did you ever get the theme loading the correct mo files with this? I'm checking if a post is in a specific category or that category terms listing page and changing to locale. It changes the document language and the core es_ES mo file loads, but plugins and theme still load the default language Aug 20, 2018 at 21:31
  • @RobertWent with the Category as a criteria to change the locale, you are facing the same issue I had with a taxonomy: the Post content is loaded too late, and you need to find a trick to test for the Category earlier in the process. I think the solution by Fahad Alduraibi below can point you in the right direction.
    – Manu
    Aug 22, 2018 at 6:17

2 Answers 2


You might be interested in url_to_postid function

Used as follows from your wpsx_redefine_locale function:

$postid = url_to_postid( $url );

Note that this does not return the post id for custom post types but the function is located in /wp-includes/rewrite.php and might be extended if needed.

UPDATE: here's your sample:

function my_function(){
if ( ! wp_is_post_revision( $post_id ) ){

    // unhook this function so it doesn't loop infinitely
    remove_action('save_post', 'my_function');

    // update the post, which calls save_post again
    $my_post_args = array();
    $my_post_args['ID'] = post_id;
    $p = get_post( $post_id );
    $lang_tax = 'my_lang_tax_name';
    $language_terms = get_post_terms( $post_id, $lang_tax );
    $my_post_args['post_name'] = $p->name . '_' . $language_terms[0]->slug;
    wp_update_post( $my_post_args );

    // re-hook this function
    add_action('save_post', 'my_function');
add_action('save_posts', 'my_function');

What have to be done further, but that's up to you. You have to sanitize the situation when user changed language taxonomy term assigned to post, so you don't get my-post_de_en instead of my-post_en on post which was before in de and had my-post_de slug. This would require some regular expressions stuff, but you'll manage that ;)

  • Ok, that's interesting. What's the implied reasoning - to retrieve the post ID, then to make a raw database query to check for the taxonomy? Unfortunately, url_to_postid() doesn't work that early in the action chain. If I include it in the locale filter, it generates a "Fatal error: Call to a member function wp_rewrite_rules() on a non-object". If I call it at a later step, it works fine.
    – Manu
    Mar 8, 2013 at 14:59
  • was worth trying... wp_rewrite is defined later, apparently. I'm afraid I'm out of further ideas. Mar 8, 2013 at 15:27
  • After all, your suggestion made me think, and I noticed that the $_SERVER['REQUEST_URI'] part was at least returning the post URL... I guess there's a reason why all existing multilanguage plugins rely on the URL. So I'm now settling for a workaround, using the last part of the URL string to switch the language, like "my-post-title-fr", "my-post-title-en", etc. A compromise, but at least it works and keeps things simple.
    – Manu
    Mar 8, 2013 at 15:36
  • Oh wow, that's a great code sample! I will build upon that. Thanks a lot.
    – Manu
    Mar 14, 2013 at 8:26

Here is a better solution that will not change anything in your post, but will only add a meta

// Set the post language when loading up the page based on the store meta
function ppl_set_post_language() {
    $postID = url_to_postid( $_SERVER["REQUEST_URI"] );
    if ($postID > 0) {
        $postLanguage = esc_attr( get_post_meta( $postID, '_ppl_post_language', true ) );
        if ( ! empty( $postLanguage ) ) {
            global $locale;
            $locale = $postLanguage;
// Any call to 'url_to_postid' earlier then 'setup_theme' will generate a fatal error.
add_action('setup_theme', 'ppl_set_post_language');

For more details check my answer (on my own question) here: Set language per post

And I have a plugin that makes everything for you (link is in my answer also)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.