| 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 |
|