Skip to main content
Signocore
// signocore multilanguage docs

WPML compatibility

Which WPML hooks Signocore Multilanguage answers, how each one behaves, and what is not covered.

Many themes and plugins support WPML through its hooks, such as apply_filters('wpml_object_id', ...). Signocore Multilanguage answers the eight most common of them, so that code works on a site without WPML. This page lists what each one returns and where it behaves differently from WPML.

When the layer is active

The WPML hooks are registered while Signocore Multilanguage boots on plugins_loaded at priority 10, and only when WPML itself is not active: if the ICL_SITEPRESS_VERSION constant is defined at that point, Signocore Multilanguage registers none of them and WPML answers its own hooks. Before the layer is registered, for example in another plugin's main file, each filter returns the value you pass in.

The layer only answers hooks. It does not define WPML's constants, functions or classes, so code that checks for WPML with defined('ICL_SITEPRESS_VERSION'), defined('ICL_LANGUAGE_CODE'), function_exists('icl_object_id') or class_exists('SitePress') sees no WPML and skips its WPML code, even where the hooks below would have worked. To support both plugins in your own code, see Template functions.

Hooks that are answered

Hook Type Returns
wpml_object_id Filter The ID of an element's translation.
wpml_current_language Filter The current language code.
wpml_default_language Filter The default language code.
wpml_active_languages Filter The active languages, keyed by code.
wpml_switch_language Action Switches the current language.
wpml_element_has_translations Filter Whether an element has translations.
wpml_permalink Filter A URL with its language part swapped.
wpml_home_url Filter The home URL of the current language.

wpml_object_id

apply_filters('wpml_object_id', $elementId, $elementType, $returnOriginal, $langCode);

Returns the ID of the post, term or menu that translates $elementId into $langCode.

Argument Default How it is read
$elementId A post, term or menu ID. A value that is not numeric is returned unchanged.
$elementType post post for a post of any post type, a post type name such as page, a taxonomy name such as category, or nav_menu for a menu. The stored types from the data model, such as post_page, work too.
$returnOriginal true What to return when there is no translation: the original ID when true, null when false.
$langCode Current language The language to look up.

Differences from WPML:

  • $returnOriginal defaults to true. WPML's default is false. A call that leaves out the third argument, such as apply_filters('wpml_object_id', $id, 'page'), gets the original ID here where WPML returns null. Pass the argument explicitly and both plugins behave the same.
  • post matches any post type. The ID is looked up as a post of whatever type it is, not only the post post type.
  • any is not recognized as an element type. It finds no translation, so you get the original ID or null.
  • Menu items are not translated one by one. nav_menu_item finds no translation; translate the whole menu and pass nav_menu.
  • Translations of any status are returned, including drafts and private posts. Check the status when that matters.

A post or term whose type is not translated has no translations and follows the $returnOriginal rule.

// The Spanish version of the shop's terms page, or null when it has none.
$termsPageId = apply_filters('wpml_object_id', 42, 'page', false, 'es');

wpml_current_language

apply_filters('wpml_current_language', null);

Returns the current language code, such as es, and ignores the value passed in. It always returns a single language code and never all. Before the language is detected on init at priority 1, it returns the default language. After wpml_switch_language or signocore_ml_switch_language(), it returns the language switched to.

wpml_default_language

apply_filters('wpml_default_language', null);

Returns the default language code and ignores the value passed in.

wpml_active_languages

apply_filters('wpml_active_languages', null, $args);

Returns every active language as an array keyed by language code, in the order the languages were added. Each entry has these keys:

Key Value
code The language code, such as es.
native_name The native name, such as Español.
translated_name The English name, such as Spanish.
default_locale The WordPress locale, such as es_ES.
active Always true.
url The current address with its language prefix, subdomain or domain swapped.

Differences from WPML:

  • $args is ignored. Options such as skip_missing, orderby, order and link_empty_to have no effect, so every active language is always returned, also when the current page has no translation in it.
  • active is true for every language. In WPML it marks the current language. To find the current language, compare code with apply_filters('wpml_current_language', null).
  • url does not point to the translation. It swaps the language part of the current address and keeps the rest, so on a translated post with its own slug it can lead to a page that does not exist. Use signocore_ml_get_permalink() for the address of a translation, or the plugin's own switcher, whose links do point to the translations.
  • translated_name is always the English name, not the name in the current language.
  • Other keys WPML returns are missing, among them id, language_code, missing and country_flag_url.
$languages = apply_filters('wpml_active_languages', null);
$current = apply_filters('wpml_current_language', null);

