PluginProbe
Translate and Go multilingual – Automatic AI translation – wpLingua / 2.16.6
Translate and Go multilingual – Automatic AI translation – wpLingua v2.16.6
2.16.6 2.16.5 2.16.4 2.16.3 2.16.2 2.16.1 2.16.0 2.15.2 2.15.1 2.15.0 2.14.3 2.14.2 2.14.1 2.14.0 2.13.1 2.13.0 2.12.3 2.12.2 2.12.1 trunk 1.0.3 1.0.4 1.0.5 1.1.0 1.1.1 All 111 releases
wplingua / inc / url.php

url.php in Translate and Go multilingual – Automatic AI translation – wpLingua 2.16.6, at inc/url.php

525 lines 12.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 // If this file is called directly, abort.
4 if ( ! defined( 'WPINC' ) ) {
5 die;
6 }
7
8
9 /**
10 * Add language ID in path while preserving WordPress home base path.
11 *
12 * @param string $path
13 * @param string $language_target_id
14 * @return string
15 */
16 function wplng_add_language_to_path( $path, $language_target_id ) {
17
18 if ( ! is_string( $path ) || '' === $path ) {
19 return '/' . $language_target_id . '/';
20 }
21
22 $path_only = $path;
23 $suffix = '';
24
25 $query_pos = strpos( $path_only, '?' );
26 $fragment_pos = strpos( $path_only, '#' );
27 $cut_pos = false;
28
29 if ( false !== $query_pos && false !== $fragment_pos ) {
30 $cut_pos = min( $query_pos, $fragment_pos );
31 } elseif ( false !== $query_pos ) {
32 $cut_pos = $query_pos;
33 } elseif ( false !== $fragment_pos ) {
34 $cut_pos = $fragment_pos;
35 }
36
37 if ( false !== $cut_pos ) {
38 $path_only = substr( $path_only, 0, $cut_pos );
39 $suffix = substr( $path, $cut_pos );
40 }
41
42 $home_base_path = wplng_get_home_base_path();
43 $home_base_with_slash = trailingslashit( $home_base_path );
44
45 if ( '' !== $home_base_path
46 && ( $path_only === $home_base_path
47 || wplng_str_starts_with( $path_only, $home_base_with_slash ) )
48 ) {
49 $path_after_base = substr( $path_only, strlen( $home_base_with_slash ) );
50 $path_only = $home_base_with_slash . $language_target_id . '/';
51
52 if ( '' !== $path_after_base ) {
53 $path_only .= ltrim( $path_after_base, '/' );
54 }
55 } elseif ( wplng_str_starts_with( $path_only, '/' ) ) {
56 $path_only = '/' . $language_target_id . '/' . ltrim( $path_only, '/' );
57 } else {
58 $path_only = $language_target_id . '/' . $path_only;
59 }
60
61 $path_only = preg_replace( '#//+#', '/', $path_only );
62
63 return $path_only . $suffix;
64 }
65
66
67 /**
68 * Get the translated URL
69 *
70 * @param string $url
71 * @param string $language_target_id
72 * @return string Translated URL
73 */
74 function wplng_url_translate( $url, $language_target_id = '' ) {
75 return apply_filters(
76 'wplng_url_translate',
77 wplng_url_translate_no_filter(
78 $url,
79 $language_target_id
80 )
81 );
82 }
83
84
85 /**
86 * Get the translated URL - No apply 'wplng_url_translate' filter
87 *
88 * @param string $url
89 * @param string $language_target_id
90 * @return string Translated URL
91 */
92 function wplng_url_translate_no_filter( $url, $language_target_id = '' ) {
93
94 // Check if URL is an empty string
95 if ( '' === $url ) {
96 return '';
97 }
98
99 // Get current target ID if not set
100 if ( '' === $language_target_id ) {
101 $language_target_id = wplng_get_language_current_id();
102 }
103
104 // Apply links / Medias rules
105 $url_link_media_applied = wplng_link_media_apply_rules(
106 $url,
107 $language_target_id
108 );
109
110 // Check if a links / Medias rules was applied
111 if ( $url_link_media_applied !== $url ) {
112 return $url_link_media_applied;
113 }
114
115 // Check if URL is not translatable (exclude /admin/, ...)
116 if ( ! wplng_url_is_translatable( $url ) ) {
117 return $url;
118 }
119
120 $languages_target = wplng_get_languages_target();
121 $home_base_path = wplng_get_home_base_path();
122
123 static $preg_domain = null;
124 static $parsed_url_home = null;
125
126 if ( null === $parsed_url_home ) {
127 $parsed_url_home = wp_parse_url( home_url() );
128 $preg_domain = '';
129 if ( isset( $parsed_url_home['host'] )
130 && is_string( $parsed_url_home['host'] )
131 ) {
132 $preg_domain = preg_quote( $parsed_url_home['host'] );
133 }
134 }
135
136 if ( ! empty( $preg_domain )
137 && preg_match( '#^(http:\/\/|https:\/\/)?' . $preg_domain . '(.*)$#', $url )
138 ) {
139
140 /**
141 * It's an URL starting y a domain name
142 */
143
144 // Check if URL is already translated
145 foreach ( $languages_target as $language_target ) {
146 if ( wplng_str_contains( $url, '/' . $language_target['id'] . '/' ) ) {
147 return $url;
148 }
149 }
150
151 $parsed_url = wp_parse_url( $url );
152
153 if ( '' === $home_base_path ) {
154
155 if ( ! empty( $parsed_url['path'] ) ) {
156 $url = str_replace(
157 $parsed_url['path'],
158 wplng_slug_translate_path(
159 $parsed_url['path'],
160 $language_target_id
161 ),
162 $url
163 );
164 }
165
166 $url = preg_replace(
167 '#^(http:\/\/|https:\/\/)?' . $preg_domain . '(.*)$#',
168 '${1}' . $parsed_url_home['host'] . '/' . $language_target_id . '${2}',
169 $url
170 );
171
172 } else {
173
174 $path = '/';
175
176 if ( ! empty( $parsed_url['path'] ) ) {
177 $path = $parsed_url['path'];
178 }
179
180 $path = wplng_slug_translate_path(
181 $path,
182 $language_target_id
183 );
184
185 $path = wplng_add_language_to_path(
186 $path,
187 $language_target_id
188 );
189
190 if ( ! empty( $parsed_url['path'] ) ) {
191 $url = str_replace( $parsed_url['path'], $path, $url );
192 } else {
193 $url = untrailingslashit( $url ) . $path;
194 }
195 }
196
197 if ( empty( $parsed_url['fragment'] )
198 && empty( $parsed_url['query'] )
199 ) {
200 // Add slash at the end if is not an anchor link
201 $url = trailingslashit( $url );
202 }
203 } elseif ( preg_match( '#^[^\/]+\/[^\/].*$|^\/[^\/].*$#', $url ) ) {
204
205 /**
206 * It's a path
207 */
208
209 // Check if URL is already translated
210 foreach ( $languages_target as $language_target ) {
211 if ( wplng_str_starts_with( $url, '/' . $language_target['id'] . '/' )
212 || wplng_str_starts_with( $url, $language_target['id'] . '/' )
213 ) {
214 return $url;
215 }
216 }
217
218 $url = wplng_slug_translate_path(
219 $url,
220 $language_target_id
221 );
222
223 if ( '' === $home_base_path ) {
224 if ( wplng_str_starts_with( $url, '/' ) ) {
225 $url = '/' . $language_target_id . $url;
226 } else {
227 $url = $language_target_id . '/' . $url;
228 }
229 } else {
230 $url = wplng_add_language_to_path(
231 $url,
232 $language_target_id
233 );
234 }
235 }
236
237 return $url;
238 }
239
240
241 /**
242 * Return true is $url is translatable
243 *
244 * @param string $url
245 * @return bool
246 */
247 function wplng_url_is_translatable( $url = '' ) {
248
249 global $wplng_request_uri;
250
251 // Get current URL if $url is empty
252 if ( '' === $url ) {
253 $url = sanitize_url( $wplng_request_uri );
254 }
255
256 $url = trailingslashit( $url );
257 $url = wp_make_link_relative( $url );
258 $url = strtolower( $url );
259
260 return apply_filters(
261 'wplng_url_is_translatable',
262 wplng_url_is_translatable_no_filter( $url ),
263 $url
264 );
265 }
266
267
268 /**
269 * Return true is $url is translatable - No apply 'wplng_url_translate' filter
270 *
271 * @param string $url
272 * @return bool
273 */
274 function wplng_url_is_translatable_no_filter( $url ) {
275
276 // Check if is an admin page
277 if ( wplng_str_contains( $url, wp_make_link_relative( get_admin_url() ) ) ) {
278 return false;
279 }
280
281 // Check if URL is an anchor link for the current page
282 if ( wplng_str_starts_with( $url, '#' ) ) {
283 return false;
284 }
285
286 // Don't translate some WordPress and WooCommerce URLs
287 // admin, REST API, rss and other special URLs
288 if ( wplng_str_contains( $url, 'wp-login.php' )
289 || wplng_str_contains( $url, 'wp-register.php' )
290 || wplng_str_contains( $url, 'wp-comments-post.php' )
291 || wplng_str_contains( $url, 'wp-cron.php' )
292 || wplng_str_contains( $url, '?doing_wp_cron=' )
293 || wplng_str_contains( $url, '&doing_wp_cron=' )
294 || wplng_str_contains( $url, 'xmlrpc.php' )
295 || wplng_str_ends_with( $url, '/feed/' )
296 || wplng_str_contains( $url, '/wp-json/' )
297 || wplng_str_contains( $url, '/wp-includes/' )
298 || wplng_str_contains( $url, '/oembed/' )
299 || wplng_str_contains( $url, '?wc-ajax=' )
300 || wplng_str_contains( $url, '?feed=' )
301 || wplng_str_contains( $url, '?embed=' )
302 || wplng_str_contains( $url, '&wc-ajax=' )
303 || wplng_str_contains( $url, '&feed=' )
304 || wplng_str_contains( $url, '&embed=' )
305 || wplng_str_contains( $url, 'builder=true&builder_id=' ) // Fusion builder
306 ) {
307 return false;
308 }
309
310 // Check if is Divi editor
311 if ( current_user_can( 'edit_posts' )
312 && (
313 wplng_str_contains( $url, '/?et_fb=1' )
314 || wplng_str_contains( $url, '&et_fb=1' )
315 )
316 ) {
317 return false;
318 }
319
320 // Check if is in wp-uploads
321 if ( wplng_str_contains( $url, wp_make_link_relative( content_url() ) ) ) {
322 return false;
323 }
324
325 // Exclude files URL
326 $regex_is_file = '#\.(avi|css|js|map|docx?|exe|gif|html?|jfif|jpe?g|webp|bmp|midi?|mp3|mpe?g|avif|mov|qt|pdf|png|ra?m|rar|tiff?|txt|wav|zip|ico|xml|rss|xls[x]?|ttf|otf|woff2?|eot|svg)\/$#i';
327
328 if ( preg_match( $regex_is_file, $url ) ) {
329 return false;
330 }
331
332 // Check if URL is excluded in option page
333 $url_original = wplng_get_url_original( $url );
334 $url_exclude_regex = wplng_get_url_exclude_regex();
335
336 foreach ( $url_exclude_regex as $regex ) {
337 if ( preg_match( $regex, $url_original ) ) {
338 return false;
339 }
340 }
341
342 return true;
343 }
344
345
346 /**
347 * Get the REGEX list of excluded URLs
348 *
349 * @return array
350 */
351 function wplng_get_url_exclude_regex() {
352
353 global $wplng_url_exclude_regex;
354
355 if ( null !== $wplng_url_exclude_regex ) {
356 return $wplng_url_exclude_regex;
357 }
358
359 $url_exclude = array();
360
361 // Get, check and sanitize excluded URL REGEX as string
362 $option = get_option( 'wplng_excluded_url' );
363 if ( empty( $option ) || ! is_string( $option ) ) {
364 $option = '';
365 } else {
366 $option = sanitize_textarea_field( $option );
367 }
368
369 // Get exclude URL REGEX as array
370 $option = explode( PHP_EOL, $option );
371
372 // Check each URL REGEX
373 foreach ( $option as $regex ) {
374 $regex = trim( $regex );
375 if ( '' !== $regex && false !== @preg_match( '#' . $regex . '#', '' ) ) {
376 $url_exclude[] = '#' . $regex . '#';
377 }
378 }
379
380 // Remove duplicate
381 $url_exclude = array_unique( $url_exclude );
382
383 // Apply wplng_url_exclude_regex filter
384 $url_exclude = apply_filters(
385 'wplng_url_exclude_regex',
386 $url_exclude
387 );
388
389 $wplng_url_exclude_regex = $url_exclude;
390
391 return $url_exclude;
392 }
393
394
395 /**
396 * Get the untranslated / original URL
397 *
398 * @param string $url
399 * @return string
400 */
401 function wplng_get_url_original( $url = '' ) {
402
403 if ( '' === $url ) {
404 $url = wplng_get_url_current();
405 }
406
407 $target = wplng_get_languages_target_ids();
408
409 foreach ( $target as $target_id ) {
410
411 if ( ! wplng_str_contains( $url, '/' . $target_id . '/' ) ) {
412 continue;
413 }
414
415 $url = str_replace(
416 '/' . $target_id . '/',
417 '/',
418 $url
419 );
420
421 $parsed_url = wp_parse_url( $url );
422
423 if ( isset( $parsed_url['path'] )
424 && $parsed_url['path'] !== ''
425 && $parsed_url['path'] !== '/'
426 ) {
427
428 $url = str_replace(
429 $parsed_url['path'],
430 wplng_slug_original_path(
431 $parsed_url['path'],
432 $target_id
433 ),
434 $url
435 );
436 }
437
438 break;
439 }
440
441 $url = apply_filters(
442 'wplng_url_original',
443 $url
444 );
445
446 return $url;
447 }
448
449
450 /**
451 * Get current path
452 *
453 * @return string
454 */
455 function wplng_get_path_current() {
456 global $wplng_request_uri;
457 return $wplng_request_uri;
458 }
459
460
461 /**
462 * Get current URL
463 *
464 * @return string
465 */
466 function wplng_get_url_current() {
467 return home_url( wplng_get_path_current() );
468 }
469
470
471 /**
472 * Get the URL translated in specified language
473 *
474 * @param string $language_id
475 * @return string
476 */
477 function wplng_get_url_current_for_language( $language_id ) {
478 return wplng_url_translate(
479 wplng_get_url_original(),
480 $language_id
481 );
482 }
483
484
485 /**
486 * Determines whether a given URL points to a sitemap XML file.
487 *
488 * This function checks if the URL matches common sitemap naming patterns such as:
489 * - sitemap.xml
490 * - sitemap_index.xml
491 * - sitemap-posts.xml
492 * - posts-sitemap.xml
493 * and similar variations.
494 *
495 * If no URL is provided, the current URL will be used.
496 * The check ignores query parameters and anchors.
497 *
498 * @param string $url The URL to check. Defaults to the current URL if empty.
499 * @return bool True if the URL is identified as a sitemap, false otherwise.
500 */
501 function wplng_url_is_sitemap_xml( $url = '' ) {
502
503 if ( '' === $url ) {
504 $url = wplng_get_url_current();
505 }
506
507 // Normalize the URL: convert to lowercase
508 $url = strtolower( $url );
509
510 // Remove GET parameters and anchors
511 $parsed_url = wp_parse_url( $url );
512 $url_path = isset( $parsed_url['path'] ) ? $parsed_url['path'] : '';
513
514 // Check if the URL matches common sitemap patterns
515 $is_sitemap = wplng_str_contains( $url_path, 'sitemap' ) && wplng_str_contains( $url_path, '.xml' );
516
517 /**
518 * Filter to allow customization of the sitemap detection logic
519 *
520 * @param bool $is_sitemap Whether the URL is a sitemap.
521 * @param string $url The URL being checked.
522 */
523 return apply_filters( 'wplng_url_is_sitemap_xml', $is_sitemap, $url );
524 }
525