PluginProbe
Translate and Go multilingual – Automatic AI translation – wpLingua / 2.10.0
Translate and Go multilingual – Automatic AI translation – wpLingua v2.10.0
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 / buffering.php

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

478 lines 10.5 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 * Redirect page if is called wiht an untranslate slug to the translated URL
11 *
12 * @return void
13 */
14 function wplng_redirect_translated_slug() {
15
16 if ( is_404() ) {
17 return;
18 }
19
20 $language_website_id = wplng_get_language_website_id();
21 $language_current_id = wplng_get_language_current_id();
22
23 if ( $language_website_id === $language_current_id ) {
24 return;
25 }
26
27 if ( empty( $_COOKIE['wplingua'] )
28 && apply_filters( 'wplng_cookie_check', true )
29 ) {
30 // Set HTTP no-cache header
31 nocache_headers();
32
33 // Disable cache for plugins
34 if ( ! defined( 'DONOTCACHEPAGE' ) ) {
35 define( 'DONOTCACHEPAGE', true );
36 }
37 }
38
39 $url_current = wplng_get_url_current();
40
41 if ( ! is_string( $url_current )
42 || '' === $url_current
43 || '/' === $url_current
44 ) {
45 return;
46 }
47
48 $url_translated = wplng_get_url_current_for_language(
49 $language_current_id
50 );
51
52 if ( $url_current === $url_translated ) {
53 return;
54 }
55
56 wp_safe_redirect(
57 wp_make_link_relative(
58 $url_translated
59 )
60 );
61
62 exit;
63 }
64
65
66 /**
67 * wpLingua output buffering starting function
68 *
69 * @return void
70 */
71 function wplng_ob_start() {
72
73 if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
74
75 /**
76 * Is an AJAX call
77 */
78
79 if ( empty( $_SERVER['HTTP_REFERER'] )
80 || ! is_string( $_SERVER['HTTP_REFERER'] )
81 ) {
82 return;
83 }
84
85 $referer = sanitize_url( $_SERVER['HTTP_REFERER'] );
86
87 // Check if the referer is clean
88 if ( strtolower( esc_url_raw( $referer ) ) !== strtolower( $referer ) ) {
89 return;
90 }
91
92 // Check AJAX action
93 if ( ! empty( $_POST['action'] )
94 && in_array( $_POST['action'], wplng_data_excluded_ajax_action() )
95 ) {
96 return;
97 }
98
99 global $wplng_request_uri;
100 $wplng_request_uri = wp_make_link_relative( $referer );
101
102 if ( ! wplng_url_is_translatable( $wplng_request_uri )
103 || wplng_get_language_website_id() === wplng_get_language_current_id()
104 ) {
105 return;
106 }
107
108 ob_start( 'wplng_ob_callback_ajax' );
109
110 } elseif ( wp_is_json_request() ) {
111
112 /**
113 * Is a REST API call
114 */
115
116 if ( empty( $_SERVER['HTTP_REFERER'] ) ) {
117 return;
118 }
119
120 $referer = sanitize_url( $_SERVER['HTTP_REFERER'] );
121
122 // Check if the referer is clean
123 if ( strtolower( esc_url_raw( $referer ) ) !== strtolower( $referer ) ) {
124 return;
125 }
126
127 global $wplng_request_uri;
128 $wplng_request_uri = wp_make_link_relative( $referer );
129
130 if ( ! wplng_url_is_translatable( $wplng_request_uri )
131 || wplng_get_language_website_id() === wplng_get_language_current_id()
132 ) {
133 return;
134 }
135
136 ob_start( 'wplng_ob_callback_wp_json' );
137
138 } elseif ( wplng_url_is_sitemap_xml() ) {
139
140 /**
141 * Is an XML sitemap
142 */
143
144 ob_start( 'wplng_ob_callback_sitemap_xml' );
145
146 } else {
147
148 /**
149 * Is a front call
150 */
151
152 if ( wplng_get_language_website_id() === wplng_get_language_current_id() ) {
153 return;
154 }
155
156 global $wplng_request_uri;
157 $current_path = $wplng_request_uri;
158
159 if ( ! is_string( $current_path ) ) {
160 return;
161 }
162
163 $origin_path = wplng_get_url_original( $current_path );
164
165 if ( ! wplng_url_is_translatable( $origin_path ) ) {
166 wp_safe_redirect( $origin_path );
167 exit;
168 }
169
170 $_SERVER['REQUEST_URI'] = $origin_path;
171
172 ob_start( 'wplng_ob_callback_page' );
173 }
174 }
175
176
177 /**
178 * wpLingua OB Callback function : AJAX call
179 *
180 * @param string $output
181 * @return string
182 */
183 function wplng_ob_callback_ajax( $output ) {
184
185 global $wplng_request_uri;
186
187 if ( wplng_str_is_json( $output ) ) {
188
189 $output_translated = wplng_translate_json( $output );
190
191 } elseif ( wplng_str_is_html( $output ) ) {
192
193 $output_translated = wplng_translate_html( $output );
194
195 } else {
196
197 $output_translated = $output;
198
199 }
200
201 // Print debug data in debug.log file
202 if ( true === WPLNG_DEBUG_AJAX ) {
203
204 $action = 'UNKNOW';
205 if ( ! empty( $_POST['action'] ) && is_string( $_POST['action'] ) ) {
206 $action = $_POST['action'];
207 }
208
209 $debug = array(
210 'title' => 'wpLingua AJAX debug',
211 'action' => $action,
212 'request_uri' => $wplng_request_uri,
213 'value' => $output,
214 'translated' => $output_translated,
215 );
216
217 error_log(
218 var_export(
219 $debug,
220 true
221 )
222 );
223 }
224
225 return $output_translated;
226 }
227
228
229 /**
230 * Callback function for output buffering to process and modify sitemap XML content.
231 *
232 * @param string $content The original XML content.
233 * @return string The modified XML content with added <xhtml:link> tags or the original content if no changes are made.
234 */
235 function wplng_ob_callback_sitemap_xml( $content ) {
236
237 // Return the content as is if it's empty or not valid XML.
238 if ( ! get_option( 'wplng_sitemap_xml', true )
239 || empty( $content )
240 || ! wplng_str_is_xml( $content )
241 ) {
242 return $content;
243 }
244
245 // Check if multilingual XML sitemap is enabled.
246 $sitemap_xml_enabled = apply_filters(
247 'wplng_enable_sitemap_xml_feature',
248 get_option( 'wplng_sitemap_xml', true )
249 );
250
251 if ( empty( $sitemap_xml_enabled ) ) {
252 return $content;
253 }
254
255 // Get language data.
256 $language_website_id = wplng_get_language_website_id();
257 $languages_target_ids = wplng_get_languages_target_ids();
258
259 if ( empty( $language_website_id ) || empty( $languages_target_ids ) ) {
260 return $content;
261 }
262
263 // Load the XML content into a DOMDocument.
264 $dom = new DOMDocument( '1.0', 'UTF-8' );
265 $dom->preserveWhiteSpace = false;
266 $dom->formatOutput = true;
267
268 // Enable internal error handling
269 $previous_libxml_setting = libxml_use_internal_errors( true );
270
271 // Check XML errors
272 if ( ! $dom->loadXML( $content ) ) {
273 if ( defined( 'WPLNG_DEBUG_XML' ) && true === WPLNG_DEBUG_XML ) {
274 $errors = array();
275
276 foreach ( libxml_get_errors() as $error ) {
277 $errors[] = $error->message;
278 }
279
280 libxml_clear_errors();
281
282 $debug = array(
283 'title' => 'wpLingua XML debug - Invalid XML content',
284 'errors' => $errors,
285 );
286
287 error_log( var_export( $debug, true ) );
288 }
289
290 return $content;
291 }
292
293 // Restore previous setting
294 libxml_use_internal_errors( $previous_libxml_setting );
295
296 $signature = '<!-- XML Sitemap is made multilingual by wpLingua -->' . PHP_EOL;
297
298 // Register namespaces and prepare XPath.
299 $xpath = new DOMXPath( $dom );
300 $xpath->registerNamespace( 'sm', 'http://www.sitemaps.org/schemas/sitemap/0.9' );
301 $xpath->registerNamespace( 'xhtml', 'http://www.w3.org/1999/xhtml' );
302
303 // Ensure the root element declares the required namespaces.
304 $urlset = $dom->documentElement;
305 if ( ! $urlset->hasAttribute( 'xmlns' ) ) {
306 $urlset->setAttribute( 'xmlns', 'http://www.sitemaps.org/schemas/sitemap/0.9' );
307 }
308 if ( ! $urlset->hasAttribute( 'xmlns:xhtml' ) ) {
309 $urlset->setAttribute( 'xmlns:xhtml', 'http://www.w3.org/1999/xhtml' );
310 }
311
312 // Get all <url> nodes.
313 $url_nodes = $xpath->query( '//sm:url' );
314
315 if ( empty( $url_nodes ) ) {
316 return $content . $signature;
317 }
318
319 foreach ( $url_nodes as $url_node ) {
320
321 // Get original URL.
322 $loc_node = $xpath->query( 'sm:loc', $url_node )->item( 0 );
323
324 if ( empty( $loc_node ) ) {
325 continue;
326 }
327
328 $url_original = trim( $loc_node->nodeValue );
329
330 if ( '' === $url_original || ! wplng_url_is_translatable( $url_original ) ) {
331 continue;
332 }
333
334 // Add link for original language.
335 $link_node = $dom->createElement( 'xhtml:link' );
336 $link_node->setAttribute( 'rel', 'alternate' );
337 $link_node->setAttribute( 'hreflang', esc_attr( $language_website_id ) );
338 $link_node->setAttribute( 'href', esc_url( $url_original ) );
339 $url_node->appendChild( $link_node );
340
341 // Add links for target languages.
342 foreach ( $languages_target_ids as $language_id ) {
343
344 $translated_url = wplng_url_translate(
345 $url_original,
346 $language_id
347 );
348
349 // Validate the translated URL.
350 if ( empty( $translated_url )
351 || ! filter_var( $translated_url, FILTER_VALIDATE_URL )
352 ) {
353 continue;
354 }
355
356 $link_node = $dom->createElement( 'xhtml:link' );
357 $link_node->setAttribute( 'rel', 'alternate' );
358 $link_node->setAttribute( 'hreflang', esc_attr( $language_id ) );
359 $link_node->setAttribute( 'href', esc_url( $translated_url ) );
360 $url_node->appendChild( $link_node );
361 }
362 }
363
364 $sitemap = $dom->saveXML();
365
366 if ( empty( $sitemap ) ) {
367 return $content;
368 }
369
370 return $sitemap . $signature;
371 }
372
373
374 /**
375 * wpLingua OB Callback function : Translate pages
376 *
377 * @param string $html
378 * @return string
379 */
380 function wplng_ob_callback_page( $content ) {
381
382 if ( wplng_str_is_json( $content ) ) {
383
384 $content = apply_filters( 'wplng_intercepted_json', $content );
385 $content = wplng_translate_json( $content );
386 $content = apply_filters( 'wplng_translated_json', $content );
387
388 } elseif ( wplng_str_is_html( $content ) ) {
389
390 $args = array();
391
392 if ( current_user_can( 'edit_posts' ) ) {
393
394 if ( ! empty( $_GET['wplng-mode'] ) ) {
395
396 switch ( $_GET['wplng-mode'] ) {
397
398 case 'editor':
399 $args['mode'] = 'editor';
400 break;
401
402 case 'list':
403 $args['mode'] = 'list';
404 break;
405 }
406 }
407
408 $load_in_progress_enabled = apply_filters(
409 'wplng_enable_in_progress_feature',
410 get_option( 'wplng_load_in_progress', false )
411 );
412
413 if ( $load_in_progress_enabled ) {
414
415 $args['load'] = 'enabled';
416
417 if ( ! empty( $_GET['wplng-load'] )
418 && (
419 $_GET['wplng-load'] === 'loading'
420 || $_GET['wplng-load'] === 'progress'
421 || $_GET['wplng-load'] === 'disabled'
422 )
423 ) {
424
425 $args['load'] = $_GET['wplng-load'];
426
427 wp_cache_flush();
428 }
429 }
430 }
431
432 $content = apply_filters( 'wplng_intercepted_html', $content );
433 $content = wplng_translate_html( $content, $args );
434 $content = apply_filters( 'wplng_translated_html', $content );
435
436 }
437
438 return $content;
439 }
440
441
442 /**
443 * wpLingua OB Callback function : /wp-json/
444 *
445 * @param string $output
446 * @return string
447 */
448 function wplng_ob_callback_wp_json( $output ) {
449
450 global $wplng_request_uri;
451
452 if ( wplng_str_is_json( $output ) ) {
453 $output_translated = wplng_translate_json( $output );
454 } else {
455 $output_translated = $output;
456 }
457
458 // Print debug data in debug.log file
459 if ( true === WPLNG_DEBUG_REST ) {
460
461 $debug = array(
462 'title' => 'wpLingua /wp-json/ debug',
463 'request_uri' => $wplng_request_uri,
464 'value' => $output,
465 'translated' => $output_translated,
466 );
467
468 error_log(
469 var_export(
470 $debug,
471 true
472 )
473 );
474 }
475
476 return $output_translated;
477 }
478