WPML

Some things work differently on a multilingual site by design: a WordPress function keyed on a default-language term, a date suffix WordPress cannot localize, a slug the Advanced Translation Editor does not invent. Support questions raise them as bugs; they are not. This page says what happens, why, and what to do instead.

has_category() and other conditional tags on translated posts

WordPress core's has_category() is not filtered by WPML, on purpose. On a translation the category is the translated term, which has its own slug, so has_category('news') is false on the French post even though the French post is in the French "news" category. The same holds for has_term(), in_category() and any code that compares a default-language slug or term id. Call the conditional with the translated slug, or resolve the term id through the wpml_object_id filter first.

What you see

The native WordPress function has_category does not work for translated posts.

An example of this is as follows:

  1. We have a category with the English slug “test” and its French translation “test-fr”.
  2. This category is assigned to posts.
  3. When you invoke the has_category("test") inside a loop in your theme’s single.php file, it returns true for the default language but false for the translation.

What to do

Define a new filter in your theme’s functions.php file:

function wp_has_category ($category) {
$category = get_term_by('name', $category, 'category');
return has_category($category);
}
add_filter('wp_has_category', 'wp_has_category', 10, 1);

Replace the has_category function with this new filter:
apply_filters( 'wp_has_category', 'test' )

This filter takes the translated category based on the name of original one and checks if the translated category is assigned to a post.

Reference: wpmlcore-3024.

Date suffixes (1st, 2nd, 3rd) are not translatable

This is a limitation of WordPress core, not of WPML: the suffix comes from PHP's date formatting and never passes through a translation function.

What you see

Some  themes or plugins use the wp_date() or date_i18n() WordPress functions to display dates. These dates may use a suffix as 1st or 26th, depending on the parameters selected.

Currently, it’s not possible to translate date suffixes because of a longstanding known limitation in WordPress core (opens in a new tab).

What to do

As a workaround, you can use the wp_date filter to get the date, then modify the suffix before it’s rendered on the page. Please make a full backup of your site before proceeding and follow the steps below:


  • Add a small wp_date filter to your theme's functions.php that registers each suffix as a string (icl_register_string) and returns its translation (icl_t) in place of the English suffix:

  • Open the page where the dates are displayed. This will execute the filter added.

  • Go to WPML → String Translation and translate the dates.

  •  You will need to translate each suffix separately (e.g. 1st, 2nd…) because it may change depending on the language.

Reference: compsupp-5773.

The Advanced Translation Editor does not invent a slug

The editor translates the slug field when you fill it and keeps the original slug when you leave it empty. It never derives a slug from the translated title on its own.

What you see

If you translate a post using our Advanced Translation Editor, the slug field is not filled automatically. If you then decided to leave the slug field empty, it loads the original language slug in the translated post.

Reference: wpmlsupp-8574.

Page-builder shortcodes in a WooCommerce product short description

The short description is the post excerpt, a plain-text field by WordPress's definition, so WPML does not parse page-builder shortcodes in it the way it does in the content. WooCommerce happens to render them, which is why the mismatch surprises people.

What you see

The WooCommerce product short description is based on the post excerpt field, and that is ordinarily a simple text field that does not handle shortcodes. As such it is not expected that if you paste page-builder shortcodes into the post excerpt they would work, and when translating post excerpts WPML does not attempt to handle such shortcodes.

But WC handles these “excerpts” a little differently, and shortcodes do work, but WPML still acts as if they do not, and if the shortcode includes attributes that need translating or internal links that should be handled automatically that is not readily possible.

What to do

We have prepared code that can be added as a plugin to provide this functionality. Copy and paste the below code into a file that you might name wpmlpb-excerpts.php and save in your wp-content/plugins/ directory, then activate the plugin.

<?php
/**
 * Plugin Name: WPML Page Builders - Proces Excerpts
 * Description: Parses shortcode strings in exceprts.
 * Version: 1.0
 */
namespace WPMLPB686;

( new Excerpts() )->add_hooks();

