PluginProbe
Linguise – AI Automatic Multilingual Translation / 2.2.63
Linguise – AI Automatic Multilingual Translation v2.2.63
2.2.63 2.2.62 2.2.61 2.2.60 2.2.59 2.2.58 2.2.57 2.2.56 2.2.55 2.2.54 2.2.53 2.2.52 2.2.51 2.2.50 2.2.49 2.2.47 2.2.48 2.2.46 2.2.45 2.2.44 2.2.43 2.2.42 1.9.7 1.9.8 1.9.9 All 254 releases
linguise / linguise.php

linguise.php in Linguise – AI Automatic Multilingual Translation 2.2.63, at linguise.php

842 lines 31.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Plugin Name: Linguise
5 * Plugin URI: https://www.linguise.com/
6 * Description: Linguise translation plugin
7 * Version:2.2.63
8 * Text Domain: linguise
9 * Domain Path: /languages
10 * Author: Linguise
11 * Author URI: https://www.linguise.com/
12 * License: GPL2
13 */
14
15 use Linguise\Vendor\Linguise\Script\Core\Configuration;
16 use Linguise\Vendor\Linguise\Script\Core\Database;
17 use Linguise\Vendor\Linguise\Script\Core\Request;
18 use Linguise\WordPress\Helper as WPHelper;
19 use Linguise\WordPress\LinguiseSwitcher;
20
21 defined('ABSPATH') || die('');
22
23 include_once plugin_dir_path(__FILE__) . 'src' . DIRECTORY_SEPARATOR . 'Helper.php';
24 include_once plugin_dir_path(__FILE__) . 'src' . DIRECTORY_SEPARATOR . 'constants.php';
25
26 // Check plugin requirements
27 $curlInstalled = function_exists('curl_version');
28 $phpVersionOk = version_compare(PHP_VERSION, '7.0', '>=');
29 if (!$curlInstalled || !$phpVersionOk) {
30 add_action('admin_init', function () {
31 if (current_user_can('activate_plugins') && is_plugin_active(plugin_basename(__FILE__))) {
32 deactivate_plugins(__FILE__);
33 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Internal function used
34 unset($_GET['activate']);
35 }
36 });
37 add_action('admin_notices', function () use ($curlInstalled, $phpVersionOk) {
38 echo '<div class="error">';
39 if (!$curlInstalled) {
40 echo '<p><strong>Curl php extension is required</strong> to install Linguise, please make sure to install it before installing Linguise again.</p>';
41 }
42 if (!$phpVersionOk) {
43 echo '<p><strong>PHP 7.0 is the minimal version required</strong> to install Linguise, please make sure to update your PHP version before installing Linguise.</p>';
44 }
45 echo '</div>';
46 });
47 // Do not load anything more
48 return;
49 }
50
51 define('LINGUISE_PLUGIN_URL', plugin_dir_url(__FILE__));
52 define('LINGUISE_PLUGIN_PATH', plugin_dir_path(__FILE__));
53
54 register_activation_hook(__FILE__, function () {
55 if (!get_option('linguise_install_time', false)) {
56 add_option('linguise_install_time', time());
57 }
58 });
59
60 include_once(__DIR__ . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'install.php');
61
62 /**
63 * Check if we are in subfolders multisite
64 *
65 * @return boolean
66 */
67 function linguiseIsMultisiteFolder()
68 {
69 // Is multisite subdomains mode or subfolders mode
70 $linguise_multisite_subdomains = defined('SUBDOMAIN_INSTALL') && SUBDOMAIN_INSTALL;
71
72 if (is_multisite()) {
73 if ($linguise_multisite_subdomains) {
74 return false;
75 }
76
77 $cached_is_subdomain = get_transient('linguise_multisite_subdomain');
78 if ($cached_is_subdomain === '1') {
79 return false;
80 } elseif ($cached_is_subdomain === '0') {
81 // Cached as false, so we need to check the sites
82 return true;
83 }
84
85 // Not cached yet, so we need to check the sites
86 /**
87 * Get all sites in the multisite network
88 *
89 * @var \WP_Site[]
90 */
91 $sites = get_sites();
92 $main_site_id = get_main_site_id();
93 $current_site_id = get_current_blog_id();
94
95 $current_site_domain = null;
96 $main_site_domain = null;
97 foreach ($sites as $site) {
98 if ((int)$site->blog_id === $current_site_id) {
99 $current_site_domain = $site->domain;
100 }
101 if ((int)$site->blog_id === $main_site_id) {
102 $main_site_domain = $site->domain;
103 }
104 }
105
106 // If we are in subdomain multisite, we need to check if the current site domain is different from the main site domain
107 if (!empty($current_site_domain) && !empty($main_site_domain) && $current_site_domain !== $main_site_domain) {
108 set_transient('linguise_multisite_subdomain', '1', DAY_IN_SECONDS);
109 return false;
110 }
111
112 set_transient('linguise_multisite_subdomain', '0', DAY_IN_SECONDS);
113 return true;
114 }
115
116 return false;
117 }
118
119 /**
120 * Switch Linguise to use main site information
121 *
122 * This will only switch if we are in subfolders multisite
123 *
124 * Remember to use linguiseRestoreMultisite() after
125 *
126 * @return void
127 */
128 function linguiseSwitchMainSite()
129 {
130 // Multisite compatible with subfolders install
131 if (linguiseIsMultisiteFolder()) {
132 $main_site = get_main_site_id(get_current_network_id());
133
134 switch_to_blog($main_site);
135 }
136 }
137
138 /**
139 * Restore Multisite
140 *
141 * This will only restore if we are in subfolders multisite
142 *
143 * @return void
144 */
145 function linguiseRestoreMultisite()
146 {
147 if (linguiseIsMultisiteFolder()) {
148 restore_current_blog();
149 }
150 }
151
152 /**
153 * Return the site URL, or the site URL with the given path.
154 *
155 * Wraps `home_url` if exists, otherwise use `site_url`.
156 *
157 * @param string $path The path to add to the site URL.
158 * @param string|null $scheme The scheme to use (http or https).
159 *
160 * @return string
161 */
162 function linguiseGetSite($path = '', $scheme = \null)
163 {
164 if (function_exists('home_url')) {
165 return home_url($path, $scheme);
166 }
167 return site_url($path, $scheme);
168 }
169
170 /**
171 * Get options
172 *
173 * @return array|mixed|void
174 */
175 function linguiseGetOptions()
176 {
177 $defaults = array(
178 'token' => '',
179 'default_language' => 'en',
180 'enabled_languages' => array(),
181 'flag_display_type' => 'popup',
182 'display_position' => 'bottom_right',
183 'enable_flag' => 1,
184 'enable_language_name' => 1,
185 'enable_language_name_popup' => 1,
186 'enable_language_short_name' => 0,
187 'flag_shape' => 'rounded',
188 'flag_en_type' => 'en-us',
189 'flag_de_type' => 'de',
190 'flag_es_type' => 'es',
191 'flag_pt_type' => 'pt',
192 'flag_tw_type' => 'zh-tw',
193 'flag_border_radius' => 0,
194 'flag_width' => 24,
195 'browser_redirect' => 0,
196 'ukraine_redirect' => 0,
197 'cookies_redirect' => 0,
198 'language_name_display' => 'en',
199 'pre_text' => '',
200 'post_text' => '',
201 'alternate_link' => 1,
202 'add_flag_automatically' => 1,
203 'custom_css' => '',
204 'cache_enabled' => 1,
205 'cache_max_size' => 200,
206 'cache_ignore_parameters' => 0,
207 'cache_params_always_included' => 's,utm_source,utm_medium,utm_campaign,utm_term,utm_content',
208 'language_name_color' => '#222',
209 'language_name_hover_color' => '#222',
210 'popup_language_name_color' => '#222',
211 'popup_language_name_hover_color' => '#222',
212 'flag_shadow_h' => 2,
213 'flag_shadow_v' => 2,
214 'flag_shadow_blur' => 12,
215 'flag_shadow_spread' => 0,
216 'flag_shadow_color' => '#eee',
217 'flag_shadow_color_alpha' => (float)1.0, // we use 100% scaling, 0.0-1.0
218 'flag_hover_shadow_h' => 3,
219 'flag_hover_shadow_v' => 3,
220 'flag_hover_shadow_blur' => 6,
221 'flag_hover_shadow_spread' => 0,
222 'flag_hover_shadow_color' => '#bfbfbf',
223 'flag_hover_shadow_color_alpha' => (float)1.0,
224 'search_translation' => 0,
225 'debug' => false,
226 'woocommerce_emails_translation' => 0,
227 'dynamic_translations' => [
228 'enabled' => 0,
229 'public_key' => '',
230 ],
231 // empty array that will be filled with the expert mode options
232 'expert_mode' => [],
233 );
234
235 // Switch to main site
236 linguiseSwitchMainSite();
237
238 $options = get_option('linguise_options');
239 if (!empty($options) && is_array($options)) {
240 $options = array_merge($defaults, $options);
241 } else {
242 $options = $defaults;
243 }
244
245 // Restore multisite
246 linguiseRestoreMultisite();
247
248 return $options;
249 }
250
251 /**
252 * Log message to debug log if debug is enabled
253 *
254 * Based on: https://developer.wordpress.org/advanced-administration/debug/debug-wordpress/
255 *
256 * @param mixed $data Data to log
257 *
258 * @return void
259 */
260 function linguiseErrorLog($data)
261 {
262 if (true === WP_DEBUG) {
263 if (is_array($data) || is_object($data)) {
264 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r,WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Debug function
265 error_log(print_r($data, true));
266 } else {
267 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Debug function
268 error_log($data);
269 }
270 }
271 }
272
273 /**
274 * Load either local config or default config
275 *
276 * Used anywhere in the plugin that needs to load configuration before doing anything.
277 *
278 * @return void
279 */
280 function linguiseInitializeConfiguration()
281 {
282 if (!defined('LINGUISE_SCRIPT_TRANSLATION')) {
283 define('LINGUISE_SCRIPT_TRANSLATION', true);
284 }
285
286 require_once(__DIR__ . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php');
287
288 // Explicitely set the CMS to WordPress
289 Configuration::getInstance()->set('cms', 'wordpress');
290 // Set base directory to Wordpress root
291 Configuration::getInstance()->set('base_dir', realpath(__DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..') . DIRECTORY_SEPARATOR);
292
293 // Switch to main site
294 linguiseSwitchMainSite();
295
296 // Get token
297 $host = array_key_exists('HTTP_HOST', $_SERVER) ? $_SERVER['HTTP_HOST'] : wp_parse_url(linguiseGetSite(), PHP_URL_HOST);
298 $token = Database::getInstance()->retrieveWordpressOption('token', $host);
299
300 // Data folder in script folder
301 $data_folder_in_script_folder = __DIR__ . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'linguise' . DIRECTORY_SEPARATOR . 'script-php' . DIRECTORY_SEPARATOR . md5('data' . $token);
302 // Data folder in WP upload folder
303 $linguise_upload_dir = wp_upload_dir()['basedir'] . DIRECTORY_SEPARATOR . 'linguise';
304 $data_folder_in_upload_folder = $linguise_upload_dir . DIRECTORY_SEPARATOR . md5('data' . $token);
305
306 // By default, we will use the data folder in upload folder
307 $data_folder = $data_folder_in_upload_folder;
308
309 // Check if data has already been saved for this site (if not create the new linguise root)
310 if (!file_exists($data_folder_in_upload_folder) && file_exists($data_folder_in_script_folder) && mkdir($linguise_upload_dir, 0755, true)) {
311 $success = rename($data_folder_in_script_folder, $data_folder_in_upload_folder);
312 if ($success) {
313 // Then move the data
314 $index_html_made = file_put_contents($data_folder_in_upload_folder . DIRECTORY_SEPARATOR . 'index.html', '');
315 if ($index_html_made === false) {
316 linguiseErrorLog('Linguise: Failed to create index.html in ' . $data_folder_in_upload_folder);
317 }
318 } else {
319 // If the move failed, we will use the old location
320 linguiseErrorLog('Linguise: Failed to move data folder to upload directory in ' . $data_folder_in_upload_folder . ', using script folder instead.');
321 $data_folder = $data_folder_in_script_folder;
322 }
323 }
324
325 if (!file_exists($data_folder) && mkdir($data_folder . DIRECTORY_SEPARATOR . 'cache', 0755, true)) {
326 $htaccess_made = file_put_contents($data_folder . DIRECTORY_SEPARATOR . '.htaccess', 'deny from all');
327 if ($htaccess_made === false) {
328 linguiseErrorLog('Linguise: Failed to create .htaccess in ' . $data_folder);
329 }
330
331 $index_html_made = file_put_contents($data_folder . DIRECTORY_SEPARATOR . 'index.html', '');
332 if ($index_html_made === false) {
333 linguiseErrorLog('Linguise: Failed to create index.html in ' . $data_folder);
334 }
335 }
336
337 Configuration::getInstance()->set('data_dir', $data_folder);
338 if (file_exists($data_folder . DIRECTORY_SEPARATOR . 'ConfigurationLocal.php')) {
339 // By default, we load the local configuration from the data folder
340 Configuration::getInstance()->loadFile($data_folder . DIRECTORY_SEPARATOR . 'ConfigurationLocal.php', true);
341 } elseif (file_exists(__DIR__ . DIRECTORY_SEPARATOR . 'ConfigurationLocal.php')) {
342 // If there is a local configuration in the script folder, we load it
343 Configuration::getInstance()->loadFile(__DIR__ . DIRECTORY_SEPARATOR . 'ConfigurationLocal.php', true);
344 } else {
345 // Else we load the default configuration
346 Configuration::getInstance()->loadFile(__DIR__ . DIRECTORY_SEPARATOR . 'Configuration.php');
347 }
348
349 $options = linguiseGetOptions();
350
351 $cache_enabled = $options['cache_enabled'];
352 $cache_max_size = $options['cache_max_size'];
353 $debug = $options['debug'] ? 5 : false;
354 $cache_ignore_parameters = $options['cache_ignore_parameters'];
355 $cache_params_always_included = $options['cache_params_always_included'];
356
357 Configuration::getInstance()->set('token', $token);
358
359 Configuration::getInstance()->set('cache_enabled', $cache_enabled);
360 Configuration::getInstance()->set('cache_max_size', $cache_max_size);
361 Configuration::getInstance()->set('debug', $debug);
362 Configuration::getInstance()->set('cache_ignore_parameters', $cache_ignore_parameters);
363 Configuration::getInstance()->set('cache_params_always_included', $cache_params_always_included);
364
365 $options = linguiseGetOptions();
366 foreach ($options['expert_mode'] as $key => $value) {
367 Configuration::getInstance()->set($key, $value);
368 }
369
370 linguiseRestoreMultisite();
371 }
372
373 /**
374 * Get configuration attributes
375 *
376 * @return array
377 */
378 function linguiseGetConfiguration()
379 {
380 linguiseInitializeConfiguration();
381
382 $instance = Configuration::getInstance();
383 // get all attributes from the class
384 $attributes = $instance->toArray();
385 return $attributes;
386 }
387
388 /**
389 * Hook to insert custom user meta
390 *
391 * @param array $custom_meta Custom metadata that we want to insert
392 * @param \WP_User $user User object itself
393 * @param bool $update Whether this is an update or not
394 *
395 * @return array
396 */
397 add_filter('insert_custom_user_meta', function ($custom_meta, $user, $update) {
398 if ($update) {
399 // We don't want to update custom meta on update
400 return $custom_meta;
401 }
402
403 $language = WPHelper::getLanguage();
404 if (!$language && strtoupper($_SERVER['REQUEST_METHOD']) === 'POST') {
405 $language = WPHelper::getLanguageFromReferer();
406 }
407
408 if (!$language) {
409 // No language metadata
410 return $custom_meta;
411 }
412
413 $custom_meta['linguise_register_language'] = $language;
414
415 return $custom_meta;
416 }, 5, 3);
417
418 // Load all the super-important stuff first
419 require_once ABSPATH . 'wp-admin/includes/plugin.php';
420
421 include_once(__DIR__ . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'HTMLHelper.php'); // Main HTML Helper, required by fragment handler
422 include_once(__DIR__ . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'FragmentBase.php'); // Base class for fragment handlers
423 include_once(__DIR__ . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'FragmentHandler.php');
424 include_once(__DIR__ . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'AttributeHandler.php');
425 include_once(__DIR__ . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'rest-ajax.php');
426 include_once(__DIR__ . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'third-party-loader.php');
427 include_once(__DIR__ . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'synchronization.php');
428
429 if (wp_doing_ajax()) {
430 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- No action
431 if (empty($_REQUEST['action']) || strpos($_REQUEST['action'], 'wc_emailer') === false) {
432 include_once(__DIR__ . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'config-iframe.php');
433 include_once(__DIR__ . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'debug.php');
434 include_once(__DIR__ . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'cache.php');
435 return;
436 }
437 }
438
439 // fixme: should not be a global script variable
440 $languages_names = \Linguise\WordPress\Helper::getLanguagesInfos();
441
442 // Load all the frontend stuff
443 include_once(__DIR__ . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'install.php');
444 include_once(__DIR__ . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'switcher.php');
445 include_once(__DIR__ . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'admin/menu.php');
446 include_once(__DIR__ . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'frontend/redirector.php'); // Main redirector/base class
447 include_once(__DIR__ . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'frontend/ukrainian_redirection.php'); // Ukrainian redirection
448 include_once(__DIR__ . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'frontend/cookies_language.php'); // Cookies-based redirection
449 include_once(__DIR__ . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'frontend/browser_language.php'); // Browser language-based redirection
450 include_once(__DIR__ . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'configuration.php');
451 include_once(__DIR__ . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'synchronization-loader.php'); // Synchronization loader
452
453 register_deactivation_hook(__FILE__, 'linguiseUnInstall');
454 /**
455 * UnInstall plugin
456 *
457 * @return void
458 */
459 function linguiseUnInstall()
460 {
461 global $wp_filesystem;
462 if (empty($wp_filesystem)) {
463 require_once(ABSPATH . 'wp-admin/includes/file.php');
464 WP_Filesystem();
465 }
466
467 // Save htaccess content
468 $htaccess_path = ABSPATH . DIRECTORY_SEPARATOR . '.htaccess';
469 $htaccess_content = $wp_filesystem->get_contents($htaccess_path);
470 if ($wp_filesystem->exists($htaccess_path) && is_writable($htaccess_path)) {
471 if (strpos($htaccess_content, '#### LINGUISE DO NOT EDIT ####') !== false) {
472 $htaccess_content = preg_replace('/#### LINGUISE DO NOT EDIT ####.*?#### LINGUISE DO NOT EDIT END ####/s', '', $htaccess_content);
473 $wp_filesystem->put_contents($htaccess_path, $htaccess_content);
474 }
475 }
476
477 // Delete transient
478 delete_transient('linguise_multisite_subdomain');
479 }
480
481 add_action('admin_notices', function () {
482 $translate_plugins = array(
483 'sitepress-multilingual-cms/sitepress.php' => 'WPML Multilingual CMS',
484 'polylang/polylang.php' => 'Polylang',
485 'polylang-pro/polylang.php' => 'Polylang Pro',
486 'translatepress-multilingual/index.php' => 'TranslatePress',
487 'weglot/weglot.php' => 'Weglot',
488 'gtranslate/gtranslate.php' => 'GTranslate',
489 'conveythis-translate/index.php' => 'ConveyThis',
490 'google-language-translator/google-language-translator.php' => 'Google Language Translator',
491 );
492
493 foreach ($translate_plugins as $path => $plugin_name) {
494 if (is_plugin_active($path)) {
495 echo '<div class="error">';
496 /* translators: %s: Name of the conflicting translation plugin */
497 echo '<p>' . sprintf(esc_html__('We\'ve detected that %s translation plugin is installed. Please disable it before using Linguise to avoid conflict with translated URLs mainly', 'linguise'), '<strong>' . esc_html($plugin_name) . '</strong>') . '</p>';
498 echo '</div>';
499 }
500 }
501 });
502
503 /**
504 * Compatibility Checker for GTranslate
505 */
506 add_action('admin_notices', function () {
507 $htaccess_file = ABSPATH . '.htaccess';
508 if (file_exists($htaccess_file)) {
509 if (strpos(file_get_contents($htaccess_file), 'BEGIN GTranslate config') !== false) {
510 echo '<div class="error">';
511 /* translators: %1$s: GTranslate %2$s: GTranslate */
512 echo '<p>' . sprintf(esc_html__("It looks like you have %1\$s extension that hasn't been properly uninstalled and prevents Linguise from working properly, please contact our support team or remove %2\$s code from your .htaccess file.", 'linguise'), '<strong>GTranslate</strong>', '<strong>GTranslate</strong>') . '</p>';
513 echo '</div>';
514 }
515 }
516 });
517
518 add_action('admin_notices', function () {
519 $options = linguiseGetOptions();
520 if ($options['debug']) {
521 ?>
522 <div id="linguise_admin_notice_debug" class="notice notice-warning" style="display: flex; flex-direction: row;">
523 <img src="data:image/webp;base64,UklGRqYDAABXRUJQVlA4TJkDAAAvx8AOEF8wRuM1vgraRkLxS2CGABzhWDwQjMOjUEBQmrZtbd08loxJQeWGVeZWM+GUvCrDWZVBYcYtM2lzTleZUZnbsPnz/fP0SZZ0XFxF9H8C9P/v9qrKX0CHyJ3k1IV1U6d3gagyQZfdKZ5TFt8palDbOF6UW++KUw5vFFUKGrn6Ks7Lh1Y5QqgVhOSN6zkFsLAcJ6BZjB9L6i7OyYcF5QihVkz7sKQTb+ekwRW3HJ6JKsWEn0pqH87Lv0cl9R0VO/uipCDKa2reXChJhQXb1lRS/C2vOQVs3vZIir95jZOh25Lk5zaingjHsKtiCQxEbqLLAskfX3Ekf3zFkeT9CjxpCUYQu2n9hqSggKYkzwAssgwB3k4MWCgF4EoBuJLmSFYTPYDDacOapHB3MSdIxokQq5uTsTwjKcBaTzGupBMvFtODS2OoS+pAbGBxPm3gMkSSfoDYwIspSNL3S4ox7NYMtCQNiZ3A8HY+J+AB/QSO1CN2fMNhWxAnOq1CPGhKQ56RZFgkdYjyuUkkzUBVGvGMNMcV28zhRLdZSACu1OVFSVCXThDntVvyoC4ZmlIItgNvJwb1Etxid1oIeR2WdOGCK0E90+wziZFbgpslOAFV2Se5uTAxrkyFGTjsZJrjiq3blOTHmgoycNjNEBgO2/p1SUE0JeaAyLVZn7ENq5LC3VPCGwJRJUvVZkiN3SkgfwgsyvCW7GR8cRrI/w3itJ1OSqzUA7ungrwhVBN1ZfQztKdAsNKV2tCcSKSFn5boRF5dnpFkaKXMcMVm3JQTL2boEOdnWCR1LH2ekdoTvC1pxELJ0JROgG3QTLm5MMMsNHIbEjuBsXTZLZ0Apd0ikmRoSiOWSD8Q2TovpnRaGUKIVq5c6eTSgdhg+Z4rrvrEGWahoQPQkPrEjmf41BZecWy9RgZvTLKZS4hd0gGIL8PbGdpw5cIYXOkHiEaw2OaZt2yDWgZ1C9Awgzcm2cqgEclI0gzWmk1zvOEkRm6W9riAwMB2i35MxJUsc5ZFkjRMHFb6r9iV+dA4rSH54CTeTsjf8mho80fA/ZLkgyNJvwK7lAwMxG4G7+w4EWWTv3LlSke5p8jfuu1RTbh525qKRcG2ba4mHLzGgxPkv2VbJUvZR6PDKinU58+YWnka0gni+eDzlspqWCx1iOZDcMUpzYDY8Q2fzgc9otJ2IDaweF6UOMRam24aJg5rygcGYnfayd/6gaP/BQMA" width="200" height="60" />
524 <div class="notice-content">
525 <p style="font-size: 16px; font-weight: 700;">
526 <?php echo esc_html_e('Linguise debug mode is currently enabled.', 'linguise'); ?>
527 </p>
528 <p>
529 <?php echo esc_html_e('This mode is intended for debugging purposes only and will generate a ton of logs that will consume a lot of space.', 'linguise'); ?>
530 <br />
531 <?php echo esc_html_e('Please disable it when you are done.', 'linguise'); ?>
532 </p>
533 <p>
534 <?php $disable_url = wp_nonce_url(admin_url('admin-ajax.php') . '?action=linguise_disable_debug', '_linguise_nonce_'); ?>
535 <a href="<?php echo esc_url($disable_url); ?>" class="button" id="linguise_admin_notice_debug_disable">
536 <?php esc_html_e('Disable debug!', 'linguise') ?>
537 </a>
538 </p>
539 </div>
540 </div>
541 <script type="text/javascript">
542 jQuery(function($) {
543 $(document).ready(function() {
544 $(document).on('click', '#linguise_admin_notice_debug_disable', function (e) {
545 e.preventDefault();
546 $.ajax({
547 url: $(this).prop('href'),
548 method: 'POST',
549 success: function(data) {
550 if (data.success) {
551 $('#linguise_admin_notice_debug').fadeOut('fast', function () {
552 $(this).remove();
553 })
554 } else {
555 alert('Failed to disable debug mode for Linguise');
556 }
557 },
558 error: function (data) {
559 alert('Failed to disable debug mode for Linguise');
560 }
561 })
562 })
563 });
564 });
565 </script>
566 <?php
567 }
568 });
569
570 /**
571 * Translate search requests
572 *
573 * @param \WP_Query $query_object
574 */
575 add_action('parse_query', function ($query_object) {
576 $linguise_original_language = \Linguise\WordPress\Helper::getLanguage();
577
578 if (!$linguise_original_language) {
579 return;
580 }
581
582 $options = linguiseGetOptions();
583
584 if (!$options['search_translation']) {
585 return;
586 }
587
588 /**
589 * Do not translate if the search was already translated
590 */
591 if (defined('LINGUISE_SEARCH_TRANSLATION_WAS_EXECUTED')) {
592 return;
593 }
594
595 if ($query_object->is_main_query() && $query_object->is_search()) {
596 $raw_search = $query_object->query['s'];
597
598 if (!defined('LINGUISE_SCRIPT_TRANSLATION')) {
599 define('LINGUISE_SCRIPT_TRANSLATION', 1);
600 }
601
602 include_once(__DIR__ . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php');
603
604 Configuration::getInstance()->set('cms', 'wordpress');
605 Configuration::getInstance()->set('token', $options['token']);
606
607 $translation = \Linguise\Vendor\Linguise\Script\Core\Translation::getInstance()->translateJson(['search' => $raw_search], linguiseGetSite(), $linguise_original_language, '/');
608
609 if (empty($translation->search)) {
610 return;
611 }
612
613 $query_object->set('s', $translation->search);
614 define('LINGUISE_SEARCH_TRANSLATION_WAS_EXECUTED', 1);
615 }
616 });
617
618 /**
619 * First hook available to check if we should translate this request
620 *
621 * @return void
622 */
623 function linguiseFirstHook()
624 {
625 static $run = null;
626
627 // Check if it has been already called or not
628 if ($run) {
629 return;
630 }
631
632 $run = true;
633
634 $linguise_original_language = \Linguise\WordPress\Helper::getLanguage();
635 $languages_names = \Linguise\WordPress\Helper::getLanguagesInfos();
636 if (!empty($linguise_original_language) && !empty($languages_names->$linguise_original_language)) {
637 // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited -- This is a WP Global variable override
638 $GLOBALS['text_direction'] = $languages_names->$linguise_original_language->rtl ? 'rtl' : 'ltr';
639 return;
640 }
641
642 if (is_admin()) {
643 return;
644 }
645
646 $linguise_options = linguiseGetOptions();
647
648 if (!$linguise_options['token']) {
649 return;
650 }
651
652 include_once(__DIR__ . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php');
653
654 $base_dir = linguiseGetSite('', 'relative');
655 $path = substr($_SERVER['REQUEST_URI'], strlen($base_dir));
656
657 $path = parse_url('https://localhost/' . ltrim($path, '/'), PHP_URL_PATH);
658
659 $parts = explode('/', trim($path, '/'));
660
661 if (!count($parts) || $parts[0] === '') {
662 return;
663 }
664
665 $language = $parts[0];
666
667 if (!in_array($language, array_merge($linguise_options['enabled_languages'], array('zz-zz')))) {
668 return;
669 }
670
671 $_GET['linguise_language'] = $language;
672
673 if (is_plugin_active('woocommerce/woocommerce.php')) {
674 define('LINGUISE_SCRIPT_TRANSLATION_WOOCOMMERCE', true);
675 }
676
677 add_filter('ecwid_lang', $language);
678
679 if (!defined('WP_ROCKET_WHITE_LABEL_FOOTPRINT')) {
680 define('WP_ROCKET_WHITE_LABEL_FOOTPRINT', true);
681 }
682
683 // Reset $wp_rewrite to avoid issues with WP-Rocket
684 // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited -- This is a WP Global variable override
685 $GLOBALS['wp_rewrite'] = new \WP_Rewrite();
686
687 include_once __DIR__ . DIRECTORY_SEPARATOR . 'script.php';
688 }
689
690 /**
691 * Hook to change locale based on Referer or HTTP header
692 *
693 * @return void
694 */
695 function linguiseHookLanguage()
696 {
697 if (isset($_SERVER['HTTP_LINGUISE_ORIGINAL_LANGUAGE'])) {
698 $new_locale = WPHelper::mapLanguageToWordPressLocale($_SERVER['HTTP_LINGUISE_ORIGINAL_LANGUAGE']);
699 if (!empty($new_locale)) {
700 switch_to_locale($new_locale);
701 }
702 return;
703 }
704
705 $lang_referer = WPHelper::getLanguageFromReferer();
706 if (!empty($lang_referer)) {
707 $new_locale = WPHelper::mapLanguageToWordPressLocale($lang_referer);
708 if (!empty($new_locale)) {
709 switch_to_locale($lang_referer);
710 }
711 return;
712 }
713 }
714
715 add_action('muplugins_loaded', 'linguiseFirstHook', 1);
716 add_action('plugins_loaded', 'linguiseFirstHook', 1);
717 add_action('plugins_loaded', 'linguiseHookLanguage', 2);
718 add_action('init', function () {
719 load_plugin_textdomain('linguise', false, dirname(plugin_basename(__FILE__)) . '/languages');
720
721 if (!is_admin() && !wp_doing_ajax()) {
722 linguiseInitializeConfiguration();
723
724 $tl_host = Configuration::getInstance()->get('host');
725 $tl_port = (int)Configuration::getInstance()->get('port');
726 $no_port_needed = $tl_port === 80 || $tl_port === 443;
727 $tl_addr = 'http' . ($tl_port === 443 ? 's' : '') . '://' . $tl_host . ($no_port_needed ? '' : ':' . $tl_port);
728
729 $options = linguiseGetOptions();
730 $request = Request::getInstance();
731 $base_url = $request->getBaseUrl();
732 $switcher = new LinguiseSwitcher($options, $base_url, $tl_addr);
733 $switcher->start(); // initialize hook and more
734 }
735 });
736
737 // Redirection, cookies, and more.
738 add_action('init', function () {
739 $options = linguiseGetOptions();
740 if (empty($options['token'])) {
741 // Don't allow this to be run if the token is not set
742 return;
743 }
744
745 \Linguise\WordPress\Frontend\LinguiseUkrainianRedirection::startRedirect();
746 \Linguise\WordPress\Frontend\LinguiseCookiesLanguage::startRedirect();
747 \Linguise\WordPress\Frontend\LinguiseBrowserLanguage::startRedirect();
748
749 // Either we inject the `linguise_lang` if WP_CACHE is enabled OR cookies_redirect is enabled
750 if ((defined('WP_CACHE') && WP_CACHE) || !empty($options['cookies_redirect'])) {
751 /**
752 * Check for LINGUISE_NO_COOKIE constant, if defined we don't set the cookie
753 *
754 * This can be added in wp-config.php
755 *
756 * @disregard P1011
757 */
758 if (defined('LINGUISE_NO_COOKIE') && LINGUISE_NO_COOKIE) {
759 return;
760 }
761
762 $allowed_request_methods = array('GET', 'HEAD', 'OPTIONS');
763 $is_rest_request = (defined('REST_REQUEST') && REST_REQUEST); // disallow in REST API requests
764 $has_wp_json_in_url = strpos($_SERVER['REQUEST_URI'], '/wp-json/') !== false; // disallow in REST API requests based on URL
765
766 if (empty($_SERVER['REQUEST_METHOD']) // don't have request method
767 || !in_array($_SERVER['REQUEST_METHOD'], $allowed_request_methods) // check if it's an allowed request method
768 || is_admin() // disallow in admin
769 || wp_doing_ajax() // disallow in ajax
770 || $is_rest_request
771 || $has_wp_json_in_url
772 || $GLOBALS['pagenow'] === 'wp-login.php' // disallow in login page
773 ) {
774 // Do not set cookie if we are in admin, ajax or login page
775 return;
776 }
777
778 // Add linguise_lang header
779 $current_lang = WPHelper::getLanguage();
780 if (empty($current_lang)) {
781 $current_lang = WPHelper::getLanguageFromUrl($_SERVER['REQUEST_URI']);
782 }
783
784 if (empty($current_lang) && !empty($options['default_language'])) {
785 $current_lang = $options['default_language'];
786 }
787
788 // cache for a month - ensure header is not sent yet
789 if (!headers_sent()) {
790 setcookie('linguise_lang', $current_lang, time() + MONTH_IN_SECONDS, '/', COOKIE_DOMAIN);
791 }
792 }
793 }, 11);
794
795 /**
796 * If the website behind cloudflare
797 * Exclude front.bundle.js from rocket loader
798 */
799 add_filter('script_loader_tag', function ($tag, $handle) {
800 if (is_admin()) {
801 return $tag;
802 }
803
804 if (!WPHelper::isBehindCloudflare()) {
805 return $tag;
806 }
807
808 if ('linguise_switcher' !== $handle) {
809 return $tag;
810 }
811
812 /**
813 * Add data-cfasync="false" to exluded from Rocket loader
814 *
815 * @see https://developers.cloudflare.com/speed/optimization/content/rocket-loader/ignore-javascripts/
816 */
817 return str_replace(' src', ' data-cfasync="false" src', $tag);
818 }, 50, 2);
819
820 /**
821 * The front.bundle.js is depend on <script id="linguise_switcher-js-extra">
822 * Also exclude <script id="linguise_switcher-js-extra"> from Rocket loader
823 */
824 add_filter('wp_inline_script_attributes', function ($attributes) {
825 if (is_admin()) {
826 return $attributes;
827 }
828
829 if (!WPHelper::isBehindCloudflare()) {
830 return $attributes;
831 }
832
833 /**
834 * Append data-cfasync=true into <script id="linguise_switcher-js-extra">
835 */
836 if (isset($attributes['id']) && $attributes['id'] === 'linguise_switcher-js-extra') {
837 $attributes = array_merge(array( 'data-cfasync' => 'false' ), $attributes);
838 }
839
840 return $attributes;
841 }, 50);
842