// =========================================================================
// Reiss Multilingual Helpers
// =========================================================================
if (!function_exists('reiss_get_current_request_path')) {
function reiss_get_current_request_path() {
$current_request_uri = isset($_SERVER['REQUEST_URI']) ? wp_unslash($_SERVER['REQUEST_URI']) : '/';
$current_path = strtok($current_request_uri, '?');
if ($current_path === false || $current_path === '') {
$current_path = '/';
}
$current_path = '/' . ltrim((string) $current_path, '/');
$current_path = preg_replace('#/+#', '/', $current_path);
return $current_path;
}
}
if (!function_exists('reiss_get_default_lang')) {
function reiss_get_default_lang() {
return 'en';
}
}
if (!function_exists('reiss_get_host')) {
function reiss_get_host() {
return home_url('/');
}
}
if (!function_exists('reiss_get_language_codes')) {
function reiss_get_language_codes() {
return array(
'af','ar','az','de','el','es','fa','fr','id','it','ja','ko','ms','nl','pl','pt','ru','sv','th','tr','vi','zh-cn'
);
}
}
if (!function_exists('reiss_get_supported_langs')) {
function reiss_get_supported_langs() {
return array_values(array_unique(array_merge(array(reiss_get_default_lang()), reiss_get_language_codes())));
}
}
if (!function_exists('reiss_get_locale_map')) {
function reiss_get_locale_map() {
return array(
'en' => 'en_US',
'af' => 'af_ZA',
'ar' => 'ar_SA',
'az' => 'az_AZ',
'de' => 'de_DE',
'el' => 'el_GR',
'es' => 'es_ES',
'fa' => 'fa_IR',
'fr' => 'fr_FR',
'id' => 'id_ID',
'it' => 'it_IT',
'ja' => 'ja_JP',
'ko' => 'ko_KR',
'ms' => 'ms_MY',
'nl' => 'nl_NL',
'pl' => 'pl_PL',
'pt' => 'pt_PT',
'ru' => 'ru_RU',
'sv' => 'sv_SE',
'th' => 'th_TH',
'tr' => 'tr_TR',
'vi' => 'vi_VN',
'zh-cn' => 'zh_CN',
);
}
}
if (!function_exists('reiss_get_html_lang_map')) {
function reiss_get_html_lang_map() {
return array(
'en' => 'en',
'af' => 'af',
'ar' => 'ar',
'az' => 'az',
'de' => 'de',
'el' => 'el',
'es' => 'es',
'fa' => 'fa',
'fr' => 'fr',
'id' => 'id',
'it' => 'it',
'ja' => 'ja',
'ko' => 'ko',
'ms' => 'ms',
'nl' => 'nl',
'pl' => 'pl',
'pt' => 'pt',
'ru' => 'ru',
'sv' => 'sv',
'th' => 'th',
'tr' => 'tr',
'vi' => 'vi',
'zh-cn' => 'zh-CN',
);
}
}
if (!function_exists('reiss_normalize_path')) {
function reiss_normalize_path($path) {
$path = '/' . ltrim((string) $path, '/');
$path = preg_replace('#/+#', '/', $path);
if ($path !== '/' && substr($path, -1) !== '/') {
$path .= '/';
}
return $path;
}
}
if (!function_exists('reiss_get_current_lang')) {
function reiss_get_current_lang() {
$current_path = reiss_get_current_request_path();
$current_lang = reiss_get_default_lang();
if (preg_match('#^/([a-zA-Z]{2,3}(?:-[a-zA-Z]{2})?)(?:/|$)#', $current_path, $matches)) {
$current_lang = strtolower($matches[1]);
}
if (!in_array($current_lang, reiss_get_supported_langs(), true)) {
$current_lang = reiss_get_default_lang();
}
return $current_lang;
}
}
if (!function_exists('reiss_get_current_lang_path')) {
function reiss_get_current_lang_path() {
$current_path = reiss_get_current_request_path();
$current_lang = reiss_get_current_lang();
$default_lang = reiss_get_default_lang();
$path = $current_path;
if ($current_lang !== $default_lang) {
$path = preg_replace('#^/' . preg_quote($current_lang, '#') . '(?=/|$)#i', '', $path);
}
if ($path === '' || $path === false) {
$path = '/';
}
return reiss_normalize_path($path);
}
}
if (!function_exists('reiss_lang_url')) {
function reiss_lang_url($host, $lang, $default, $path) {
$host = rtrim((string) $host, '/');
$path = reiss_normalize_path($path);
if ($lang === $default) {
return $host . $path;
}
return $host . '/' . rawurlencode($lang) . $path;
}
}
if (!function_exists('reiss_strip_lang_from_path')) {
function reiss_strip_lang_from_path($path, $supported_langs) {
$path = (string) $path;
$path_only = parse_url($path, PHP_URL_PATH);
if (!is_string($path_only) || $path_only === '') {
$path_only = '/';
}
foreach ($supported_langs as $lang_code) {
if ($lang_code === reiss_get_default_lang()) {
continue;
}
$pattern = '#^/' . preg_quote($lang_code, '#') . '(?=/|$)#i';
if (preg_match($pattern, $path_only)) {
$path_only = preg_replace($pattern, '', $path_only);
break;
}
}
if ($path_only === '' || $path_only === false) {
$path_only = '/';
}
return reiss_normalize_path($path_only);
}
}
if (!function_exists('reiss_localize_url')) {
function reiss_localize_url($url, $target_lang, $default_lang, $host, $supported_langs) {
$url = trim((string) $url);
if ($url === '') {
return $url;
}
$parsed = wp_parse_url($url);
if (!is_array($parsed)) {
return $url;
}
$target_host = wp_parse_url($host, PHP_URL_HOST);
$url_host = isset($parsed['host']) ? $parsed['host'] : '';
if ($url_host && $target_host && strtolower($url_host) !== strtolower($target_host)) {
return $url;
}
$path = isset($parsed['path']) ? $parsed['path'] : '/';
$clean = reiss_strip_lang_from_path($path, $supported_langs);
$localized = reiss_lang_url($host, $target_lang, $default_lang, $clean);
if (!empty($parsed['query'])) {
$localized .= '?' . $parsed['query'];
}
if (!empty($parsed['fragment'])) {
$localized .= '#' . $parsed['fragment'];
}
return $localized;
}
}
if (!function_exists('reiss_replace_host_urls_in_value')) {
function reiss_replace_host_urls_in_value($value, $current_lang, $default_lang, $host, $supported_langs) {
if (is_array($value)) {
foreach ($value as $k => $v) {
$value[$k] = reiss_replace_host_urls_in_value($v, $current_lang, $default_lang, $host, $supported_langs);
}
return $value;
}
if (is_string($value) && preg_match('#^https?://#i', $value)) {
return reiss_localize_url($value, $current_lang, $default_lang, $host, $supported_langs);
}
return $value;
}
}
if (!function_exists('reiss_replace_host_urls_in_json_string')) {
function reiss_replace_host_urls_in_json_string($json, $current_lang, $default_lang, $host, $supported_langs) {
if (!is_string($json) || $json === '') {
return $json;
}
$host_no_trailing = rtrim($host, '/');
$host_quoted = preg_quote($host_no_trailing, '#');
foreach ($supported_langs as $lang_code) {
if ($lang_code === $default_lang) {
continue;
}
$json = preg_replace(
'#'.$host_quoted.'/' . preg_quote($lang_code, '#') . '(/?)#i',
$host_no_trailing . '$1',
$json
);
}
$path = reiss_get_current_lang_path();
$current_url = reiss_lang_url($host, $current_lang, $default_lang, $path);
$default_url = reiss_lang_url($host, $default_lang, $default_lang, $path);
$json = str_replace(
array(
wp_json_encode(rtrim($default_url, '/') . '/#article'),
wp_json_encode(rtrim($default_url, '/') . '/#breadcrumb'),
wp_json_encode(rtrim($default_url, '/') . '/#primaryimage'),
wp_json_encode(rtrim($default_url, '/') . '/#webpage'),
wp_json_encode(rtrim($default_url, '/') . '/')
),
array(
wp_json_encode(rtrim($current_url, '/') . '/#article'),
wp_json_encode(rtrim($current_url, '/') . '/#breadcrumb'),
wp_json_encode(rtrim($current_url, '/') . '/#primaryimage'),
wp_json_encode(rtrim($current_url, '/') . '/#webpage'),
wp_json_encode(rtrim($current_url, '/') . '/')
),
$json
);
$decoded = json_decode($json, true);
if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) {
$decoded = reiss_replace_host_urls_in_value($decoded, $current_lang, $default_lang, $host, $supported_langs);
return wp_json_encode($decoded, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
}
return $json;
}
}
if (!function_exists('reiss_get_current_url')) {
function reiss_get_current_url() {
return reiss_lang_url(
reiss_get_host(),
reiss_get_current_lang(),
reiss_get_default_lang(),
reiss_get_current_lang_path()
);
}
}
if (!function_exists('reiss_get_default_url')) {
function reiss_get_default_url() {
return reiss_lang_url(
reiss_get_host(),
reiss_get_default_lang(),
reiss_get_default_lang(),
reiss_get_current_lang_path()
);
}
}
if (!function_exists('reiss_get_current_og_locale')) {
function reiss_get_current_og_locale() {
$map = reiss_get_locale_map();
$lang = reiss_get_current_lang();
return isset($map[$lang]) ? $map[$lang] : 'en_US';
}
}
if (!function_exists('reiss_get_current_html_lang')) {
function reiss_get_current_html_lang() {
$map = reiss_get_html_lang_map();
$lang = reiss_get_current_lang();
return isset($map[$lang]) ? $map[$lang] : 'en';
}
}
if (!function_exists('reiss_get_schema_language')) {
function reiss_get_schema_language() {
$lang = reiss_get_current_lang();
if ($lang === 'en') {
return 'en-US';
}
$map = array(
'zh-cn' => 'zh-CN',
);
return isset($map[$lang]) ? $map[$lang] : $lang;
}
}
// =========================================================================
// Language Attributes
// =========================================================================
function reiss_filter_language_attributes($output) {
$html_lang = reiss_get_current_html_lang();
$output = preg_replace('/lang=("|\')[^"\']*("|\')/i', 'lang="' . esc_attr($html_lang) . '"', $output);
if (stripos($output, 'lang=') === false) {
$output .= ' lang="' . esc_attr($html_lang) . '"';
}
return $output;
}
add_filter('language_attributes', 'reiss_filter_language_attributes', 20);
// =========================================================================
// Yoast SEO Multilingual Fix - Base Filters
// =========================================================================
function reiss_filter_wpseo_canonical($canonical) {
if (is_search() || is_404()) {
return $canonical;
}
$current_lang = reiss_get_current_lang();
$default_lang = reiss_get_default_lang();
$host = reiss_get_host();
$current_path = reiss_get_current_lang_path();
$supported_langs = reiss_get_supported_langs();
if (!empty($canonical)) {
return reiss_localize_url($canonical, $current_lang, $default_lang, $host, $supported_langs);
}
return reiss_lang_url($host, $current_lang, $default_lang, $current_path);
}
add_filter('wpseo_canonical', 'reiss_filter_wpseo_canonical', 99);
function reiss_filter_wpseo_opengraph_url($url) {
$current_lang = reiss_get_current_lang();
$default_lang = reiss_get_default_lang();
$host = reiss_get_host();
$current_path = reiss_get_current_lang_path();
$supported_langs = reiss_get_supported_langs();
if (!empty($url)) {
return reiss_localize_url($url, $current_lang, $default_lang, $host, $supported_langs);
}
return reiss_lang_url($host, $current_lang, $default_lang, $current_path);
}
add_filter('wpseo_opengraph_url', 'reiss_filter_wpseo_opengraph_url', 99);
function reiss_filter_wpseo_locale($locale) {
return reiss_get_current_og_locale();
}
add_filter('wpseo_locale', 'reiss_filter_wpseo_locale', 99);
function reiss_filter_wpseo_schema_graph($graph) {
if (!is_array($graph)) {
return $graph;
}
$current_lang = reiss_get_current_lang();
$default_lang = reiss_get_default_lang();
$host = reiss_get_host();
$supported_langs = reiss_get_supported_langs();
$schema_lang = reiss_get_schema_language();
foreach ($graph as $i => $piece) {
$graph[$i] = reiss_replace_host_urls_in_value($piece, $current_lang, $default_lang, $host, $supported_langs);
if (is_array($graph[$i]) && isset($graph[$i]['inLanguage'])) {
$graph[$i]['inLanguage'] = $schema_lang;
}
}
return $graph;
}
add_filter('wpseo_schema_graph', 'reiss_filter_wpseo_schema_graph', 999);
function reiss_filter_wpseo_json_ld_output($data) {
if (!is_array($data)) {
return $data;
}
$current_lang = reiss_get_current_lang();
$default_lang = reiss_get_default_lang();
$host = reiss_get_host();
$supported_langs = reiss_get_supported_langs();
$schema_lang = reiss_get_schema_language();
$data = reiss_replace_host_urls_in_value($data, $current_lang, $default_lang, $host, $supported_langs);
if (!empty($data['@graph']) && is_array($data['@graph'])) {
foreach ($data['@graph'] as $index => $node) {
if (!is_array($node)) {
continue;
}
if (isset($node['inLanguage'])) {
$data['@graph'][$index]['inLanguage'] = $schema_lang;
}
$data['@graph'][$index] = reiss_replace_host_urls_in_value($node, $current_lang, $default_lang, $host, $supported_langs);
}
}
return $data;
}
add_filter('wpseo_json_ld_output', 'reiss_filter_wpseo_json_ld_output', 999);
// =========================================================================
// Yoast SEO Multilingual Fix - Final Head Output Override
// =========================================================================
if (!function_exists('reiss_start_wpseo_head_buffer')) {
function reiss_start_wpseo_head_buffer() {
ob_start('reiss_filter_wpseo_head_output');
}
}
if (!function_exists('reiss_end_wpseo_head_buffer')) {
function reiss_end_wpseo_head_buffer() {
if (ob_get_level() > 0) {
@ob_end_flush();
}
}
}
if (!function_exists('reiss_filter_wpseo_head_output')) {
function reiss_filter_wpseo_head_output($html) {
if (!is_string($html) || trim($html) === '') {
return $html;
}
if (strpos($html, 'yoast') === false && strpos($html, 'og:locale') === false && strpos($html, 'application/ld+json') === false) {
return $html;
}
$current_lang = reiss_get_current_lang();
$default_lang = reiss_get_default_lang();
$host = reiss_get_host();
$supported_langs = reiss_get_supported_langs();
$current_url = reiss_get_current_url();
$current_og_locale = reiss_get_current_og_locale();
$schema_lang = reiss_get_schema_language();
$html = preg_replace(
'##i',
'',
$html
);
$html = preg_replace(
'##i',
'',
$html
);
$html = preg_replace(
'##i',
'',
$html
);
$html = preg_replace_callback(
'##is',
function ($matches) use ($current_lang, $default_lang, $host, $supported_langs, $schema_lang) {
$script_open = preg_replace('#>(.*?)$#s', '>', $matches[0]);
$json = $matches[2];
$decoded = json_decode($json, true);
if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) {
$decoded = reiss_replace_host_urls_in_value($decoded, $current_lang, $default_lang, $host, $supported_langs);
if (!empty($decoded['@graph']) && is_array($decoded['@graph'])) {
foreach ($decoded['@graph'] as $i => $node) {
if (!is_array($node)) {
continue;
}
$decoded['@graph'][$i] = reiss_replace_host_urls_in_value($node, $current_lang, $default_lang, $host, $supported_langs);
if (isset($decoded['@graph'][$i]['inLanguage'])) {
$decoded['@graph'][$i]['inLanguage'] = $schema_lang;
}
}
} elseif (isset($decoded['inLanguage'])) {
$decoded['inLanguage'] = $schema_lang;
}
$json = wp_json_encode($decoded, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
} else {
$json = reiss_replace_host_urls_in_json_string($json, $current_lang, $default_lang, $host, $supported_langs);
}
return preg_replace(
'##is',
$script_open . $json . '',
$matches[0]
);
},
$html
);
return $html;
}
}
add_action('wpseo_head', 'reiss_start_wpseo_head_buffer', 0);
add_action('wpseo_head', 'reiss_end_wpseo_head_buffer', 999999);