Last week I ran into an issue with WPML URLs on post type archive page. When the permalink is set to %post_name%, we can access the archive page following //site_url/post_type_slug. And the posts can be filtered by taxonomy using //site_url/post_type_slug?taxonomy_name=taxonomy parameter in the URL. With WPML language switcher things become a bit tricky.

The issue

When I tried to change the language on the archive page while the taxonomy filter was present in the URL, WPML tend to take me to the taxonomy archive page instead. Let’s say for example my URL was and when I tried to change to a different language (e.g. French) the URL became while I expected it to be Here livresla-genre and la-fiction is French translation of booksgenre and fiction respectively.

This wouldn’t be an issue for most cases. But in this particular case, I wanted to display only the detail of each genre along with some other info on their archive page and then show the books of each genre on the books archive page using the URL parameter.

Solution using WPML filter

The filter icl_ls_languages to the rescue! I added this filter to catch the language switcher and modify the URL before sent out to the output. Here is the final code I used:

Inside the foreach loop of languages I checked if this is a post_type_archive using is_post_type_archive() function. We can use is_search(), is_archive() or any similar function based on our need. Used the get_queried_object() function to get the current taxonomy and get_post_type() to fetch current post type. I checked whether $archived_taxonomy->slug is set to make sure we are filtering by a taxonomy and the WPML’s language switcher is going to redirect me to a different URL. So, next step is to generate the right URL and replace the WPML generated one with that.

Now that we have the taxonomy ID, we can get the counterpart of that in other language using wpml_object_id filter. Problem is, when we pass that ID to get_term() function, WPML takes over and adjusts the ID to our active language. So, we’ll get the taxonomy that I already have! Here comes the use of the global variable $icl_adjust_id_url_filter_off. I backed up the existing value of that variable (generally false), set it to true and then called the get_term() function like this:

//Backup the global variable
$orig_flag_value = $icl_adjust_id_url_filter_off;
//Set the global variable to true
$icl_adjust_id_url_filter_off = true;
//Fetch the translated counterpart of the term
$translated_term = get_term( apply_filters( 'wpml_object_id', $archived_taxonomy->term_id, $archived_taxonomy->taxonomy, false, $lang_code ), $archived_taxonomy->taxonomy );
//Reset the global variable to it's old value
$icl_adjust_id_url_filter_off = $orig_flag_value;

Now that I have the translated taxonomy name and slug, I replaced the query string of current URL using the desired taxonomy slugs. Then replaced the language URL to the post type (books in this case) archive page instead of taxonomy archive page and appended the new query string.

That it! Now the taxonomy archive works fine on its own and the post type archive works fine with query strings. %DRUMROLLS%!!

Published by Ashiqur Rahman

Programmer and photography enthusiast.

Join the Conversation


  1. the solution for me !

    its very specific hack , but works !

    save the GET parameters in array and make a foreach and use get term by to replace in query string

    function my_ls_filter($languages) {
    global $icl_adjust_id_url_filter_off;
    if( $_SERVER[ ‘QUERY_STRING’ ] ){
    if( strpos( basename( $_SERVER[ ‘REQUEST_URI’ ] ), $_SERVER[ ‘QUERY_STRING’ ] ) !== false ){
    foreach( $languages as $lang_code => $language ){
    if( is_post_type_archive(‘product’) ) {
    $query_string = $_SERVER[‘QUERY_STRING’];

    // get the params
    $params = array();
    if (isset($_GET[‘linea’]) && !empty($_GET[‘linea’])){
    $params [‘linea’] = $_GET[‘linea’];
    if (isset($_GET[‘pais’]) && !empty($_GET[‘pais’])){
    $params [‘pais’] = $_GET[‘pais’];

    $archived_post_type = get_post_type();

    foreach($params as $taxName => $taxSlug) {
    $archived_taxonomy = get_term_by(‘slug’, $taxSlug , $taxName);

    if( isset( $archived_taxonomy->slug ) ) {
    $orig_flag_value = $icl_adjust_id_url_filter_off;
    $icl_adjust_id_url_filter_off = true;
    $translated_term = get_term( apply_filters( ‘wpml_object_id’, $archived_taxonomy->term_id, $archived_taxonomy->taxonomy, false, $lang_code ), $archived_taxonomy->taxonomy );
    $icl_adjust_id_url_filter_off = $orig_flag_value;

    $query_string = str_replace($archived_taxonomy->taxonomy.’=’.$archived_taxonomy->slug, $translated_term->taxonomy.’=’.$translated_term->slug, $_SERVER[“QUERY_STRING”]);

    $_SERVER[“QUERY_STRING”] = $query_string;

    $languages[ $lang_code ][‘url’] = apply_filters( ‘wpml_permalink’, get_post_type_archive_link( $archived_post_type ), $lang_code ) . ‘?’ . $query_string;
    } else {
    $languages[ $lang_code ][‘url’] = $languages[ $lang_code ][‘url’] . ‘?’ . $_SERVER[“QUERY_STRING”];
    return $languages;

    1. Hi Roberto,

      Nice catch. I haven’t tested with more than one parameter. I’ll improve my code based on your hack. 🙂

Leave a comment

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