gptranslate
Last commit date
assets
11 months ago
flags
11 months ago
language
11 months ago
gptranslate.php
11 months ago
multilang-routing.php
11 months ago
readme.txt
11 months ago
serverside-translations.php
11 months ago
settings.php
11 months ago
simplehtmldom.php
11 months ago
uninstall.php
11 months ago
multilang-routing.php
566 lines
| 1 | <?php |
| 2 | /** |
| 3 | * GPTranslate - Multilang Routing System for WordPress |
| 4 | * Handles language prefixes in URLs like /it/, /fr/, /en/, etc. |
| 5 | * and maps them to internal pages, similar to Joomla LanguageFilter plugin. |
| 6 | */ |
| 7 | |
| 8 | if (!defined('ABSPATH')) exit; |
| 9 | |
| 10 | // Load only in frontend |
| 11 | if (! is_admin ()) { |
| 12 | $settings = get_option("gptranslate_options"); |
| 13 | |
| 14 | if ( ! function_exists( 'is_plugin_active' ) ) { |
| 15 | include_once ABSPATH . 'wp-admin/includes/plugin.php'; |
| 16 | } |
| 17 | $polylangActive = is_plugin_active( 'polylang/polylang.php' ); |
| 18 | |
| 19 | $enabledLanguages = $settings['languages'] ?? []; |
| 20 | |
| 21 | // Define supported languages (lowercase) |
| 22 | $gpt_supported_languages = array_map ( 'strtolower', [ |
| 23 | 'AF', |
| 24 | 'SQ', |
| 25 | 'AM', |
| 26 | 'AR', |
| 27 | 'HY', |
| 28 | 'AZ', |
| 29 | 'EU', |
| 30 | 'BE', |
| 31 | 'BN', |
| 32 | 'BS', |
| 33 | 'BG', |
| 34 | 'CA', |
| 35 | 'CEB', |
| 36 | 'NY', |
| 37 | 'ZH', |
| 38 | 'CO', |
| 39 | 'HR', |
| 40 | 'CS', |
| 41 | 'DA', |
| 42 | 'NL', |
| 43 | 'EN', |
| 44 | 'EO', |
| 45 | 'ET', |
| 46 | 'TL', |
| 47 | 'FI', |
| 48 | 'FR', |
| 49 | 'FY', |
| 50 | 'GL', |
| 51 | 'KA', |
| 52 | 'DE', |
| 53 | 'EL', |
| 54 | 'GU', |
| 55 | 'HT', |
| 56 | 'HA', |
| 57 | 'HAW', |
| 58 | 'IW', |
| 59 | 'HI', |
| 60 | 'HMN', |
| 61 | 'HU', |
| 62 | 'IS', |
| 63 | 'IG', |
| 64 | 'ID', |
| 65 | 'GA', |
| 66 | 'IT', |
| 67 | 'JA', |
| 68 | 'JW', |
| 69 | 'KN', |
| 70 | 'KK', |
| 71 | 'KM', |
| 72 | 'KO', |
| 73 | 'KU', |
| 74 | 'KY', |
| 75 | 'LO', |
| 76 | 'LA', |
| 77 | 'LV', |
| 78 | 'LT', |
| 79 | 'LB', |
| 80 | 'MK', |
| 81 | 'MG', |
| 82 | 'MS', |
| 83 | 'ML', |
| 84 | 'MT', |
| 85 | 'MI', |
| 86 | 'MR', |
| 87 | 'MN', |
| 88 | 'MY', |
| 89 | 'NE', |
| 90 | 'NO', |
| 91 | 'PS', |
| 92 | 'FA', |
| 93 | 'PL', |
| 94 | 'PT', |
| 95 | 'PA', |
| 96 | 'RO', |
| 97 | 'RU', |
| 98 | 'SM', |
| 99 | 'GD', |
| 100 | 'SR', |
| 101 | 'ST', |
| 102 | 'SN', |
| 103 | 'SD', |
| 104 | 'SI', |
| 105 | 'SK', |
| 106 | 'SL', |
| 107 | 'SO', |
| 108 | 'ES', |
| 109 | 'SU', |
| 110 | 'SW', |
| 111 | 'SV', |
| 112 | 'TG', |
| 113 | 'TA', |
| 114 | 'TE', |
| 115 | 'TH', |
| 116 | 'TR', |
| 117 | 'UK', |
| 118 | 'UR', |
| 119 | 'UZ', |
| 120 | 'VI', |
| 121 | 'CY', |
| 122 | 'XH', |
| 123 | 'YI', |
| 124 | 'YO', |
| 125 | 'ZU' |
| 126 | ] ); |
| 127 | |
| 128 | /** |
| 129 | * GPTranslate - Alias Translation Routing for WordPress |
| 130 | * This section augments the language prefix routing by checking translated aliases |
| 131 | * and routing them to the original page link. |
| 132 | */ |
| 133 | |
| 134 | add_action('init', function () use ($gpt_supported_languages, $polylangActive, $settings) { |
| 135 | if (is_admin()) return; |
| 136 | |
| 137 | global $wpdb; |
| 138 | |
| 139 | $subfolder = $settings['subfolder_installation'] ?? 0; |
| 140 | $rewriteAlias = $settings['rewrite_language_alias'] ?? 0; |
| 141 | $rewriteUrl = $settings['rewrite_language_url'] ?? 0; |
| 142 | $originalLang = $settings['language'] ?? 'en'; |
| 143 | |
| 144 | if (! $rewriteAlias || ! $rewriteUrl) return; |
| 145 | |
| 146 | $requestUri = urldecode($_SERVER['REQUEST_URI']) ?? ''; |
| 147 | $requestUri = sanitize_text_field(wp_unslash($requestUri)); |
| 148 | |
| 149 | // Remove subfolder if present |
| 150 | if ($subfolder) { |
| 151 | $homePath = wp_parse_url(home_url(), PHP_URL_PATH) ?? ''; |
| 152 | if ($homePath && strpos($requestUri, $homePath) === 0) { |
| 153 | $requestUri = substr($requestUri, strlen($homePath)); |
| 154 | } |
| 155 | } |
| 156 | |
| 157 | // Normalize path |
| 158 | $rawUri = rtrim(home_url() . $requestUri, '/'); |
| 159 | $rawUriWithSlash = $rawUri . '/'; |
| 160 | |
| 161 | $uri = isset($_SERVER['REQUEST_URI']) ? sanitize_text_field(wp_unslash($_SERVER['REQUEST_URI'])) : ''; |
| 162 | $pattern = '#^/(' . implode ( '|', array_map ( 'preg_quote', $gpt_supported_languages ) ) . ')(/.*)?$#i'; |
| 163 | |
| 164 | // Optional: remove subfolder if set |
| 165 | $subfolder_prefix = ''; // To hold subfolder if any |
| 166 | if ($settings['subfolder_installation']) { |
| 167 | $uri_parts = explode('/', ltrim($uri, '/')); |
| 168 | |
| 169 | // Remove the first part (subfolder name) |
| 170 | $subfolder_prefix = '/' . array_shift($uri_parts); |
| 171 | |
| 172 | // Rebuild URI without subfolder |
| 173 | $uri_to_match = '/' . implode('/', $uri_parts); |
| 174 | } else { |
| 175 | $uri_to_match = $uri; |
| 176 | } |
| 177 | |
| 178 | if (preg_match ( $pattern, $uri_to_match, $matches )) { |
| 179 | $currentLang = strtolower ( $matches [1] ); |
| 180 | } else { |
| 181 | return; |
| 182 | } |
| 183 | |
| 184 | // Check translated alias |
| 185 | $table = $wpdb->prefix . 'gptranslate'; |
| 186 | $query = $wpdb->prepare( |
| 187 | "SELECT pagelink FROM $table WHERE published = 1 AND languagetranslated = %s AND ( |
| 188 | translated_alias = %s OR translated_alias = %s)", |
| 189 | $currentLang, $rawUri, $rawUriWithSlash ); |
| 190 | |
| 191 | $originalPageLink = $wpdb->get_var($query); |
| 192 | |
| 193 | if (! $originalPageLink) return; |
| 194 | |
| 195 | // Extract path from URL |
| 196 | $parsed = wp_parse_url($originalPageLink); |
| 197 | $originalPath = $parsed['path'] ?? ''; |
| 198 | |
| 199 | // Remove subfolder prefix again from final path |
| 200 | if ($subfolder && !empty($homePath) && strpos($originalPath, $homePath) === 0) { |
| 201 | $originalPath = substr($originalPath, strlen($homePath)); |
| 202 | } |
| 203 | |
| 204 | // Clean path |
| 205 | $originalPath = preg_replace('#^/?index\.php/?#i', '', $originalPath); |
| 206 | $originalPath = '/' . ltrim($originalPath, '/'); |
| 207 | |
| 208 | // Rewrite the request |
| 209 | $_SERVER['REQUEST_URI'] = $originalPath; |
| 210 | }, 1); |
| 211 | |
| 212 | /** |
| 213 | * Detect language from URI and rewrite $_SERVER['REQUEST_URI'] accordingly defining a GPTRANSLATE_CURRENT_LANG constant |
| 214 | */ |
| 215 | add_action ( 'init', function () use ($gpt_supported_languages, $polylangActive, $settings) { |
| 216 | if (is_admin()) return; |
| 217 | |
| 218 | $uri = isset($_SERVER['REQUEST_URI']) ? sanitize_text_field(wp_unslash($_SERVER['REQUEST_URI'])) : ''; |
| 219 | $pattern = '#^/(' . implode ( '|', array_map ( 'preg_quote', $gpt_supported_languages ) ) . ')(/.*)?$#i'; |
| 220 | |
| 221 | // Optional: remove subfolder if set |
| 222 | $subfolder_prefix = ''; // To hold subfolder if any |
| 223 | if ($settings['subfolder_installation']) { |
| 224 | $uri_parts = explode('/', ltrim($uri, '/')); |
| 225 | |
| 226 | // Remove the first part (subfolder name) |
| 227 | $subfolder_prefix = '/' . array_shift($uri_parts); |
| 228 | |
| 229 | // Rebuild URI without subfolder |
| 230 | $uri_to_match = '/' . implode('/', $uri_parts); |
| 231 | } else { |
| 232 | $uri_to_match = $uri; |
| 233 | } |
| 234 | |
| 235 | if (preg_match ( $pattern, $uri_to_match, $matches )) { |
| 236 | $lang = strtolower ( $matches [1] ); |
| 237 | $new_uri = isset ( $matches [2] ) ? $matches [2] : '/'; |
| 238 | if ($settings ['rewrite_language_url'] == 1 && !$polylangActive) { |
| 239 | $_SERVER ['REQUEST_URI'] = $subfolder_prefix . $new_uri; |
| 240 | } |
| 241 | |
| 242 | if (! defined ( 'GPTRANSLATE_CURRENT_LANG' )) { |
| 243 | define ( 'GPTRANSLATE_CURRENT_LANG', $lang ); |
| 244 | } |
| 245 | } |
| 246 | }, 2); |
| 247 | |
| 248 | /** |
| 249 | * Replace and manage the lang attribute of the html tag |
| 250 | */ |
| 251 | add_filter ( 'language_attributes', function ($output) use ($settings, $polylangActive) { |
| 252 | if (! defined ( 'GPTRANSLATE_CURRENT_LANG' ) || (!$settings['set_html_lang'] && !$settings ['rewrite_language_url']) || $polylangActive) |
| 253 | return $output; |
| 254 | |
| 255 | $altflags_array = get_option ( 'gptranslate_options' ) ['alt_flags'] ?? [ ]; |
| 256 | |
| 257 | $lang_map = [ |
| 258 | // Variazioni per EN |
| 259 | 'en' => (in_array ( 'usa', $altflags_array ) || in_array ( 'canada', $altflags_array )) ? 'en-US' : 'en-GB', |
| 260 | |
| 261 | // Variazioni per FR |
| 262 | 'fr' => in_array ( 'quebec', $altflags_array ) ? 'fr-CA' : 'fr-FR', |
| 263 | |
| 264 | // Variazioni per PT |
| 265 | 'pt' => in_array ( 'brazil', $altflags_array ) ? 'pt-BR' : 'pt-PT', |
| 266 | |
| 267 | // Variazioni per ES |
| 268 | 'es' => in_array ( 'mexico', $altflags_array ) ? 'es-MX' : (in_array ( 'argentina', $altflags_array ) ? 'es-AR' : (in_array ( 'colombia', $altflags_array ) ? 'es-CO' : 'es-ES')), |
| 269 | |
| 270 | // Tutte le altre senza variazioni |
| 271 | 'af' => 'af-ZA', |
| 272 | 'sq' => 'sq-AL', |
| 273 | 'am' => 'am-ET', |
| 274 | 'ar' => 'ar-SA', |
| 275 | 'hy' => 'hy-AM', |
| 276 | 'az' => 'az-AZ', |
| 277 | 'eu' => 'eu-ES', |
| 278 | 'be' => 'be-BY', |
| 279 | 'bn' => 'bn-BD', |
| 280 | 'bs' => 'bs-BA', |
| 281 | 'bg' => 'bg-BG', |
| 282 | 'ca' => 'ca-ES', |
| 283 | 'ceb' => 'ceb-PH', |
| 284 | 'ny' => 'ny-MW', |
| 285 | 'zh' => 'zh-CN', |
| 286 | 'co' => 'co-FR', |
| 287 | 'hr' => 'hr-HR', |
| 288 | 'cs' => 'cs-CZ', |
| 289 | 'da' => 'da-DK', |
| 290 | 'nl' => 'nl-NL', |
| 291 | 'eo' => 'eo-EO', |
| 292 | 'et' => 'et-EE', |
| 293 | 'tl' => 'tl-PH', |
| 294 | 'fi' => 'fi-FI', |
| 295 | 'fy' => 'fy-NL', |
| 296 | 'gl' => 'gl-ES', |
| 297 | 'ka' => 'ka-GE', |
| 298 | 'de' => 'de-DE', |
| 299 | 'el' => 'el-GR', |
| 300 | 'gu' => 'gu-IN', |
| 301 | 'ht' => 'ht-HT', |
| 302 | 'ha' => 'ha-NG', |
| 303 | 'haw' => 'haw-US', |
| 304 | 'iw' => 'iw-IL', |
| 305 | 'hi' => 'hi-IN', |
| 306 | 'hmn' => 'hmn-US', |
| 307 | 'hu' => 'hu-HU', |
| 308 | 'is' => 'is-IS', |
| 309 | 'ig' => 'ig-NG', |
| 310 | 'id' => 'id-ID', |
| 311 | 'ga' => 'ga-IE', |
| 312 | 'it' => 'it-IT', |
| 313 | 'ja' => 'ja-JP', |
| 314 | 'jw' => 'jw-ID', |
| 315 | 'kn' => 'kn-IN', |
| 316 | 'kk' => 'kk-KZ', |
| 317 | 'km' => 'km-KH', |
| 318 | 'ko' => 'ko-KR', |
| 319 | 'ku' => 'ku-TR', |
| 320 | 'ky' => 'ky-KG', |
| 321 | 'lo' => 'lo-LA', |
| 322 | 'la' => 'la-VA', |
| 323 | 'lv' => 'lv-LV', |
| 324 | 'lt' => 'lt-LT', |
| 325 | 'lb' => 'lb-LU', |
| 326 | 'mk' => 'mk-MK', |
| 327 | 'mg' => 'mg-MG', |
| 328 | 'ms' => 'ms-MY', |
| 329 | 'ml' => 'ml-IN', |
| 330 | 'mt' => 'mt-MT', |
| 331 | 'mi' => 'mi-NZ', |
| 332 | 'mr' => 'mr-IN', |
| 333 | 'mn' => 'mn-MN', |
| 334 | 'my' => 'my-MM', |
| 335 | 'ne' => 'ne-NP', |
| 336 | 'no' => 'no-NO', |
| 337 | 'ps' => 'ps-AF', |
| 338 | 'fa' => 'fa-IR', |
| 339 | 'pl' => 'pl-PL', |
| 340 | 'pa' => 'pa-IN', |
| 341 | 'ro' => 'ro-RO', |
| 342 | 'ru' => 'ru-RU', |
| 343 | 'sm' => 'sm-WS', |
| 344 | 'gd' => 'gd-GB', |
| 345 | 'sr' => 'sr-RS', |
| 346 | 'st' => 'st-LS', |
| 347 | 'sn' => 'sn-ZW', |
| 348 | 'sd' => 'sd-PK', |
| 349 | 'si' => 'si-LK', |
| 350 | 'sk' => 'sk-SK', |
| 351 | 'sl' => 'sl-SI', |
| 352 | 'so' => 'so-SO', |
| 353 | 'su' => 'su-ID', |
| 354 | 'sw' => 'sw-TZ', |
| 355 | 'sv' => 'sv-SE', |
| 356 | 'tg' => 'tg-TJ', |
| 357 | 'ta' => 'ta-IN', |
| 358 | 'te' => 'te-IN', |
| 359 | 'th' => 'th-TH', |
| 360 | 'tr' => 'tr-TR', |
| 361 | 'uk' => 'uk-UA', |
| 362 | 'ur' => 'ur-PK', |
| 363 | 'uz' => 'uz-UZ', |
| 364 | 'vi' => 'vi-VN', |
| 365 | 'cy' => 'cy-GB', |
| 366 | 'xh' => 'xh-ZA', |
| 367 | 'yi' => 'yi-US', |
| 368 | 'yo' => 'yo-NG', |
| 369 | 'zu' => 'zu-ZA' |
| 370 | ]; |
| 371 | |
| 372 | $gpt_lang = strtolower ( GPTRANSLATE_CURRENT_LANG ); |
| 373 | $full_lang = $lang_map [$gpt_lang] ?? $gpt_lang; |
| 374 | |
| 375 | $output = 'lang="' . esc_attr ( $full_lang ) . '"'; |
| 376 | |
| 377 | return $output; |
| 378 | } ); |
| 379 | |
| 380 | /** |
| 381 | * Inject alternate hreflang links in <head> |
| 382 | */ |
| 383 | add_action ( 'wp_head', function () use ($enabledLanguages, $polylangActive, $settings) { |
| 384 | if (! defined ( 'GPTRANSLATE_CURRENT_LANG' ) || ! $settings ['add_alternate'] || ! $settings ['serverside_translations'] || $polylangActive) { |
| 385 | return; |
| 386 | } |
| 387 | |
| 388 | $current_lang = GPTRANSLATE_CURRENT_LANG; |
| 389 | $request_uri = isset($_SERVER['REQUEST_URI']) ? sanitize_text_field(wp_unslash($_SERVER['REQUEST_URI'])) : ''; |
| 390 | $request_path = sanitize_text_field ( wp_unslash ( $request_uri ) ); |
| 391 | |
| 392 | // Remove query string |
| 393 | $request_path = strtok ( $request_path, '?' ); |
| 394 | |
| 395 | // Optional subfolder cleanup |
| 396 | if (!empty($settings['subfolder_installation'])) { |
| 397 | $home_path = wp_parse_url(home_url(), PHP_URL_PATH) ?? ''; |
| 398 | if ($home_path && strpos($request_path, $home_path) === 0) { |
| 399 | $request_path = substr($request_path, strlen($home_path)); |
| 400 | } |
| 401 | } |
| 402 | |
| 403 | // Remove current language code from URL if present |
| 404 | $current_path = preg_replace ( '#^/' . preg_quote ( $current_lang, '#' ) . '(/|$)#', '/', $request_path ); |
| 405 | |
| 406 | $site_url = home_url (); |
| 407 | |
| 408 | foreach ( $enabledLanguages as $lang ) { |
| 409 | $translated_url = rtrim ( $site_url, '/' ) . '/' . $lang . rtrim ( $current_path, '/' ); |
| 410 | |
| 411 | echo '<link rel="alternate" hreflang="' . esc_attr ( $lang ) . '" href="' . esc_url ( $translated_url . '/' ) . "\" />\n"; |
| 412 | |
| 413 | if ($lang === $settings ['language']) { |
| 414 | echo '<link rel="alternate" hreflang="x-default" href="' . esc_url ( $translated_url . '/' ) . "\" />\n"; |
| 415 | } |
| 416 | } |
| 417 | } ); |
| 418 | |
| 419 | /** |
| 420 | * Handle the multilanguage URLs |
| 421 | */ |
| 422 | if ($settings ['rewrite_language_url'] == 1 && !$polylangActive) { |
| 423 | // Prevent WP to redirect |
| 424 | add_filter ( 'redirect_canonical', function ($redirect_url, $requested_url) use ($gpt_supported_languages) { |
| 425 | if (defined ( 'GPTRANSLATE_CURRENT_LANG' )) { |
| 426 | return false; |
| 427 | } |
| 428 | }, 10, 2 ); |
| 429 | |
| 430 | /** |
| 431 | * Add rewrite rules to allow /lang/ URLs |
| 432 | */ |
| 433 | add_filter ( 'rewrite_rules_array', function ($rules) use ($gpt_supported_languages) { |
| 434 | $new_rules = [ ]; |
| 435 | foreach ( $gpt_supported_languages as $lang ) { |
| 436 | $new_rules ["{$lang}/(.*)$"] = 'index.php?pagename=$matches[1]&gptlang=' . $lang; |
| 437 | $new_rules ["{$lang}$"] = 'index.php?gptlang=' . $lang; |
| 438 | } |
| 439 | return $new_rules + $rules; |
| 440 | } ); |
| 441 | |
| 442 | /** |
| 443 | * Redirect URLs without language prefix to default language |
| 444 | */ |
| 445 | add_action ( 'template_redirect', function () use ($gpt_supported_languages, $settings) { |
| 446 | $defaultOriginalLanguage = get_option ( 'gptranslate_options' ) ['language'] ?? 'en'; |
| 447 | |
| 448 | $default_lang = $defaultOriginalLanguage; |
| 449 | $uri = isset($_SERVER['REQUEST_URI']) ? sanitize_text_field(wp_unslash($_SERVER['REQUEST_URI'])) : ''; |
| 450 | |
| 451 | // Exceptions and management for subfolder installations |
| 452 | if($settings['subfolder_installation']) { |
| 453 | // Explode URI into parts |
| 454 | $uri_parts = explode('/', ltrim($uri, '/')); |
| 455 | |
| 456 | // Remove the first part (subfolder) |
| 457 | array_shift($uri_parts); |
| 458 | |
| 459 | // Rebuild the URI |
| 460 | $uri = '/' . implode('/', $uri_parts); |
| 461 | } |
| 462 | |
| 463 | // Avoid multiple redirects in the same session |
| 464 | if (! session_id ()) { |
| 465 | session_start (); |
| 466 | } |
| 467 | |
| 468 | if (! empty ( $_SESSION ['gptranslate_redirected'] ) && ($_SESSION ['gptranslate_redirected'] === $uri || $settings ['subfolder_installation'])) { |
| 469 | unset ( $_SESSION ['gptranslate_redirected'] ); |
| 470 | return; |
| 471 | } |
| 472 | |
| 473 | // Skip static assets and admin/API routes |
| 474 | if (preg_match ( '#\.(ico|png|jpe?g|gif|svg|css|js|woff2?|ttf|eot|mp4|webm)$#i', $uri ) || strpos ( $uri, '/wp-' ) === 0 || strpos ( $uri, '/wp-json/' ) === 0) { |
| 475 | return; |
| 476 | } |
| 477 | |
| 478 | // If a language has already been detected and defined, skip redirect |
| 479 | if (defined ( 'GPTRANSLATE_CURRENT_LANG' )) { |
| 480 | return; |
| 481 | } |
| 482 | |
| 483 | // Redirect to default language |
| 484 | $_SESSION ['gptranslate_redirected'] = $uri; |
| 485 | wp_redirect ( home_url ( "/{$default_lang}{$uri}" ), 301 ); |
| 486 | exit (); |
| 487 | } ); |
| 488 | |
| 489 | /** |
| 490 | * Add gptlang as a recognized query var |
| 491 | */ |
| 492 | add_filter ( 'query_vars', function ($vars) { |
| 493 | $vars [] = 'gptlang'; |
| 494 | return $vars; |
| 495 | } ); |
| 496 | |
| 497 | /** |
| 498 | * Helper function to get current language |
| 499 | */ |
| 500 | function gpt_get_current_lang() { |
| 501 | if (defined ( 'GPTRANSLATE_CURRENT_LANG' )) |
| 502 | return GPTRANSLATE_CURRENT_LANG; |
| 503 | $lang = get_query_var ( 'gptlang' ); |
| 504 | return $lang ?: 'en'; |
| 505 | } |
| 506 | |
| 507 | /** |
| 508 | * Rewrite internal links to include language prefix |
| 509 | */ |
| 510 | if ($settings ['rewrite_page_links'] == 1 && !$polylangActive) { |
| 511 | add_action('template_redirect', function () use ($gpt_supported_languages, $settings) { |
| 512 | ob_start(function ($html) use ($gpt_supported_languages, $settings) { |
| 513 | $current_lang = defined('GPTRANSLATE_CURRENT_LANG') ? GPTRANSLATE_CURRENT_LANG : ($settings['language'] ?? 'en'); |
| 514 | |
| 515 | $site_url = home_url(); |
| 516 | $parsed_site_url = wp_parse_url($site_url); |
| 517 | $base_path = rtrim($parsed_site_url['path'] ?? '', ''); |
| 518 | |
| 519 | return preg_replace_callback('#<a\s[^>]*href=["\']([^"\']+)["\']#i', function ($matches) use ($current_lang, $gpt_supported_languages, $parsed_site_url, $base_path, $site_url) { |
| 520 | $original_url = $matches[1]; |
| 521 | $url = $original_url; |
| 522 | |
| 523 | // Skip external URLs |
| 524 | if (preg_match('#^https?://#', $url) && strpos($url, $parsed_site_url['host']) === false) { |
| 525 | return $matches[0]; |
| 526 | } |
| 527 | |
| 528 | // Skip admin-related URLs |
| 529 | if (strpos($url, 'wp-admin') !== false || strpos($url, 'wp-login.php') !== false || strpos($url, 'wp-json') !== false) { |
| 530 | return $matches[0]; |
| 531 | } |
| 532 | |
| 533 | // Convert absolute local URL to relative |
| 534 | if (strpos($url, $parsed_site_url['scheme'] . '://' . $parsed_site_url['host']) === 0) { |
| 535 | $url = substr($url, strlen($parsed_site_url['scheme'] . '://' . $parsed_site_url['host'])); |
| 536 | } |
| 537 | |
| 538 | // Remove base path if present |
| 539 | if (!empty($base_path) && strpos($url, $base_path) === 0) { |
| 540 | $url = substr($url, strlen($base_path)); |
| 541 | } |
| 542 | |
| 543 | // Ensure it starts with / |
| 544 | if (strpos($url, '/') !== 0) { |
| 545 | return $matches[0]; // ignore non-relative, non-local URLs |
| 546 | } |
| 547 | |
| 548 | // Skip if already has a language prefix |
| 549 | foreach ($gpt_supported_languages as $lang) { |
| 550 | if (preg_match("#^/{$lang}(/|\$)#i", $url)) { |
| 551 | return $matches[0]; |
| 552 | } |
| 553 | } |
| 554 | |
| 555 | // Build new full absolute URL |
| 556 | $new_url = rtrim($site_url, '/') . '/' . $current_lang . $url; |
| 557 | |
| 558 | return str_replace($original_url, $new_url, $matches[0]); |
| 559 | |
| 560 | }, $html); |
| 561 | }); |
| 562 | }, 15); |
| 563 | } |
| 564 | } |
| 565 | } // end is_admin check |
| 566 |