foreach ($languages as $code => $language) {
    if ($code !== $current) {
        printf('<a href="%s">%s</a>', esc_url($language['url']), esc_html($language['native_name']));
    }
}

wpml_switch_language

do_action('wpml_switch_language', $langCode);

Makes another language the current one, the same way as signocore_ml_switch_language(): language-filtered queries, string translations, the locale filter and, on the front end, home_url() follow it. It fires signocore_ml_language_switched.

Differences from WPML:

  • null does not switch back. WPML treats null as a request to return to the request's own language. Here, anything that is not a string is ignored, so the language stays switched until the request ends.
  • all is ignored. There is no mode that lists content from every language through this action; use the sml_filter_language query argument described in Template functions instead.
  • The code is not checked against your languages. An unknown code makes filtered queries return nothing.
  • Switches nest. Each switch remembers the language before it, and signocore_ml_restore_language() goes back one step.

Code that must run on both plugins can restore like this:

do_action('wpml_switch_language', 'es');

$spanishPosts = get_posts([
    'post_type' => 'post',
    'suppress_filters' => false,
    'sml_filter_language' => true,
]);

if (!defined('ICL_SITEPRESS_VERSION') && function_exists('signocore_ml_restore_language')) {
    signocore_ml_restore_language();
} else {
    do_action('wpml_switch_language', null);
}

Signocore Multilanguage does not filter secondary queries by itself, so the sml_filter_language argument is what limits that query to Spanish; WPML ignores it.

wpml_element_has_translations

apply_filters('wpml_element_has_translations', null, $elementId, $elementType);

Returns true when the element's translation group holds more than one post or term, and false otherwise, ignoring the value passed in. $elementType defaults to post and is read as in wpml_object_id. Translations count whatever their status, drafts included. An ID that is not a positive number, an element without a language record and a menu all return false.

apply_filters('wpml_permalink', $url, $langCode);

Returns $url with its language prefix, subdomain or domain swapped to $langCode, as signocore_ml_get_url_for_language() does. The path stays exactly as it is.

Differences from WPML:

  • Only the language part changes. The filter does not look up the translated post or its translated slug, so on a translated post with its own slug the result can lead to a page that does not exist. For the address of a translation, get its ID with wpml_object_id and pass it to signocore_ml_get_permalink().
  • The third argument, $full_resolution, is ignored.
  • Without a language code, the URL is returned unchanged. Always pass the code.

wpml_home_url

apply_filters('wpml_home_url', null);

Returns home_url('/'), which on the front end is the home URL of the current language, such as https://example.com/es/. Any argument is ignored. In wp-admin, home_url() is not changed by the plugin, so the filter returns the site's own home URL there.

What is not provided

Everything else in WPML's API is missing, among others:

Kind Not provided
Functions icl_object_id(), icl_get_languages(), icl_t(), icl_register_string()
Constants ICL_SITEPRESS_VERSION, ICL_LANGUAGE_CODE, ICL_LANGUAGE_NAME, ICL_LANGUAGE_NAME_EN
Objects The SitePress class and the global $sitepress
String hooks wpml_register_single_string, wpml_translate_single_string
Element hooks wpml_post_language_details, wpml_element_language_code, wpml_element_language_details, wpml_element_trid, wpml_get_element_translations, wpml_set_element_language_details, wpml_is_translated_post_type
Other hooks wpml_loaded, wpml_language_has_switched, wpml_add_language_selector, wpml_language_is_active, wpml_display_language_names
Configuration wpml-config.xml files in themes and plugins are not read.

Most of these have a counterpart in Signocore Multilanguage's own API:

WPML Signocore Multilanguage
ICL_LANGUAGE_CODE signocore_ml_get_current_language()
icl_object_id() signocore_ml_get_translation()
icl_get_languages() signocore_ml_get_active_languages() and signocore_ml_get_permalink()
wpml_post_language_details, wpml_element_language_code signocore_ml_get_element_language()
wpml_get_element_translations signocore_ml_get_translations()
wpml_register_single_string The signocore_ml_register_string action
wpml_translate_single_string, icl_t() signocore_ml_translate_string()
wpml_add_language_selector signocore_language_switcher()
wpml_language_has_switched The signocore_ml_language_switched action

To move content, links and strings from a WPML site, see Switch from WPML or Polylang.

Stuck on something the docs don't cover?

Questions go straight to the developer who builds the plugins. Replies usually within a day.

September Sale

€20 off Signocore SEO Pro

Pay €49 instead of €69, one time for unlimited sites. code SEP20