PluginProbe
Translate and boost SEO – Automatic AI translation – wpLingua / 3.0.0
Translate and boost SEO – Automatic AI translation – wpLingua v3.0.0
3.0.0 2.16.8 2.16.7 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 All 114 releases
wplingua / wplingua.php

wplingua.php in Translate and boost SEO – Automatic AI translation – wpLingua 3.0.0, at wplingua.php

461 lines 16.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Plugin Name: wpLingua
4 * Plugin URI: https://wplingua.com/
5 * Description: An all-in-one solution that makes your websites multilingual and translates them automatically, without word or page limits. The highlights: a free first language, an on-page visual editor for editing translations, a customizable language switcher, search engine optimization (SEO), self-hosted data and more!
6 * Author: wpLingua Translation Service
7 * Author URI: https://wplingua.com/
8 * Text Domain: wplingua
9 * Domain Path: /languages/
10 * Version: 3.0.0
11 * Requires PHP: 7.4
12 * License: GPL v2 or later
13 * License URI: https://www.gnu.org/licenses/gpl-2.0.html
14 */
15
16
17 // If this file is called directly, abort.
18 if ( ! defined( 'WPINC' ) ) {
19 die;
20 }
21
22
23 // Define wpLingua constants
24 define( 'WPLNG_API_URL', 'https://api.wplingua.com' );
25 define( 'WPLNG_API_VERSION', '3.0' );
26 define( 'WPLNG_API_SSLVERIFY', true );
27 define( 'WPLNG_PLUGIN_VERSION', '3.0.0' );
28 define( 'WPLNG_PLUGIN_FILE', plugin_basename( __FILE__ ) );
29 define( 'WPLNG_PLUGIN_DIR', __DIR__ );
30 define( 'WPLNG_CACHE_DIR', WP_CONTENT_DIR . '/wplingua-cache' );
31 define( 'WPLNG_PHP_MIN_VERSION', '7.4' );
32 define( 'WPLNG_MAX_TRANSLATIONS_STR', 220 );
33 define( 'WPLNG_MAX_TRANSLATIONS_CHAR', 4200 );
34 define( 'WPLNG_MAX_FILE_SIZE', 5000000 );
35
36
37 // Define debug constants
38 defined( 'WPLNG_DEBUG_JSON' ) || define( 'WPLNG_DEBUG_JSON', false );
39 defined( 'WPLNG_DEBUG_AJAX' ) || define( 'WPLNG_DEBUG_AJAX', false );
40 defined( 'WPLNG_DEBUG_REST' ) || define( 'WPLNG_DEBUG_REST', false );
41 defined( 'WPLNG_DEBUG_BEAT' ) || define( 'WPLNG_DEBUG_BEAT', false );
42 defined( 'WPLNG_DEBUG_MAIL' ) || define( 'WPLNG_DEBUG_MAIL', false );
43 defined( 'WPLNG_DEBUG_XML' ) || define( 'WPLNG_DEBUG_XML', false );
44
45
46 // Load all needed PHP files
47 require_once WPLNG_PLUGIN_DIR . '/loader.php';
48
49
50 /**
51 * Loads wpLingua plugin's translated strings.
52 *
53 * @return void
54 */
55 function wplng_load_plugin_textdomain() {
56 load_plugin_textdomain(
57 'wplingua',
58 false,
59 'wplingua/languages'
60 );
61 }
62
63
64 /**
65 * Register all wpLingua Hook
66 *
67 * @return void
68 */
69 function wplng_start() {
70
71 // Setup $wplng_class_reload
72 global $wplng_class_reload;
73 $wplng_class_reload = false;
74
75 // Setup $wplng_request_uri
76 if ( isset( $_SERVER['REQUEST_URI'] ) ) {
77
78 $request_uri = wp_unslash( (string) $_SERVER['REQUEST_URI'] );
79 $request_uri = wplng_normalize_request_path( $request_uri );
80 $decoded_uri = urldecode( $request_uri );
81
82 // Check if the request URI is clean
83 if ( strtolower( esc_url_raw( $request_uri ) ) !== strtolower( $request_uri )
84 || wplng_str_is_malicious( $request_uri )
85 || wplng_str_is_malicious( $decoded_uri )
86 ) {
87 return;
88 }
89
90 // Also check query string for double-encoded attacks
91 if ( isset( $_SERVER['QUERY_STRING'] ) ) {
92 $query_string = sanitize_text_field( $_SERVER['QUERY_STRING'] );
93 $decoded_query = urldecode( urldecode( $query_string ) );
94
95 if ( wplng_str_is_malicious( $decoded_query ) ) {
96 return;
97 }
98 }
99
100 global $wplng_request_uri;
101 $wplng_request_uri = $request_uri;
102 }
103
104 // The plugin version has changed
105 if ( get_option( 'wplng_version' ) !== WPLNG_PLUGIN_VERSION ) {
106 // Update version number in DB
107 update_option( 'wplng_version', WPLNG_PLUGIN_VERSION, true );
108
109 // Clear all wpLingua cache
110 delete_option( 'wplng_cached_translations' );
111 delete_option( 'wplng_cached_slugs' );
112 delete_option( 'wplng_api_key_data' );
113 wplng_clear_folder_cache();
114 wplng_clear_website_cache();
115
116 // Clear old cache method (version <= 2.12.3)
117 delete_transient( 'wplng_cached_translations' );
118 delete_transient( 'wplng_cached_slugs' );
119 }
120
121 // Load plugin text domain /languages/
122 add_action( 'init', 'wplng_load_plugin_textdomain' );
123
124 // Do not cache page for connected editor
125 add_action( 'init', 'wplng_init_manage_cache', 1 );
126
127 // Display a notice if incompatibility is detected
128 add_action( 'admin_notices', 'wplng_admin_notice_incompatible_plugin', 1 );
129 add_action( 'admin_notices', 'wplng_admin_notice_incompatible_multisite', 1 );
130 add_action( 'admin_notices', 'wplng_admin_notice_incompatible_php_version', 1 );
131 add_action( 'admin_notices', 'wplng_admin_notice_incompatible_htaccess', 1 );
132 add_action( 'admin_notices', 'wplng_admin_notice_incompatible_plain_permalink', 1 );
133
134 // Return if incompatibility is detected
135 if ( ! empty( wplng_get_incompatible_plugins() )
136 || ( is_multisite()
137 && ! apply_filters( 'wplng_bypass_multisite_incompatibility', false )
138 )
139 || ( version_compare( PHP_VERSION, WPLNG_PHP_MIN_VERSION ) < 0 )
140 || ! wplng_htaccess_is_valid()
141 || empty( get_option( 'permalink_structure' ) )
142 ) {
143 return;
144 }
145
146 // Register plugin settings
147 add_action( 'admin_init', 'wplng_register_settings' );
148
149 // Add settings link in plugin list
150 add_filter( 'plugin_action_links_' . WPLNG_PLUGIN_FILE, 'wplng_settings_link' );
151
152 // Redirect to the settings page on plugin activation
153 add_action( 'activated_plugin', 'wplng_plugin_activation_redirect' );
154
155 // Set footer text for options pages
156 add_filter( 'admin_footer_text', 'wplng_admin_footer_text', 11 );
157 add_filter( 'update_footer', 'wplng_update_footer', 11 );
158
159 // Print head script (JSON with all languages informations)
160 add_action( 'toplevel_page_wplingua-settings', 'wplng_inline_script_languages' );
161
162 if ( empty( wplng_get_api_data() ) ) {
163
164 // Add Register option page in back office menu
165 add_action( 'admin_menu', 'wplng_create_menu_register' );
166
167 // Enqueue CSS and JS files for register option pages
168 add_action( 'admin_enqueue_scripts', 'wplng_option_page_register_assets' );
169
170 // Display a notice if the plugin is activate but not configured
171 add_action( 'admin_notices', 'wplng_admin_notice_no_key_set', 1 );
172
173 } else {
174
175 /**
176 * Back office
177 */
178
179 // Add menu in back office
180 add_action( 'admin_menu', 'wplng_create_menu' );
181 add_filter( 'parent_file', 'wplng_option_page_parent_file' );
182 add_filter( 'submenu_file', 'wplng_option_page_submenu_file' );
183 add_action( 'admin_head', 'wplng_option_page_hide_submenu' );
184
185 // Add admin Bar menu
186 add_action( 'admin_bar_menu', 'wplng_admin_bar_menu', 81 );
187 add_action( 'admin_bar_menu', 'wplng_admin_bar_edit', 81 );
188
189 // Switcher in nav menu options
190 add_action( 'admin_enqueue_scripts', 'wplng_switcher_nav_menu_inline_scripts' );
191 add_action( 'admin_head-nav-menus.php', 'wp_nav_menu_switcher_box_add_register' );
192 add_action( 'wp_nav_menu_item_custom_fields', 'wp_nav_menu_switcher_box_edit', 10, 2 );
193
194 // Enqueue CSS and JS files for option pages
195 add_action( 'admin_enqueue_scripts', 'wplng_option_page_settings_assets' );
196 add_action( 'admin_enqueue_scripts', 'wplng_option_page_switcher_assets' );
197 add_action( 'admin_enqueue_scripts', 'wplng_option_page_exclusions_assets' );
198 add_action( 'admin_enqueue_scripts', 'wplng_option_page_dictionary_assets' );
199 add_action( 'admin_enqueue_scripts', 'wplng_option_page_link_media_assets' );
200 add_action( 'admin_enqueue_scripts', 'wplng_option_page_mail_assets' );
201
202 // Update flags URL
203 add_action( 'update_option_wplng_flags_style', 'wplng_options_switcher_update_flags_style', 10, 2 );
204
205 // Update translations on dictionary changes
206 add_action( 'update_option_wplng_dictionary_entries', 'wplng_on_dictionary_entries_updated', 10, 2 );
207 add_action( 'wp_ajax_wplng_dictionary_update_translations', 'wplng_ajax_dictionary_update_translations' );
208
209 // Reset API data on API key changing
210 add_action( 'update_option_wplng_api_key', 'wplng_on_update_option_wplng_api_key', 10, 2 );
211
212 // Add edit link on page and post list
213 add_filter( 'page_row_actions', 'wplng_row_edit_translation_link', 10, 2 );
214 add_filter( 'post_row_actions', 'wplng_row_edit_translation_link', 10, 2 );
215
216 // Notice for PRO users
217 add_action( 'admin_notices', 'wplng_admin_notice_pro', 1 );
218
219 /**
220 * wplng_translation : CPT, taxo, meta
221 */
222
223 // Register wplng_translation CPT
224 add_action( 'init', 'wplng_register_post_type_translation' );
225
226 // Add metabox for wplng_translation
227 add_action( 'add_meta_boxes_wplng_translation', 'wplng_translation_add_meta_box' );
228
229 // Save metabox on posts saving
230 add_action( 'save_post_wplng_translation', 'wplng_translation_save_meta_boxes_data', 10, 2 );
231
232 // Clear translation cache on trash / untrash
233 add_action( 'trashed_post', 'wplng_clear_translations_cache_trash_untrash' );
234 add_action( 'untrash_post', 'wplng_clear_translations_cache_trash_untrash' );
235 add_action( 'delete_post', 'wplng_clear_translations_cache_trash_untrash' );
236
237 // Enqueue Script for wplng_translation admin: Edit
238 add_action( 'admin_print_scripts-post.php', 'wplng_translation_edit_assets' );
239
240 // Enqueue Script for wplng_translation admin: List
241 add_action( 'admin_print_scripts-edit.php', 'wplng_translation_list_assets' );
242
243 // Only show translations for the website languages
244 add_action( 'pre_get_posts', 'wplng_filter_wplng_translation_posts' );
245
246 // Remove Quick edit from translations list
247 add_filter( 'post_row_actions', 'wplng_translation_remove_quick_edit', 10, 2 );
248
249 // Ajax function for regenerate translation on edit page
250 add_action( 'wp_ajax_wplng_ajax_translation', 'wplng_ajax_generate_translation' );
251
252 // Ajax function for edit modal: Get HTML modal
253 add_action( 'wp_ajax_wplng_ajax_edit_modal', 'wplng_ajax_edit_modal' );
254
255 // Ajax function for edit modal: Save modal
256 add_action( 'wp_ajax_wplng_ajax_save_modal', 'wplng_ajax_save_modal' );
257
258 // Ajax function for edit modal: HeartBeat
259 add_action( 'wp_ajax_wplng_ajax_heartbeat', 'wplng_ajax_heartbeat' );
260 add_action( 'wp_ajax_nopriv_wplng_ajax_heartbeat', 'wplng_ajax_heartbeat' );
261
262 // Display 100 translation in admin area by default
263 add_filter( 'get_user_option_edit_wplng_translation_per_page', 'wplng_translation_per_page' );
264
265 // Filter translations by status
266 add_action( 'restrict_manage_posts', 'wplng_restrict_manage_posts_translation_status' );
267 add_filter( 'parse_query', 'wplng_posts_filter_translation_status' );
268
269 // Translation status on website translations list
270 add_filter( 'post_class', 'wplng_post_class_translation_status', 10, 3 );
271 add_filter( 'post_row_actions', 'wplng_post_row_actions_translation_status', 10, 2 );
272 add_filter( 'manage_wplng_translation_posts_columns', 'wplng_translation_status_columns' );
273 add_action( 'manage_wplng_translation_posts_custom_column', 'wplng_translation_status_item', 10, 2 );
274
275 /**
276 * wplng_slug : CPT, taxo, meta
277 */
278
279 // Register wplng_translation CPT
280 add_action( 'init', 'wplng_register_post_type_slug' );
281
282 // Add metabox for wplng_slug
283 add_action( 'add_meta_boxes_wplng_slug', 'wplng_slug_add_meta_box' );
284
285 // Save metabox on posts saving
286 add_action( 'save_post_wplng_slug', 'wplng_slug_save_meta_boxes_data', 10, 2 );
287
288 // Clear slugs cache on trash / untrash
289 add_action( 'trashed_post', 'wplng_clear_slugs_cache_trash_untrash' );
290 add_action( 'untrash_post', 'wplng_clear_slugs_cache_trash_untrash' );
291 add_action( 'delete_post', 'wplng_clear_slugs_cache_trash_untrash' );
292
293 // Enqueue Script for wplng_slug admin: Edit
294 add_action( 'admin_print_scripts-post.php', 'wplng_slug_edit_assets' );
295
296 // Enqueue Script for wplng_slug admin: List
297 add_action( 'admin_print_scripts-edit.php', 'wplng_slug_list_assets' );
298
299 // Only show slugs for the website languages
300 add_action( 'pre_get_posts', 'wplng_filter_wplng_slug_posts' );
301
302 // Remove Quick edit from slugs list
303 add_filter( 'post_row_actions', 'wplng_slug_remove_quick_edit', 10, 2 );
304
305 // Ajax function for regenerate slug on edit page
306 add_action( 'wp_ajax_wplng_ajax_slug', 'wplng_ajax_generate_slug' );
307
308 // Display 100 translation in admin area by default
309 add_filter( 'get_user_option_edit_wplng_slug_per_page', 'wplng_slug_per_page' );
310
311 // Filter slugs by status
312 add_action( 'restrict_manage_posts', 'wplng_restrict_manage_posts_slug_status' );
313 add_filter( 'parse_query', 'wplng_posts_filter_slug_status' );
314
315 // Translation status on website slugs list
316 add_filter( 'post_class', 'wplng_post_class_slug_status', 10, 3 );
317 add_filter( 'post_row_actions', 'wplng_post_row_actions_slug_status', 10, 2 );
318 add_filter( 'manage_wplng_slug_posts_columns', 'wplng_slug_status_columns' );
319 add_action( 'manage_wplng_slug_posts_custom_column', 'wplng_slug_status_item', 10, 2 );
320
321 /**
322 * Front
323 */
324
325 // Enqueue CSS and JS files
326 add_action( 'wp_enqueue_scripts', 'wplng_register_assets' );
327
328 // Add custom inline styles (option page: switcher)
329 add_action( 'wp_head', 'wplng_add_custom_inline_styles', 50 );
330
331 // Script JS in page
332 add_action( 'wp_footer', 'wplng_on_page_script' );
333
334 // Add languages switcher before </body>
335 add_action( 'wp_footer', 'wplng_switcher_wp_footer' );
336
337 // Add languages switcher in nav menu
338 add_filter( 'wp_nav_menu_objects', 'wplng_switcher_nav_menu_replace_items' );
339 add_filter( 'nav_menu_link_attributes', 'wplng_add_nav_menu_link_attributes_atts', 10, 2 );
340
341 // Set alternate links with hreflang parametters
342 add_action( 'wp_head', 'wplng_link_alternate_hreflang', 1 );
343
344 // Disable web browser automatic translation
345 add_action( 'language_attributes', 'wplng_disable_web_browser_auto_translate' );
346
347 // Ajax function for Load in progress
348 add_action( 'wp_ajax_wplng_load_in_progress', 'wplng_ajax_load_in_progress' );
349
350 /**
351 * OB and REQUEST_URI
352 */
353
354 // Manage URL with REQUEST_URI and start OB
355 add_action( 'init', 'wplng_ob_start', 1 );
356
357 // Redirect page if is called with an untranslate slug
358 add_action( 'template_redirect', 'wplng_redirect_translated_slug' );
359
360 // Translate WooCommerce cart URL
361 add_filter( 'woocommerce_get_cart_url', 'wplng_url_translate' );
362
363 /**
364 * Generate JSON translation on the fly for wp-i18n.js
365 */
366
367 // Generate JSON translation
368 add_filter( 'load_script_translation_file', 'wplng_load_script_translation_file', 20, 3 );
369
370 /**
371 * Clear wpLingua cache on updates
372 */
373
374 // Clear wpLingua cache on WordPress core, plugins, themes or translations update
375 add_action( 'upgrader_process_complete', 'wplng_clear_cache_on_update', 10, 2 );
376
377 // Clear wpLingua cache on plugin activation/deactivation
378 add_action( 'activated_plugin', 'wplng_clear_folder_cache' );
379 add_action( 'deactivated_plugin', 'wplng_clear_folder_cache' );
380
381 // Clear wpLingua cache on theme switch
382 add_action( 'switch_theme', 'wplng_clear_folder_cache' );
383
384 // Clear wpLingua cache on site language change
385 add_action( 'update_option_WPLANG', 'wplng_clear_folder_cache' );
386
387 // Clear wpLingua cache on wpLingua settings change
388 add_action( 'update_option_wplng_website_language', 'wplng_clear_folder_cache' );
389 add_action( 'update_option_wplng_target_languages', 'wplng_clear_folder_cache' );
390
391 /**
392 * Features
393 */
394
395 // Make multilingua Sitemap XML for All In One SEO plugin
396 // Il other case, multilingual Sitemap is make by output buffering
397 if ( get_option( 'wplng_sitemap_xml', true )
398 && function_exists( 'aioseo' )
399 ) {
400 add_filter( 'aioseo_sitemap_post', 'wplng_aioseo_filter_sitemap_post', 10, 2 );
401 add_filter( 'aioseo_sitemap_term', 'wplng_aioseo_filter_sitemap_term', 10, 2 );
402 }
403
404 // Search from translated languages
405 if ( ! empty( get_option( 'wplng_translate_search' ) )
406 && wplng_api_feature_is_allow( 'search' )
407 ) {
408 add_action( 'parse_query', 'wplng_translate_search_query' );
409 add_filter( 'get_search_query', 'wplng_search_put_tag' );
410 add_filter( 'wplng_translated_html', 'wplng_search_replace_tag', 5 );
411 } else {
412 add_filter( 'wplng_url_is_translatable', 'wplng_exclude_search', 20 );
413 }
414
415 // Redirect by browser language
416 $browser_language_redirect = get_option( 'wplng_browser_language_redirect' );
417 if ( $browser_language_redirect === 'js_only' ) {
418 add_action( 'wp_head', 'wplng_browser_language_redirect_js_only', 2 );
419 } elseif ( $browser_language_redirect === 'php_js' ) {
420 add_action( 'template_redirect', 'wplng_browser_language_redirect_php_js' );
421 }
422
423 /**
424 * Shortcode
425 */
426
427 add_shortcode( 'wplng_switcher', 'wplng_shortcode_switcher' );
428 add_shortcode( 'wplng_notranslate', 'wplng_shortcode_notranslate' );
429 add_shortcode( 'wplng_only', 'wplng_shortcode_only' );
430
431 /**
432 * Gutenberg
433 */
434
435 add_filter( 'block_categories_all', 'wplng_block_category' );
436 add_action( 'init', 'wplng_register_block' );
437 add_action( 'enqueue_block_editor_assets', 'wplng_register_block_assets' );
438
439 /**
440 * Do action after wpLingua fully initialized
441 */
442
443 do_action( 'wplng_initialized' );
444
445 }
446 }
447 wplng_start();
448
449
450 /**
451 * Delete translation and slug cache options on plugin deactivation.
452 *
453 * @return void
454 */
455 function wplng_deactivate() {
456 delete_option( 'wplng_cached_translations' );
457 delete_option( 'wplng_cached_slugs' );
458 delete_option( 'wplng_api_key_data' );
459 }
460 register_deactivation_hook( __FILE__, 'wplng_deactivate' );
461