WPML language switcher for custom rewrite rules


I am making custom rewrite rules for categories in a dual-language project (german as main, english as second language). The urls look like this

example.com/fliegen > shows archive.php for category fliegen

example.com/en/aviation > shows archive.php for category aviation (the translated fliegen)

This could be achieved by changing the category-base to . (although it doesn’t seem to work in my case?)

Unfortunately that wouldn’t be enough for me, anyways; there is a custom taxonomy called filter in the game aswell, which requires urls like this:



When the project was still single-language, I went that route:

add_filter("rewrite_rules_array", function($rules) {
    $newRules = array();

    $cats = get_terms("category", array("hide_empty" => false));

    foreach ($cats as $id => $cat) {
        $slug = $cat->slug;
        $newRules[$slug . "/?$"] = "index.php?category_name=" . $slug;
        $newRules[$slug . "/filter/(.+?)/?$"] = 'index.php?category_name=' . $slug . '&filter=$matches[1]';

    return $newRules;

This code now also includes the translated category-terms, but obviously doesn’t care about the needed /en/ in the rewrite-rule; So I now need a way to ask inside the foreach loop what language the current term represents.

Hoooow can I do that?



PS: If anybody knows where to find proper Docs for all the icl_-php functions, that seem to come with WPML, please let me know!



I found a solution to this myself.

The key is a filter-hook called wpml_element_language_details. But WPML changes core functions like get_terms so one gets only the terms for the current language. This may be very convenient in most cases, creating rewrite rules based on the currently active language in the backend? Not a good idea… therefore you have to temporarily remove the wpml-filters. Which filters to remove? No idea, .. found that online.

add_filter("rewrite_rules_array", function($rules) {
    $newRules = array();

    // remove WPML term filters
    global $sitepress;
    remove_filter('get_term', array($sitepress,'get_term_adjust_id'));
    remove_filter('get_terms_args', array($sitepress, 'get_terms_args_filter'));
    remove_filter('terms_clauses', array($sitepress,'terms_clauses'));

    // now get ALL categories of ALL languages,
    $cats = get_terms("category", array("hide_empty" => false)); 

    // restore WPML term filters
    add_filter('get_term', array($sitepress,'get_term_adjust_id'));
    add_filter('get_terms_args', array($sitepress, 'get_terms_args_filter'));
    add_filter('terms_clauses', array($sitepress,'terms_clauses'));

    // Loop through the $cats
    foreach ($cats as $id => $cat) {

        $details = apply_filters("wpml_element_language_details", null, array("element_id" => $cat->term_id, "element_type" => "category"));

        $slug = $cat->slug;

        // if necessary, add language prefix
        // not having a source_language_code means this is part of the main language and (in our case) therefore doesn't need a prefix at all
        // (!) this may be different for your WPML installation!
        $lang_prefix = ($details->source_language_code != NULL) 
            ? $details->language_code . "/"
            : ""

        $newRules[$lang_prefix . $slug . "/?$"] = "index.php?category_name=" . $slug;
        $newRules[$lang_prefix . $slug . "/filter/(.+?)/?$"] = 'index.php?category_name=' . $slug . '&filter=$matches[1]';


Language switcher

So far my language switcher looks like this,

$lang_switcher = icl_get_languages("skip_missing=0");

foreach ($lang_switcher as $lang) {
    $activeClass = (($lang["active"])) ? " active" : "";
    echo '
        <a href="' . $lang["url"] . '" class="'.$activeClass.'">'. $lang["native_name"] .'</a>

I have more special cases, like filterable search-page, filterable author-pages.

How can I now link these different custom urls to each other properly?

, , , kater louis 6 years 2017-12-20T11:35:41-05:00 0 Answers 97 views 0

Leave an answer