class Excerpts {

	const SEPARATOR_START = '<!--WPML_EXCERPT_START-->';
	const SEPARATOR_END   = '<!--WPML_EXCERPT_END-->';

	public function add_hooks() {
		add_filter( 'wpml_pb_shortcode_content_for_translation', [ $this, 'joinWithContent' ], 10, 2 );
		add_filter( 'wpml_tm_translation_job_data', [ $this, 'excludeFromJob' ], 10, 2 );
		add_action( 'wpml_pro_translation_completed', [ $this, 'splitFromContent' ], 999 );
	}

	public function joinWithContent( $content, $id ) {
		$post = get_post( $id );
		if ( $post && $post->post_excerpt ) {
			$content .= self::SEPARATOR_START . $post->post_excerpt . self::SEPARATOR_END;
		}

		return $content;
	}

	public function excludeFromJob( $package, $post ) {
		if ( preg_match( '/[[^]]+]/', $post->post_excerpt ) ) {
			$package['contents']['excerpt']['translate'] = 0;
			$package['contents']['excerpt']['data']      = '';
		}

		return $package;
	}

	public function splitFromContent( $post_id ) {
		$post = get_post( $post_id );
		if ( $post && false !== strpos( $post->post_content, self::SEPARATOR_START ) ) {
			$start_pos = strpos( $post->post_content, self::SEPARATOR_START );
			$end_pos   = strpos( $post->post_content, self::SEPARATOR_END, $start_pos );

			if ( false !== $end_pos ) {
				$content = substr( $post->post_content, 0, $start_pos );
				$excerpt = substr( $post->post_content, $start_pos + strlen( self::SEPARATOR_START ), $end_pos - $start_pos - strlen( self::SEPARATOR_START ) );

				if ( $excerpt ) {
					wp_update_post(
						[
							'ID'           => $post_id,
							'post_content' => $content,
							'post_excerpt' => $excerpt,
						]
					);
				}
			}
		}
	}
}

Reference: wpmlpb-686.

Different domains per language on WordPress.com hosting

WordPress.com maps one domain to a site; the "different domains per language" URL format needs every language domain to reach the same WordPress, which that hosting does not offer.

What you see

Because of limitations on how domain mapping works with WordPress.com it is not possible to choose the language URLs setting to use different domains per language when sites are hosted with them.

What to do

Either of the other language URL options, with languages in directories or added as a URL parameter, can be used instead of different domains per language.

A different host would be needed if different domains per language were a requirement.

Reference: wpmltriage-2045.

Imported translations and the translation editors

An import writes finished translations; it does not create translation jobs, and the editors work from jobs. The translations are complete on the front end and simply not editable in the Advanced or Classic Translation Editor.

What you see

Whenever you import content using WP All Import and the WPML All Import add-on, you will see the imported post translations perfectly on the front-end. However, you will encounter issues if you try to update them using WPML’s translation editors:

This is because when you import multilingual content, WPML does not create translation jobs, which are needed for string segmentation.

What to do

To edit or update your imported translations, please switch to the native WordPress editor and use manual translation.

Reference: WPMLAI-168.

Strings registered in English on a site whose default language is not English

Since WPML String Translation 5.0, a string whose language WPML cannot determine is registered in English, by design. The source language of a theme's or plugin's strings is a setting of its text domain, not of the site's default language, and the fix is to set it for that domain.

What you see

When strings are automatically registered for translation in WPML String Translation, they are assigned English as the source language, even if English is not installed or is not the default language on the site.

What to do

Set the language of the text domain: go to WPMLString Translation, scroll down to Utilities, expand Set the original language of themes and plugins and choose the language of the theme's or plugin's domain. The steps, and how to change the source language of individual strings, are in How to Change the Source Language of Strings.

Do not patch the fallback in the plugin's code. The retired known-issue page offered an edit to class-wpml-autoregister-save-strings.php; every update undoes it, and the domain setting is the supported way.

Reference: wpmldev-10164 (earlier wpmldev-3232).