Background of the issue:
I am trying to ensure that my URLs reference the correct language when I translate automatically using WPML. I have had contact with Bruno this morning, who helped me solve my issue, but I am experiencing a similar issue on other parts of my site. The site I need help with is hidden link.
In my screenshot when I access the "View iPhone screen repairs" link, it goes to : hidden link instead of hidden link
Symptoms:
My URLs are not referencing the right language when I translate automatically. They remain in the default language.
Questions:
Why are my URLs not updating to the correct language when I use automatic translation with WPML?
How can I resolve the issue of URLs remaining in the default language on other parts of my site?
This issue is also happening for my USP's ( The 6 white checkmarks in the hero banner), where they also are going to the dutch translation, instead of their english version.
/**
* Translate an ACF Link URL from default language to current language (WPML-aware) with per-request caching.
* - Resolves posts/pages by ID to get the correct translated slug.
* - Falls back to wpml_permalink for archives/terms/custom endpoints.
* - Preserves query params and fragments.
* - Skips external, mailto:, tel:, and fragment-only links.
*
* Expects ACF link array: ['url' => '', 'title' => '', 'target' => '']
*/
function tpl_translate_acf_link($link) {
if (empty($link) || !is_array($link) || empty($link['url'])) {
return $link;
}
$raw = trim((string) $link['url']);
// Fast path: non-http(s) or fragment-only — no translation, but sanitize.
if (preg_match('#^(mailto:|tel:|#)#i', $raw)) {
$link['url'] = esc_url_raw($raw);
return $link;
}
// Cache key: include current language + home URL to be safe across multisite / domains per language.
static $cache = [];
$lang = defined('ICL_LANGUAGE_CODE') ? ICL_LANGUAGE_CODE : '';
$cache_key = md5(home_url('/') . '|' . $lang . '|' . $raw);
if (isset($cache[$cache_key])) {
$link['url'] = $cache[$cache_key];
return $link;
}
// Parse once
$home = home_url('/');
$home_host = wp_parse_url($home, PHP_URL_HOST);
$is_relative = (strpos($raw, '/') === 0);
$abs_for_host = $is_relative ? home_url($raw) : $raw;
$abs_host = wp_parse_url($abs_for_host, PHP_URL_HOST);
// External host → leave untouched (but sanitize)
if ($abs_host && $home_host && strcasecmp($abs_host, $home_host) !== 0) {
$safe = esc_url_raw($raw);
$cache[$cache_key] = $safe;
$link['url'] = $safe;
return $link;
}
// Remember original query/fragment to re-append later
$orig_parts = wp_parse_url($raw);
$orig_query = isset($orig_parts['query']) ? $orig_parts['query'] : '';
$orig_frag = isset($orig_parts['fragment']) ? $orig_parts['fragment'] : '';
// 1) Try to resolve a post/page by ID (best for exact translated slugs)
$abs_url = $is_relative ? $abs_for_host : $raw;
$post_id = url_to_postid($abs_url);
$translated_url = '';
if ($post_id) {
$ptype = get_post_type($post_id) ?: 'post';
$translated_id = apply_filters('wpml_object_id', $post_id, $ptype, true, $lang);
if ($translated_id) {
$translated_url = get_permalink($translated_id);
}
}
// 2) Fallback for archives/terms/custom endpoints
if (!$translated_url) {
$converted = apply_filters('wpml_permalink', $raw, $lang);
if (is_string($converted) && strpos($converted, '/') === 0) {
$converted = home_url($converted);
}
$translated_url = $converted ?: ($is_relative ? $abs_for_host : $raw);
}
// Re-append original query params if they existed (merge with any that translation added)
if ($orig_query) {
parse_str($orig_query, $orig_q);
$translated_parts = wp_parse_url($translated_url);
$translated_q = [];
if (!empty($translated_parts['query'])) {
parse_str($translated_parts['query'], $translated_q);
}
// Original params win if keys overlap (change order if you want the opposite)
$merged_q = array_merge($translated_q, $orig_q);
$base = isset($translated_parts['scheme'])
? ( $translated_parts['scheme'] . '://' . ($translated_parts['host'] ?? '') . (isset($translated_parts['port']) ? ':' . $translated_parts['port'] : '') . ($translated_parts['path'] ?? '/') )
: ($translated_parts['path'] ?? '/');
$translated_url = add_query_arg($merged_q, $base);
}
// Re-append fragment
if ($orig_frag) {
// Strip any existing fragment first
$translated_url = preg_replace('/#.*$/', '', $translated_url) . '#' . rawurlencode($orig_frag);
// If you don't want rawurlencode for fragments, swap to . $orig_frag
}
$safe = esc_url_raw($translated_url);
$cache[$cache_key] = $safe;
$link['url'] = $safe;
return $link;
}
I hope this will work for you.
Please note that we do our best to help with custom code, but we can't guarantee it will work. We have extensive documentation for developers, which you can check here: https://wpml.org/documentation/support/.
Regards,
Itamar.
The topic ‘[Closed] My URLs are not referencing the right lang, when I translate automatically. They remain in the defau…’ is closed to new replies.