Polylang - Version 2.4

Version Description

(2018-11-12) =

  • Minimum WordPress version is now 4.7
  • Pro: Add the possibility to bulk duplicate or bulk synchronize posts.
  • Pro: Add compatibility with Admin Columns
  • Pro: Add synchronized posts to the REST API
  • Pro: Fix variations messed when changing WooCommerce attributes slugs
  • Pro: Fix incorrect language for ajax requests made on front by The Events Calendar
  • Pro: Fix term not duplicated correctly when the language is set from the content
  • Refactor the core to activate on front and for the REST api actions that were previously available only in the backend (language checks, synchronizations...).
  • Add flags to widgets displayed in only one language (Props Jory Hogeveen) #257
  • Honor 'pll_the_language_args' for all options in menus #237
  • Add better filters for default flags and custom flags
  • Custom flags can now be stored in the polylang directory in the theme
  • Custom flags can now use SVG
  • Add compatibility with Jetpack featured content module
  • Fix Twenty Fourteen featured posts possibly not filtered per language
  • Fix home url not working with WordPress MU Domain mapping
  • Fix Assigning a parent category breaking the hierarchy of translated category
  • Fix: Accept 0,1 and 1.0 as q factors in browser preferred language detection (Props Dominic Rubas)
  • Fix performance issue when using hundreds of widgets
  • Fix translations possibly wrong if the post language is changed without saving the post after
Download this release

Release Info

Developer Chouby
Plugin Icon 128x128 Polylang
Version 2.4
Comparing to
See all releases

Code changes from version 2.3.11 to 2.4

Files changed (90) hide show
  1. admin/admin-base.php +58 -43
  2. admin/admin-classic-editor.php +285 -0
  3. admin/admin-filters-columns.php +9 -3
  4. admin/admin-filters-media.php +8 -36
  5. admin/admin-filters-post-base.php +0 -23
  6. admin/admin-filters-post.php +1 -399
  7. admin/admin-filters-term.php +53 -222
  8. admin/admin-filters.php +9 -38
  9. admin/admin-model.php +54 -42
  10. admin/admin-nav-menu.php +10 -8
  11. admin/admin-notices.php +17 -14
  12. admin/admin-static-pages.php +1 -1
  13. admin/admin-strings.php +4 -4
  14. admin/admin.php +24 -17
  15. admin/view-translations-post.php +2 -2
  16. admin/view-translations-term.php +2 -2
  17. changelog.txt +0 -1
  18. css/admin.css +1 -1
  19. css/admin.min.css +1 -1
  20. css/selectmenu.css +1 -1
  21. css/selectmenu.min.css +1 -1
  22. frontend/choose-lang.php +9 -7
  23. frontend/frontend-auto-translate.php +9 -7
  24. frontend/frontend-filters-links.php +17 -11
  25. frontend/frontend-filters-search.php +12 -10
  26. frontend/frontend-filters.php +16 -145
  27. frontend/frontend-nav-menu.php +4 -1
  28. frontend/frontend.php +19 -12
  29. include/api.php +3 -3
  30. include/base.php +9 -4
  31. include/class-polylang.php +3 -3
  32. include/crud-posts.php +234 -0
  33. include/crud-terms.php +206 -0
  34. include/filters.php +1 -1
  35. include/language.php +67 -28
  36. include/license.php +1 -1
  37. include/links-default.php +1 -1
  38. include/links-directory.php +2 -2
  39. include/links-domain.php +1 -1
  40. include/model.php +12 -4
  41. include/olt-manager.php +7 -7
  42. include/pointer.php +4 -4
  43. include/switcher.php +6 -4
  44. include/translated-post.php +18 -15
  45. include/translated-term.php +1 -1
  46. include/walker-dropdown.php +4 -4
  47. include/walker-list.php +4 -4
  48. include/widget-languages.php +5 -5
  49. install/install.php +11 -7
  50. install/upgrade.php +22 -12
  51. js/admin.js +15 -11
  52. js/admin.min.js +1 -1
  53. js/classic-editor.js +157 -0
  54. js/classic-editor.min.js +1 -0
  55. js/post.js +2 -152
  56. js/post.min.js +1 -1
  57. js/widgets.js +83 -0
  58. js/widgets.min.js +1 -0
  59. modules/plugins/cache-compat.php +2 -2
  60. modules/plugins/featured-content.php +130 -0
  61. modules/plugins/jetpack.php +1 -1
  62. modules/plugins/plugins-compat.php +21 -80
  63. modules/plugins/wp-import.php +17 -12
  64. modules/plugins/wpseo.php +19 -8
  65. modules/share-slug/settings-share-slug.php +8 -5
  66. modules/sync/admin-sync.php +53 -150
  67. modules/sync/settings-sync.php +9 -6
  68. modules/sync/sync-metas.php +3 -3
  69. modules/sync/sync-tax.php +16 -14
  70. modules/sync/sync.php +177 -0
  71. modules/translate-slugs/settings-translate-slugs.php +8 -5
  72. modules/wpml/settings-wpml.php +8 -5
  73. modules/wpml/wpml-compat.php +3 -3
  74. modules/wpml/wpml-config.php +2 -2
  75. polylang.php +5 -4
  76. readme.txt +26 -3
  77. settings/flags.php +245 -245
  78. settings/settings-browser.php +9 -6
  79. settings/settings-cpt.php +8 -5
  80. settings/settings-licenses.php +17 -10
  81. settings/settings-media.php +9 -6
  82. settings/settings-module.php +12 -13
  83. settings/settings-tools.php +8 -5
  84. settings/settings-url.php +31 -14
  85. settings/settings.php +31 -22
  86. settings/table-languages.php +22 -18
  87. settings/table-settings.php +16 -16
  88. settings/table-string.php +27 -21
  89. settings/view-tab-lang.php +7 -1
  90. uninstall.php +23 -19
admin/admin-base.php CHANGED
@@ -29,6 +29,8 @@ class PLL_Admin_Base extends PLL_Base {
29
  add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
30
  add_action( 'admin_print_footer_scripts', array( $this, 'admin_print_footer_scripts' ), 0 ); // High priority in case an ajax request is sent by an immediately invoked function
31
 
 
 
32
  // Lingotek
33
  if ( ! defined( 'POLYLANG_PRO' ) && ( ! defined( 'PLL_LINGOTEK_AD' ) || PLL_LINGOTEK_AD ) ) {
34
  require_once POLYLANG_DIR . '/lingotek/lingotek.php';
@@ -116,10 +118,12 @@ class PLL_Admin_Base extends PLL_Base {
116
  // 3 => 1 if loaded in footer
117
  // FIXME: check if I can load more scripts in footer
118
  $scripts = array(
119
- 'post' => array( array( 'post', 'media', 'async-upload', 'edit' ), array( 'jquery', 'wp-ajax-response', 'post', 'jquery-ui-autocomplete' ), 0, 1 ),
120
- 'media' => array( array( 'upload' ), array( 'jquery' ), 0, 1 ),
121
- 'term' => array( array( 'edit-tags', 'term' ), array( 'jquery', 'wp-ajax-response', 'jquery-ui-autocomplete' ), 0, 1 ),
122
- 'user' => array( array( 'profile', 'user-edit' ), array( 'jquery' ), 0, 0 ),
 
 
123
  );
124
 
125
  foreach ( $scripts as $script => $v ) {
@@ -129,6 +133,38 @@ class PLL_Admin_Base extends PLL_Base {
129
  }
130
 
131
  wp_enqueue_style( 'polylang_admin', plugins_url( '/css/admin' . $suffix . '.css', POLYLANG_FILE ), array(), POLYLANG_VERSION );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
132
  }
133
 
134
  /**
@@ -236,12 +272,6 @@ class PLL_Admin_Base extends PLL_Base {
236
  * @since 1.2.3
237
  */
238
  public function init_user() {
239
- // Backend locale
240
- // FIXME: Backward compatibility with WP < 4.7
241
- if ( version_compare( $GLOBALS['wp_version'], '4.7alpha', '<' ) ) {
242
- add_filter( 'locale', array( $this, 'get_locale' ) );
243
- }
244
-
245
  // Language for admin language filter: may be empty
246
  // $_GET['lang'] is numeric when editing a language, not when selecting a new language in the filter
247
  if ( ! wp_doing_ajax() && ! empty( $_GET['lang'] ) && ! is_numeric( $_GET['lang'] ) && current_user_can( 'edit_user', $user_id = get_current_user_id() ) ) {
@@ -267,13 +297,7 @@ class PLL_Admin_Base extends PLL_Base {
267
 
268
  // Inform that the admin language has been set
269
  // Only if the admin language is one of the Polylang defined language
270
- // FIXME test get_user_locale for backward compatibility with WP 4.7
271
- if ( $curlang = $this->model->get_language( function_exists( 'get_user_locale' ) ? get_user_locale() : get_locale() ) ) {
272
- // FIXME: Backward compatibility with WP < 4.7
273
- if ( version_compare( $GLOBALS['wp_version'], '4.7alpha', '<' ) ) {
274
- $GLOBALS['text_direction'] = $curlang->is_rtl ? 'rtl' : 'ltr'; // force text direction according to language setting
275
- }
276
-
277
  /** This action is documented in frontend/choose-lang.php */
278
  do_action( 'pll_language_defined', $curlang->slug, $curlang );
279
  } else {
@@ -301,19 +325,6 @@ class PLL_Admin_Base extends PLL_Base {
301
  return $qvars;
302
  }
303
 
304
- /**
305
- * Get the locale based on user preference
306
- * FIXME: Backward compatibility with WP < 4.7
307
- *
308
- * @since 0.4
309
- *
310
- * @param string $locale
311
- * @return string modified locale
312
- */
313
- public function get_locale( $locale ) {
314
- return ( $loc = get_user_meta( get_current_user_id(), 'locale', 'true' ) ) ? $loc : $locale;
315
- }
316
-
317
  /**
318
  * Adds the languages list in admin bar for the admin languages filter
319
  *
@@ -337,25 +348,29 @@ class PLL_Admin_Base extends PLL_Base {
337
  esc_html( $selected->name )
338
  );
339
 
340
- $wp_admin_bar->add_menu( array(
341
- 'id' => 'languages',
342
- 'title' => $selected->flag . $title,
343
- 'href' => esc_url( add_query_arg( 'lang', $selected->slug, remove_query_arg( 'paged' ) ) ),
344
- 'meta' => array( 'title' => __( 'Filters content by language', 'polylang' ) ),
345
- ) );
 
 
346
 
347
  foreach ( array_merge( array( $all_item ), $this->model->get_languages_list() ) as $lang ) {
348
  if ( $selected->slug === $lang->slug ) {
349
  continue;
350
  }
351
 
352
- $wp_admin_bar->add_menu( array(
353
- 'parent' => 'languages',
354
- 'id' => $lang->slug,
355
- 'title' => $lang->flag . esc_html( $lang->name ),
356
- 'href' => esc_url( add_query_arg( 'lang', $lang->slug, remove_query_arg( 'paged' ) ) ),
357
- 'meta' => 'all' === $lang->slug ? array() : array( 'lang' => esc_attr( $lang->get_locale( 'display' ) ) ),
358
- ) );
 
 
359
  }
360
  }
361
  }
29
  add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
30
  add_action( 'admin_print_footer_scripts', array( $this, 'admin_print_footer_scripts' ), 0 ); // High priority in case an ajax request is sent by an immediately invoked function
31
 
32
+ add_action( 'customize_controls_enqueue_scripts', array( $this, 'customize_controls_enqueue_scripts' ) );
33
+
34
  // Lingotek
35
  if ( ! defined( 'POLYLANG_PRO' ) && ( ! defined( 'PLL_LINGOTEK_AD' ) || PLL_LINGOTEK_AD ) ) {
36
  require_once POLYLANG_DIR . '/lingotek/lingotek.php';
118
  // 3 => 1 if loaded in footer
119
  // FIXME: check if I can load more scripts in footer
120
  $scripts = array(
121
+ 'classic-editor' => array( array( 'post', 'media', 'async-upload' ), array( 'jquery', 'wp-ajax-response', 'post', 'jquery-ui-autocomplete' ), 0, 1 ),
122
+ 'post' => array( array( 'edit' ), array( 'jquery', 'wp-ajax-response' ), 0, 1 ),
123
+ 'media' => array( array( 'upload' ), array( 'jquery' ), 0, 1 ),
124
+ 'term' => array( array( 'edit-tags', 'term' ), array( 'jquery', 'wp-ajax-response', 'jquery-ui-autocomplete' ), 0, 1 ),
125
+ 'user' => array( array( 'profile', 'user-edit' ), array( 'jquery' ), 0, 0 ),
126
+ 'widgets' => array( array( 'widgets' ), array( 'jquery' ), 0, 0 ),
127
  );
128
 
129
  foreach ( $scripts as $script => $v ) {
133
  }
134
 
135
  wp_enqueue_style( 'polylang_admin', plugins_url( '/css/admin' . $suffix . '.css', POLYLANG_FILE ), array(), POLYLANG_VERSION );
136
+
137
+ $this->localize_scripts();
138
+ }
139
+
140
+ /**
141
+ * Enqueue scripts to the WP Customizer.
142
+ *
143
+ * @since 2.4.0
144
+ */
145
+ public function customize_controls_enqueue_scripts() {
146
+ if ( $this->model->get_languages_list() ) {
147
+ $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
148
+ wp_enqueue_script( 'pll_widgets', plugins_url( '/js/widgets' . $suffix . '.js', POLYLANG_FILE ), array( 'jquery' ), POLYLANG_VERSION, true );
149
+ $this->localize_scripts();
150
+ }
151
+ }
152
+
153
+ /**
154
+ * Localize scripts.
155
+ *
156
+ * @since 2.4.0
157
+ */
158
+ public function localize_scripts() {
159
+ if ( wp_script_is( 'pll_widgets', 'enqueued' ) ) {
160
+ wp_localize_script(
161
+ 'pll_widgets',
162
+ 'pll_widgets',
163
+ array(
164
+ 'flags' => wp_list_pluck( $this->model->get_languages_list(), 'flag', 'slug' ),
165
+ )
166
+ );
167
+ }
168
  }
169
 
170
  /**
272
  * @since 1.2.3
273
  */
274
  public function init_user() {
 
 
 
 
 
 
275
  // Language for admin language filter: may be empty
276
  // $_GET['lang'] is numeric when editing a language, not when selecting a new language in the filter
277
  if ( ! wp_doing_ajax() && ! empty( $_GET['lang'] ) && ! is_numeric( $_GET['lang'] ) && current_user_can( 'edit_user', $user_id = get_current_user_id() ) ) {
297
 
298
  // Inform that the admin language has been set
299
  // Only if the admin language is one of the Polylang defined language
300
+ if ( $curlang = $this->model->get_language( get_user_locale() ) ) {
 
 
 
 
 
 
301
  /** This action is documented in frontend/choose-lang.php */
302
  do_action( 'pll_language_defined', $curlang->slug, $curlang );
303
  } else {
325
  return $qvars;
326
  }
327
 
 
 
 
 
 
 
 
 
 
 
 
 
 
328
  /**
329
  * Adds the languages list in admin bar for the admin languages filter
330
  *
348
  esc_html( $selected->name )
349
  );
350
 
351
+ $wp_admin_bar->add_menu(
352
+ array(
353
+ 'id' => 'languages',
354
+ 'title' => $selected->flag . $title,
355
+ 'href' => esc_url( add_query_arg( 'lang', $selected->slug, remove_query_arg( 'paged' ) ) ),
356
+ 'meta' => array( 'title' => __( 'Filters content by language', 'polylang' ) ),
357
+ )
358
+ );
359
 
360
  foreach ( array_merge( array( $all_item ), $this->model->get_languages_list() ) as $lang ) {
361
  if ( $selected->slug === $lang->slug ) {
362
  continue;
363
  }
364
 
365
+ $wp_admin_bar->add_menu(
366
+ array(
367
+ 'parent' => 'languages',
368
+ 'id' => $lang->slug,
369
+ 'title' => $lang->flag . esc_html( $lang->name ),
370
+ 'href' => esc_url( add_query_arg( 'lang', $lang->slug, remove_query_arg( 'paged' ) ) ),
371
+ 'meta' => 'all' === $lang->slug ? array() : array( 'lang' => esc_attr( $lang->get_locale( 'display' ) ) ),
372
+ )
373
+ );
374
  }
375
  }
376
  }
admin/admin-classic-editor.php ADDED
@@ -0,0 +1,285 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Manages filters and actions related to the editor
5
+ *
6
+ * @since 2.4
7
+ */
8
+ class PLL_Admin_Classic_Editor {
9
+ public $model, $links, $curlang, $pref_lang;
10
+
11
+ /**
12
+ * Constructor: setups filters and actions
13
+ *
14
+ * @since 2.4
15
+ *
16
+ * @param object $polylang
17
+ */
18
+ public function __construct( &$polylang ) {
19
+ $this->model = &$polylang->model;
20
+ $this->links = &$polylang->links;
21
+ $this->curlang = &$polylang->curlang;
22
+ $this->pref_lang = &$polylang->pref_lang;
23
+
24
+ // Adds the Languages box in the 'Edit Post' and 'Edit Page' panels
25
+ add_action( 'add_meta_boxes', array( $this, 'add_meta_boxes' ), 10, 2 );
26
+
27
+ // Ajax response for changing the language in the post metabox
28
+ add_action( 'wp_ajax_post_lang_choice', array( $this, 'post_lang_choice' ) );
29
+ add_action( 'wp_ajax_pll_posts_not_translated', array( $this, 'ajax_posts_not_translated' ) );
30
+
31
+ // Filters the pages by language in the parent dropdown list in the page attributes metabox
32
+ add_filter( 'page_attributes_dropdown_pages_args', array( $this, 'page_attributes_dropdown_pages_args' ), 10, 2 );
33
+ }
34
+
35
+ /**
36
+ * Adds the Language box in the 'Edit Post' and 'Edit Page' panels ( as well as in custom post types panels )
37
+ *
38
+ * @since 0.1
39
+ *
40
+ * @param string $post_type Current post type
41
+ * @param object $post Current post
42
+ */
43
+ public function add_meta_boxes( $post_type, $post ) {
44
+ if ( $this->model->is_translated_post_type( $post_type ) ) {
45
+ add_meta_box( 'ml_box', __( 'Languages', 'polylang' ), array( $this, 'post_language' ), $post_type, 'side', 'high' );
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Displays the Languages metabox in the 'Edit Post' and 'Edit Page' panels
51
+ *
52
+ * @since 0.1
53
+ */
54
+ public function post_language() {
55
+ global $post_ID;
56
+ $post_id = $post_ID;
57
+ $post_type = get_post_type( $post_ID );
58
+
59
+ $lang = ( $lg = $this->model->post->get_language( $post_ID ) ) ? $lg :
60
+ ( isset( $_GET['new_lang'] ) ? $this->model->get_language( $_GET['new_lang'] ) :
61
+ $this->pref_lang );
62
+
63
+ $dropdown = new PLL_Walker_Dropdown();
64
+
65
+ wp_nonce_field( 'pll_language', '_pll_nonce' );
66
+
67
+ // NOTE: the class "tags-input" allows to include the field in the autosave $_POST ( see autosave.js )
68
+ printf(
69
+ '<p><strong>%1$s</strong></p>
70
+ <label class="screen-reader-text" for="%2$s">%1$s</label>
71
+ <div id="select-%3$s-language">%4$s</div>',
72
+ esc_html__( 'Language', 'polylang' ),
73
+ $id = ( 'attachment' === $post_type ) ? sprintf( 'attachments[%d][language]', $post_ID ) : 'post_lang_choice',
74
+ 'attachment' === $post_type ? 'media' : 'post',
75
+ $dropdown->walk(
76
+ $this->model->get_languages_list(),
77
+ array(
78
+ 'name' => $id,
79
+ 'class' => 'post_lang_choice tags-input',
80
+ 'selected' => $lang ? $lang->slug : '',
81
+ 'flag' => true,
82
+ )
83
+ )
84
+ );
85
+
86
+ /**
87
+ * Fires before displaying the list of translations in the Languages metabox for posts
88
+ *
89
+ * @since 1.8
90
+ */
91
+ do_action( 'pll_before_post_translations', $post_type );
92
+
93
+ echo '<div id="post-translations" class="translations">';
94
+ if ( $lang ) {
95
+ include PLL_ADMIN_INC . '/view-translations-' . ( 'attachment' == $post_type ? 'media' : 'post' ) . '.php';
96
+ }
97
+ echo '</div>' . "\n";
98
+ }
99
+
100
+ /**
101
+ * Ajax response for changing the language in the post metabox
102
+ *
103
+ * @since 0.2
104
+ */
105
+ public function post_lang_choice() {
106
+ check_ajax_referer( 'pll_language', '_pll_nonce' );
107
+
108
+ global $post_ID; // Obliged to use the global variable for wp_popular_terms_checklist
109
+ $post_id = $post_ID = (int) $_POST['post_id'];
110
+ $lang = $this->model->get_language( $_POST['lang'] );
111
+
112
+ $post_type = $_POST['post_type'];
113
+ $post_type_object = get_post_type_object( $post_type );
114
+ if ( ! current_user_can( $post_type_object->cap->edit_post, $post_ID ) ) {
115
+ wp_die( -1 );
116
+ }
117
+
118
+ $this->model->post->set_language( $post_ID, $lang ); // Save language, useful to set the language when uploading media from post
119
+
120
+ // We also need to save the translations to match the language change
121
+ $translations = $this->model->post->get_translations( $post_ID );
122
+ $translations = array_diff( $translations, array( $post_ID ) );
123
+ $this->model->post->save_translations( $post_ID, $translations );
124
+
125
+ ob_start();
126
+ if ( $lang ) {
127
+ include PLL_ADMIN_INC . '/view-translations-' . ( 'attachment' == $post_type ? 'media' : 'post' ) . '.php';
128
+ }
129
+ $x = new WP_Ajax_Response( array( 'what' => 'translations', 'data' => ob_get_contents() ) );
130
+ ob_end_clean();
131
+
132
+ // Categories
133
+ if ( isset( $_POST['taxonomies'] ) ) {
134
+ // Not set for pages
135
+ foreach ( $_POST['taxonomies'] as $taxname ) {
136
+ $taxonomy = get_taxonomy( $taxname );
137
+
138
+ ob_start();
139
+ $popular_ids = wp_popular_terms_checklist( $taxonomy->name );
140
+ $supplemental['populars'] = ob_get_contents();
141
+ ob_end_clean();
142
+
143
+ ob_start();
144
+ // Use $post_ID to remember checked terms in case we come back to the original language
145
+ wp_terms_checklist( $post_ID, array( 'taxonomy' => $taxonomy->name, 'popular_cats' => $popular_ids ) );
146
+ $supplemental['all'] = ob_get_contents();
147
+ ob_end_clean();
148
+
149
+ $supplemental['dropdown'] = wp_dropdown_categories(
150
+ array(
151
+ 'taxonomy' => $taxonomy->name,
152
+ 'hide_empty' => 0,
153
+ 'name' => 'new' . $taxonomy->name . '_parent',
154
+ 'orderby' => 'name',
155
+ 'hierarchical' => 1,
156
+ 'show_option_none' => '&mdash; ' . $taxonomy->labels->parent_item . ' &mdash;',
157
+ 'echo' => 0,
158
+ )
159
+ );
160
+
161
+ $x->Add( array( 'what' => 'taxonomy', 'data' => $taxonomy->name, 'supplemental' => $supplemental ) );
162
+ }
163
+ }
164
+
165
+ // Parent dropdown list ( only for hierarchical post types )
166
+ if ( in_array( $post_type, get_post_types( array( 'hierarchical' => true ) ) ) ) {
167
+ $post = get_post( $post_ID );
168
+
169
+ // Args and filter from 'page_attributes_meta_box' in wp-admin/includes/meta-boxes.php of WP 4.2.1
170
+ $dropdown_args = array(
171
+ 'post_type' => $post->post_type,
172
+ 'exclude_tree' => $post->ID,
173
+ 'selected' => $post->post_parent,
174
+ 'name' => 'parent_id',
175
+ 'show_option_none' => __( '(no parent)' ),
176
+ 'sort_column' => 'menu_order, post_title',
177
+ 'echo' => 0,
178
+ );
179
+
180
+ /** This filter is documented in wp-admin/includes/meta-boxes.php */
181
+ $dropdown_args = apply_filters( 'page_attributes_dropdown_pages_args', $dropdown_args, $post ); // Since WP 3.3
182
+
183
+ $x->Add( array( 'what' => 'pages', 'data' => wp_dropdown_pages( $dropdown_args ) ) );
184
+ }
185
+
186
+ // Flag
187
+ $x->Add( array( 'what' => 'flag', 'data' => empty( $lang->flag ) ? esc_html( $lang->slug ) : $lang->flag ) );
188
+
189
+ // Sample permalink
190
+ $x->Add( array( 'what' => 'permalink', 'data' => get_sample_permalink_html( $post_ID ) ) );
191
+
192
+ $x->send();
193
+ }
194
+
195
+ /**
196
+ * Ajax response for input in translation autocomplete input box
197
+ *
198
+ * @since 1.5
199
+ */
200
+ public function ajax_posts_not_translated() {
201
+ check_ajax_referer( 'pll_language', '_pll_nonce' );
202
+
203
+ if ( ! post_type_exists( $_GET['post_type'] ) ) {
204
+ die( 0 );
205
+ }
206
+
207
+ $post_language = $this->model->get_language( $_GET['post_language'] );
208
+ $translation_language = $this->model->get_language( $_GET['translation_language'] );
209
+
210
+ // Don't order by title: see https://wordpress.org/support/topic/find-translated-post-when-10-is-not-enough
211
+ $args = array(
212
+ 's' => wp_unslash( $_GET['term'] ),
213
+ 'suppress_filters' => 0, // To make the post_fields filter work
214
+ 'lang' => 0, // Avoid admin language filter
215
+ 'numberposts' => 20, // Limit to 20 posts
216
+ 'post_status' => 'any',
217
+ 'post_type' => $_GET['post_type'],
218
+ 'tax_query' => array(
219
+ array(
220
+ 'taxonomy' => 'language',
221
+ 'field' => 'term_taxonomy_id', // WP 3.5+
222
+ 'terms' => $translation_language->term_taxonomy_id,
223
+ ),
224
+ ),
225
+ );
226
+
227
+ /**
228
+ * Filter the query args when auto suggesting untranslated posts in the Languages metabox
229
+ * This should help plugins to fix some edge cases
230
+ *
231
+ * @see https://wordpress.org/support/topic/find-translated-post-when-10-is-not-enough
232
+ *
233
+ * @since 1.7
234
+ *
235
+ * @param array $args WP_Query arguments
236
+ */
237
+ $args = apply_filters( 'pll_ajax_posts_not_translated_args', $args );
238
+ $posts = get_posts( $args );
239
+
240
+ $return = array();
241
+
242
+ foreach ( $posts as $key => $post ) {
243
+ if ( ! $this->model->post->get_translation( $post->ID, $post_language ) ) {
244
+ $return[] = array(
245
+ 'id' => $post->ID,
246
+ 'value' => $post->post_title,
247
+ 'link' => $this->links->edit_post_translation_link( $post->ID ),
248
+ );
249
+ }
250
+ }
251
+
252
+ // Add current translation in list
253
+ if ( $post_id = $this->model->post->get_translation( (int) $_GET['pll_post_id'], $translation_language ) ) {
254
+ $post = get_post( $post_id );
255
+ array_unshift(
256
+ $return,
257
+ array(
258
+ 'id' => $post_id,
259
+ 'value' => $post->post_title,
260
+ 'link' => $this->links->edit_post_translation_link( $post_id ),
261
+ )
262
+ );
263
+ }
264
+
265
+ wp_die( json_encode( $return ) );
266
+ }
267
+
268
+ /**
269
+ * Filters the pages by language in the parent dropdown list in the page attributes metabox
270
+ *
271
+ * @since 0.6
272
+ *
273
+ * @param array $dropdown_args Arguments passed to wp_dropdown_pages
274
+ * @param object $post
275
+ * @return array Modified arguments
276
+ */
277
+ public function page_attributes_dropdown_pages_args( $dropdown_args, $post ) {
278
+ $dropdown_args['lang'] = isset( $_POST['lang'] ) ? $this->model->get_language( $_POST['lang'] ) : $this->model->post->get_language( $post->ID ); // ajax or not ?
279
+ if ( ! $dropdown_args['lang'] ) {
280
+ $dropdown_args['lang'] = $this->pref_lang;
281
+ }
282
+
283
+ return $dropdown_args;
284
+ }
285
+ }
admin/admin-filters-columns.php CHANGED
@@ -94,7 +94,7 @@ class PLL_Admin_Filters_Columns {
94
  * @param array $columns list of posts table columns
95
  * @return array modified list of columns
96
  */
97
- function add_post_column( $columns ) {
98
  return $this->add_column( $columns, 'comments' );
99
  }
100
 
@@ -140,7 +140,10 @@ class PLL_Admin_Filters_Columns {
140
  }
141
  printf(
142
  '<a class="%1$s" title="%2$s" href="%3$s"><span class="screen-reader-text">%4$s</span></a>',
143
- esc_attr( $class ), esc_attr( get_post( $id )->post_title ), esc_url( $link ), esc_html( $s )
 
 
 
144
  );
145
  } elseif ( $id === $post_id ) {
146
  printf(
@@ -251,7 +254,10 @@ class PLL_Admin_Filters_Columns {
251
  }
252
  $out .= sprintf(
253
  '<a class="%1$s" title="%2$s" href="%3$s"><span class="screen-reader-text">%4$s</span></a>',
254
- $class, esc_attr( $term->name ), esc_url( $link ), esc_html( $s )
 
 
 
255
  );
256
  } elseif ( $id === $term_id ) {
257
  $out .= printf(
94
  * @param array $columns list of posts table columns
95
  * @return array modified list of columns
96
  */
97
+ public function add_post_column( $columns ) {
98
  return $this->add_column( $columns, 'comments' );
99
  }
100
 
140
  }
141
  printf(
142
  '<a class="%1$s" title="%2$s" href="%3$s"><span class="screen-reader-text">%4$s</span></a>',
143
+ esc_attr( $class ),
144
+ esc_attr( get_post( $id )->post_title ),
145
+ esc_url( $link ),
146
+ esc_html( $s )
147
  );
148
  } elseif ( $id === $post_id ) {
149
  printf(
254
  }
255
  $out .= sprintf(
256
  '<a class="%1$s" title="%2$s" href="%3$s"><span class="screen-reader-text">%4$s</span></a>',
257
+ $class,
258
+ esc_attr( $term->name ),
259
+ esc_url( $link ),
260
+ esc_html( $s )
261
  );
262
  } elseif ( $id === $term_id ) {
263
  $out .= printf(
admin/admin-filters-media.php CHANGED
@@ -21,9 +21,7 @@ class PLL_Admin_Filters_Media extends PLL_Admin_Filters_Post_Base {
21
  add_filter( 'attachment_fields_to_edit', array( $this, 'attachment_fields_to_edit' ), 10, 2 );
22
 
23
  // Adds actions related to languages when creating, saving or deleting media
24
- add_action( 'add_attachment', array( $this, 'set_default_language' ) );
25
  add_filter( 'attachment_fields_to_save', array( $this, 'save_media' ), 10, 2 );
26
- add_filter( 'wp_delete_file', array( $this, 'wp_delete_file' ) );
27
 
28
  // Creates a media translation
29
  if ( isset( $_GET['action'], $_GET['new_lang'], $_GET['from_media'] ) && 'translate_media' === $_GET['action'] ) {
@@ -53,11 +51,14 @@ class PLL_Admin_Filters_Media extends PLL_Admin_Filters_Post_Base {
53
  $fields['language'] = array(
54
  'label' => __( 'Language', 'polylang' ),
55
  'input' => 'html',
56
- 'html' => $dropdown->walk( $this->model->get_languages_list(), array(
57
- 'name' => sprintf( 'attachments[%d][language]', $post_id ),
58
- 'class' => 'media_lang_choice',
59
- 'selected' => $lang ? $lang->slug : '',
60
- ) ),
 
 
 
61
  );
62
 
63
  return $fields;
@@ -163,33 +164,4 @@ class PLL_Admin_Filters_Media extends PLL_Admin_Filters_Post_Base {
163
 
164
  return $post;
165
  }
166
-
167
- /**
168
- * Prevents WP deleting files when there are still media using them
169
- * Thanks to Bruno "Aesqe" Babic and its plugin file gallery in which I took all the ideas for this function
170
- *
171
- * @since 0.9
172
- *
173
- * @param string $file
174
- * @return string unmodified $file
175
- */
176
- public function wp_delete_file( $file ) {
177
- global $wpdb;
178
-
179
- $uploadpath = wp_upload_dir();
180
-
181
- $ids = $wpdb->get_col( $wpdb->prepare( "
182
- SELECT post_id FROM $wpdb->postmeta
183
- WHERE meta_key = '_wp_attached_file' AND meta_value = %s",
184
- substr_replace( $file, '', 0, strlen( trailingslashit( $uploadpath['basedir'] ) ) )
185
- ) );
186
-
187
- if ( ! empty( $ids ) ) {
188
- // Regenerate intermediate sizes if it's an image ( since we could not prevent WP deleting them before )
189
- wp_update_attachment_metadata( $ids[0], wp_generate_attachment_metadata( $ids[0], $file ) );
190
- return ''; // Prevent deleting the main file
191
- }
192
-
193
- return $file;
194
- }
195
  }
21
  add_filter( 'attachment_fields_to_edit', array( $this, 'attachment_fields_to_edit' ), 10, 2 );
22
 
23
  // Adds actions related to languages when creating, saving or deleting media
 
24
  add_filter( 'attachment_fields_to_save', array( $this, 'save_media' ), 10, 2 );
 
25
 
26
  // Creates a media translation
27
  if ( isset( $_GET['action'], $_GET['new_lang'], $_GET['from_media'] ) && 'translate_media' === $_GET['action'] ) {
51
  $fields['language'] = array(
52
  'label' => __( 'Language', 'polylang' ),
53
  'input' => 'html',
54
+ 'html' => $dropdown->walk(
55
+ $this->model->get_languages_list(),
56
+ array(
57
+ 'name' => sprintf( 'attachments[%d][language]', $post_id ),
58
+ 'class' => 'media_lang_choice',
59
+ 'selected' => $lang ? $lang->slug : '',
60
+ )
61
+ ),
62
  );
63
 
64
  return $fields;
164
 
165
  return $post;
166
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
167
  }
admin/admin-filters-post-base.php CHANGED
@@ -21,29 +21,6 @@ abstract class PLL_Admin_Filters_Post_Base {
21
  $this->pref_lang = &$polylang->pref_lang;
22
  }
23
 
24
- /**
25
- * Allows to set a language by default for posts if it has no language yet
26
- *
27
- * @since 1.5
28
- *
29
- * @param int $post_id
30
- */
31
- public function set_default_language( $post_id ) {
32
- if ( ! $this->model->post->get_language( $post_id ) ) {
33
- if ( isset( $_GET['new_lang'] ) && $lang = $this->model->get_language( $_GET['new_lang'] ) ) {
34
- $this->model->post->set_language( $post_id, $lang );
35
- }
36
-
37
- elseif ( ( $parent_id = wp_get_post_parent_id( $post_id ) ) && $parent_lang = $this->model->post->get_language( $parent_id ) ) {
38
- $this->model->post->set_language( $post_id, $parent_lang );
39
- }
40
-
41
- else {
42
- $this->model->post->set_language( $post_id, $this->pref_lang );
43
- }
44
- }
45
- }
46
-
47
  /**
48
  * Save translations from language metabox
49
  *
21
  $this->pref_lang = &$polylang->pref_lang;
22
  }
23
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  /**
25
  * Save translations from language metabox
26
  *
admin/admin-filters-post.php CHANGED
@@ -6,7 +6,7 @@
6
  * @since 1.2
7
  */
8
  class PLL_Admin_Filters_Post extends PLL_Admin_Filters_Post_Base {
9
- public $options, $curlang;
10
 
11
  /**
12
  * Constructor: setups filters and actions
@@ -17,7 +17,6 @@ class PLL_Admin_Filters_Post extends PLL_Admin_Filters_Post_Base {
17
  */
18
  public function __construct( &$polylang ) {
19
  parent::__construct( $polylang );
20
- $this->options = &$polylang->options;
21
  $this->curlang = &$polylang->curlang;
22
 
23
  add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
@@ -25,27 +24,10 @@ class PLL_Admin_Filters_Post extends PLL_Admin_Filters_Post_Base {
25
  // Filters posts, pages and media by language
26
  add_action( 'parse_query', array( $this, 'parse_query' ) );
27
 
28
- // Adds the Languages box in the 'Edit Post' and 'Edit Page' panels
29
- add_action( 'add_meta_boxes', array( $this, 'add_meta_boxes' ), 10, 2 );
30
-
31
- // Ajax response for changing the language in the post metabox
32
- add_action( 'wp_ajax_post_lang_choice', array( $this, 'post_lang_choice' ) );
33
- add_action( 'wp_ajax_pll_posts_not_translated', array( $this, 'ajax_posts_not_translated' ) );
34
-
35
  // Adds actions and filters related to languages when creating, saving or deleting posts and pages
36
  add_action( 'load-post.php', array( $this, 'edit_post' ) );
37
  add_action( 'load-edit.php', array( $this, 'bulk_edit_posts' ) );
38
  add_action( 'wp_ajax_inline-save', array( $this, 'inline_edit_post' ), 0 ); // Before WordPress
39
- add_action( 'save_post', array( $this, 'save_post' ), 21, 3 ); // Priority 21 to come after advanced custom fields ( 20 ) and before the event calendar which breaks everything after 25
40
- add_action( 'set_object_terms', array( $this, 'set_object_terms' ), 10, 4 );
41
- add_filter( 'wp_insert_post_parent', array( $this, 'wp_insert_post_parent' ), 10, 4 );
42
- add_action( 'before_delete_post', array( $this, 'delete_post' ) );
43
- if ( $this->options['media_support'] ) {
44
- add_action( 'delete_attachment', array( $this, 'delete_post' ) ); // Action shared with media
45
- }
46
-
47
- // Filters the pages by language in the parent dropdown list in the page attributes metabox
48
- add_filter( 'page_attributes_dropdown_pages_args', array( $this, 'page_attributes_dropdown_pages_args' ), 10, 2 );
49
 
50
  // Sets the language in Tiny MCE
51
  add_filter( 'tiny_mce_before_init', array( $this, 'tiny_mce_before_init' ) );
@@ -116,226 +98,6 @@ class PLL_Admin_Filters_Post extends PLL_Admin_Filters_Post_Base {
116
  $pll_query->filter_query( $this->curlang );
117
  }
118
 
119
- /**
120
- * Adds the Language box in the 'Edit Post' and 'Edit Page' panels ( as well as in custom post types panels )
121
- *
122
- * @since 0.1
123
- *
124
- * @param string $post_type Current post type
125
- * @param object $post Current post
126
- */
127
- public function add_meta_boxes( $post_type, $post ) {
128
- if ( $this->model->is_translated_post_type( $post_type ) ) {
129
- add_meta_box( 'ml_box', __( 'Languages', 'polylang' ), array( $this, 'post_language' ), $post_type, 'side', 'high' );
130
- }
131
- }
132
-
133
- /**
134
- * Displays the Languages metabox in the 'Edit Post' and 'Edit Page' panels
135
- *
136
- * @since 0.1
137
- */
138
- public function post_language() {
139
- global $post_ID;
140
- $post_id = $post_ID;
141
- $post_type = get_post_type( $post_ID );
142
-
143
- $lang = ( $lg = $this->model->post->get_language( $post_ID ) ) ? $lg :
144
- ( isset( $_GET['new_lang'] ) ? $this->model->get_language( $_GET['new_lang'] ) :
145
- $this->pref_lang );
146
-
147
- $dropdown = new PLL_Walker_Dropdown();
148
-
149
- wp_nonce_field( 'pll_language', '_pll_nonce' );
150
-
151
- // NOTE: the class "tags-input" allows to include the field in the autosave $_POST ( see autosave.js )
152
- printf( '
153
- <p><strong>%1$s</strong></p>
154
- <label class="screen-reader-text" for="%2$s">%1$s</label>
155
- <div id="select-%3$s-language">%4$s</div>',
156
- esc_html__( 'Language', 'polylang' ),
157
- $id = ( 'attachment' === $post_type ) ? sprintf( 'attachments[%d][language]', $post_ID ) : 'post_lang_choice',
158
- 'attachment' === $post_type ? 'media' : 'post',
159
- $dropdown->walk( $this->model->get_languages_list(), array(
160
- 'name' => $id,
161
- 'class' => 'post_lang_choice tags-input',
162
- 'selected' => $lang ? $lang->slug : '',
163
- 'flag' => true,
164
- ) )
165
- );
166
-
167
- /**
168
- * Fires before displaying the list of translations in the Languages metabox for posts
169
- *
170
- * @since 1.8
171
- */
172
- do_action( 'pll_before_post_translations', $post_type );
173
-
174
- echo '<div id="post-translations" class="translations">';
175
- if ( $lang ) {
176
- include PLL_ADMIN_INC . '/view-translations-' . ( 'attachment' == $post_type ? 'media' : 'post' ) . '.php';
177
- }
178
- echo '</div>' . "\n";
179
- }
180
-
181
- /**
182
- * Ajax response for changing the language in the post metabox
183
- *
184
- * @since 0.2
185
- */
186
- public function post_lang_choice() {
187
- check_ajax_referer( 'pll_language', '_pll_nonce' );
188
-
189
- global $post_ID; // Obliged to use the global variable for wp_popular_terms_checklist
190
- $post_id = $post_ID = (int) $_POST['post_id'];
191
- $lang = $this->model->get_language( $_POST['lang'] );
192
-
193
- $post_type = $_POST['post_type'];
194
- $post_type_object = get_post_type_object( $post_type );
195
- if ( ! current_user_can( $post_type_object->cap->edit_post, $post_ID ) ) {
196
- wp_die( -1 );
197
- }
198
-
199
- $this->model->post->set_language( $post_ID, $lang ); // Save language, useful to set the language when uploading media from post
200
-
201
- ob_start();
202
- if ( $lang ) {
203
- include PLL_ADMIN_INC . '/view-translations-' . ( 'attachment' == $post_type ? 'media' : 'post' ) . '.php';
204
- }
205
- $x = new WP_Ajax_Response( array( 'what' => 'translations', 'data' => ob_get_contents() ) );
206
- ob_end_clean();
207
-
208
- // Categories
209
- if ( isset( $_POST['taxonomies'] ) ) {
210
- // Not set for pages
211
- foreach ( $_POST['taxonomies'] as $taxname ) {
212
- $taxonomy = get_taxonomy( $taxname );
213
-
214
- ob_start();
215
- $popular_ids = wp_popular_terms_checklist( $taxonomy->name );
216
- $supplemental['populars'] = ob_get_contents();
217
- ob_end_clean();
218
-
219
- ob_start();
220
- // Use $post_ID to remember checked terms in case we come back to the original language
221
- wp_terms_checklist( $post_ID, array( 'taxonomy' => $taxonomy->name, 'popular_cats' => $popular_ids ) );
222
- $supplemental['all'] = ob_get_contents();
223
- ob_end_clean();
224
-
225
- $supplemental['dropdown'] = wp_dropdown_categories( array(
226
- 'taxonomy' => $taxonomy->name,
227
- 'hide_empty' => 0,
228
- 'name' => 'new' . $taxonomy->name . '_parent',
229
- 'orderby' => 'name',
230
- 'hierarchical' => 1,
231
- 'show_option_none' => '&mdash; ' . $taxonomy->labels->parent_item . ' &mdash;',
232
- 'echo' => 0,
233
- ) );
234
-
235
- $x->Add( array( 'what' => 'taxonomy', 'data' => $taxonomy->name, 'supplemental' => $supplemental ) );
236
- }
237
- }
238
-
239
- // Parent dropdown list ( only for hierarchical post types )
240
- if ( in_array( $post_type, get_post_types( array( 'hierarchical' => true ) ) ) ) {
241
- $post = get_post( $post_ID );
242
-
243
- // Args and filter from 'page_attributes_meta_box' in wp-admin/includes/meta-boxes.php of WP 4.2.1
244
- $dropdown_args = array(
245
- 'post_type' => $post->post_type,
246
- 'exclude_tree' => $post->ID,
247
- 'selected' => $post->post_parent,
248
- 'name' => 'parent_id',
249
- 'show_option_none' => __( '(no parent)' ),
250
- 'sort_column' => 'menu_order, post_title',
251
- 'echo' => 0,
252
- );
253
-
254
- /** This filter is documented in wp-admin/includes/meta-boxes.php */
255
- $dropdown_args = apply_filters( 'page_attributes_dropdown_pages_args', $dropdown_args, $post ); // Since WP 3.3
256
-
257
- $x->Add( array( 'what' => 'pages', 'data' => wp_dropdown_pages( $dropdown_args ) ) );
258
- }
259
-
260
- // Flag
261
- $x->Add( array( 'what' => 'flag', 'data' => empty( $lang->flag ) ? esc_html( $lang->slug ) : $lang->flag ) );
262
-
263
- // Sample permalink
264
- $x->Add( array( 'what' => 'permalink', 'data' => get_sample_permalink_html( $post_ID ) ) );
265
-
266
- $x->send();
267
- }
268
-
269
- /**
270
- * Ajax response for input in translation autocomplete input box
271
- *
272
- * @since 1.5
273
- */
274
- public function ajax_posts_not_translated() {
275
- check_ajax_referer( 'pll_language', '_pll_nonce' );
276
-
277
- if ( ! post_type_exists( $_GET['post_type'] ) ) {
278
- die( 0 );
279
- }
280
-
281
- $post_language = $this->model->get_language( $_GET['post_language'] );
282
- $translation_language = $this->model->get_language( $_GET['translation_language'] );
283
-
284
- // Don't order by title: see https://wordpress.org/support/topic/find-translated-post-when-10-is-not-enough
285
- $args = array(
286
- 's' => wp_unslash( $_GET['term'] ),
287
- 'suppress_filters' => 0, // To make the post_fields filter work
288
- 'lang' => 0, // Avoid admin language filter
289
- 'numberposts' => 20, // Limit to 20 posts
290
- 'post_status' => 'any',
291
- 'post_type' => $_GET['post_type'],
292
- 'tax_query' => array(
293
- array(
294
- 'taxonomy' => 'language',
295
- 'field' => 'term_taxonomy_id', // WP 3.5+
296
- 'terms' => $translation_language->term_taxonomy_id,
297
- ),
298
- ),
299
- );
300
-
301
- /**
302
- * Filter the query args when auto suggesting untranslated posts in the Languages metabox
303
- * This should help plugins to fix some edge cases
304
- *
305
- * @see https://wordpress.org/support/topic/find-translated-post-when-10-is-not-enough
306
- *
307
- * @since 1.7
308
- *
309
- * @param array $args WP_Query arguments
310
- */
311
- $args = apply_filters( 'pll_ajax_posts_not_translated_args', $args );
312
- $posts = get_posts( $args );
313
-
314
- $return = array();
315
-
316
- foreach ( $posts as $key => $post ) {
317
- if ( ! $this->model->post->get_translation( $post->ID, $post_language ) ) {
318
- $return[] = array(
319
- 'id' => $post->ID,
320
- 'value' => $post->post_title,
321
- 'link' => $this->links->edit_post_translation_link( $post->ID ),
322
- );
323
- }
324
- }
325
-
326
- // Add current translation in list
327
- if ( $post_id = $this->model->post->get_translation( (int) $_GET['pll_post_id'], $translation_language ) ) {
328
- $post = get_post( $post_id );
329
- array_unshift( $return, array(
330
- 'id' => $post_id,
331
- 'value' => $post->post_title,
332
- 'link' => $this->links->edit_post_translation_link( $post_id ),
333
- ) );
334
- }
335
-
336
- wp_die( json_encode( $return ) );
337
- }
338
-
339
  /**
340
  * Save language and translation when editing a post (post.php)
341
  *
@@ -427,166 +189,6 @@ class PLL_Admin_Filters_Post extends PLL_Admin_Filters_Post_Base {
427
  }
428
  }
429
 
430
- /**
431
- * Called when a post ( or page ) is saved, published or updated
432
- *
433
- * @since 0.1
434
- * @since 2.3 Does not save the language and translations anymore, unless the post has no language yet
435
- *
436
- * @param int $post_id
437
- * @param object $post
438
- * @param bool $update Whether it is an update or not
439
- */
440
- public function save_post( $post_id, $post, $update ) {
441
- // Does nothing except on post types which are filterable
442
- if ( $this->model->is_translated_post_type( $post->post_type ) ) {
443
- if ( $id = wp_is_post_revision( $post_id ) ) {
444
- $post_id = $id;
445
- }
446
-
447
- $lang = $this->model->post->get_language( $post_id );
448
-
449
- if ( empty( $lang ) ) {
450
- $this->set_default_language( $post_id );
451
- }
452
-
453
- /**
454
- * Fires after the post language and translations are saved
455
- *
456
- * @since 1.2
457
- *
458
- * @param int $post_id Post id
459
- * @param object $post Post object
460
- * @param array $translations The list of translations post ids
461
- */
462
- do_action( 'pll_save_post', $post_id, $post, $this->model->post->get_translations( $post_id ) );
463
- }
464
- }
465
-
466
- /**
467
- * Make sure saved terms are in the right language (especially tags with same name in different languages)
468
- *
469
- * @since 2.3
470
- *
471
- * @param int $object_id Object ID.
472
- * @param array $terms An array of object terms.
473
- * @param array $tt_ids An array of term taxonomy IDs.
474
- * @param string $taxonomy Taxonomy slug.
475
- */
476
- public function set_object_terms( $object_id, $terms, $tt_ids, $taxonomy ) {
477
- static $avoid_recursion;
478
-
479
- if ( ! $avoid_recursion && $this->model->is_translated_taxonomy( $taxonomy ) && ! empty( $terms ) ) {
480
- $lang = $this->model->post->get_language( $object_id );
481
-
482
- if ( ! empty( $lang ) && is_array( $terms ) ) {
483
- // Convert to term ids if we got tag names
484
- $strings = array_filter( $terms, 'is_string' );
485
- if ( ! empty( $strings ) ) {
486
- $_terms = get_terms( $taxonomy, array( 'name' => $strings, 'object_ids' => $object_id, 'fields' => 'ids' ) );
487
- $terms = array_merge( array_diff( $terms, $strings ), $_terms );
488
- }
489
-
490
- $term_ids = array_combine( $terms, $terms );
491
- $languages = array_map( array( $this->model->term, 'get_language' ), $term_ids );
492
- $languages = wp_list_pluck( $languages, 'slug' );
493
- $wrong_terms = array_diff( $languages, array( $lang->slug ) );
494
-
495
- if ( ! empty( $wrong_terms ) ) {
496
- // We got terms in a wrong language
497
- $wrong_term_ids = array_keys( $wrong_terms );
498
- $terms = get_the_terms( $object_id, $taxonomy );
499
- wp_remove_object_terms( $object_id, $wrong_term_ids, $taxonomy );
500
-
501
- if ( is_array( $terms ) ) {
502
- $newterms = array();
503
-
504
- foreach ( $terms as $term ) {
505
- if ( in_array( $term->term_id, $wrong_term_ids ) ) {
506
- // Check if the term is in the correct language or if a translation exist ( mainly for default category )
507
- if ( $newterm = $this->model->term->get( $term->term_id, $lang ) ) {
508
- $newterms[] = (int) $newterm;
509
- }
510
-
511
- // Or choose the correct language for tags ( initially defined by name )
512
- elseif ( $newterm = $this->model->term_exists( $term->name, $taxonomy, $term->parent, $lang ) ) {
513
- $newterms[] = (int) $newterm; // Cast is important otherwise we get 'numeric' tags
514
- }
515
-
516
- // Or create the term in the correct language
517
- elseif ( ! is_wp_error( $term_info = wp_insert_term( $term->name, $taxonomy ) ) ) {
518
- $newterms[] = (int) $term_info['term_id'];
519
- }
520
- }
521
- }
522
-
523
- $avoid_recursion = true;
524
- wp_set_object_terms( $object_id, array_unique( $newterms ), $taxonomy, true ); // Append
525
- $avoid_recursion = false;
526
- }
527
- }
528
- }
529
- }
530
- }
531
-
532
- /**
533
- * Make sure that the post parent is in the correct language when using bulk edit
534
- *
535
- * @since 1.8
536
- *
537
- * @param int $post_parent Post parent ID.
538
- * @param int $post_id Post ID.
539
- * @param array $new_postarr Array of parsed post data.
540
- * @param array $postarr Array of sanitized, but otherwise unmodified post data.
541
- * @return int
542
- */
543
- public function wp_insert_post_parent( $post_parent, $post_id, $new_postarr, $postarr ) {
544
- if ( isset( $postarr['bulk_edit'], $postarr['inline_lang_choice'] ) ) {
545
- check_admin_referer( 'bulk-posts' );
546
- $lang = -1 == $postarr['inline_lang_choice'] ?
547
- $this->model->post->get_language( $post_id ) :
548
- $this->model->get_language( $postarr['inline_lang_choice'] );
549
- // Dont break the hierarchy in case the post has no language
550
- if ( ! empty( $lang ) ) {
551
- $post_parent = $this->model->post->get_translation( $post_parent, $lang );
552
- }
553
- }
554
- return $post_parent;
555
- }
556
-
557
- /**
558
- * Called when a post, page or media is deleted
559
- * Don't delete translations if this is a post revision thanks to AndyDeGroo who catched this bug
560
- * http://wordpress.org/support/topic/plugin-polylang-quick-edit-still-breaks-translation-linking-of-pages-in-072
561
- *
562
- * @since 0.1
563
- *
564
- * @param int $post_id
565
- */
566
- public function delete_post( $post_id ) {
567
- if ( ! wp_is_post_revision( $post_id ) ) {
568
- $this->model->post->delete_translation( $post_id );
569
- }
570
- }
571
-
572
- /**
573
- * Filters the pages by language in the parent dropdown list in the page attributes metabox
574
- *
575
- * @since 0.6
576
- *
577
- * @param array $dropdown_args Arguments passed to wp_dropdown_pages
578
- * @param object $post
579
- * @return array Modified arguments
580
- */
581
- public function page_attributes_dropdown_pages_args( $dropdown_args, $post ) {
582
- $dropdown_args['lang'] = isset( $_POST['lang'] ) ? $this->model->get_language( $_POST['lang'] ) : $this->model->post->get_language( $post->ID ); // ajax or not ?
583
- if ( ! $dropdown_args['lang'] ) {
584
- $dropdown_args['lang'] = $this->pref_lang;
585
- }
586
-
587
- return $dropdown_args;
588
- }
589
-
590
  /**
591
  * Sets the language attribute and text direction for Tiny MCE
592
  *
6
  * @since 1.2
7
  */
8
  class PLL_Admin_Filters_Post extends PLL_Admin_Filters_Post_Base {
9
+ public $curlang;
10
 
11
  /**
12
  * Constructor: setups filters and actions
17
  */
18
  public function __construct( &$polylang ) {
19
  parent::__construct( $polylang );
 
20
  $this->curlang = &$polylang->curlang;
21
 
22
  add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
24
  // Filters posts, pages and media by language
25
  add_action( 'parse_query', array( $this, 'parse_query' ) );
26
 
 
 
 
 
 
 
 
27
  // Adds actions and filters related to languages when creating, saving or deleting posts and pages
28
  add_action( 'load-post.php', array( $this, 'edit_post' ) );
29
  add_action( 'load-edit.php', array( $this, 'bulk_edit_posts' ) );
30
  add_action( 'wp_ajax_inline-save', array( $this, 'inline_edit_post' ), 0 ); // Before WordPress
 
 
 
 
 
 
 
 
 
 
31
 
32
  // Sets the language in Tiny MCE
33
  add_filter( 'tiny_mce_before_init', array( $this, 'tiny_mce_before_init' ) );
98
  $pll_query->filter_query( $this->curlang );
99
  }
100
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
  /**
102
  * Save language and translation when editing a post (post.php)
103
  *
189
  }
190
  }
191
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
192
  /**
193
  * Sets the language attribute and text direction for Tiny MCE
194
  *
admin/admin-filters-term.php CHANGED
@@ -6,10 +6,9 @@
6
  * @since 1.2
7
  */
8
  class PLL_Admin_Filters_Term {
9
- public $links, $model, $options, $curlang, $filter_lang, $pref_lang;
10
  protected $pre_term_name; // Used to store the term name before creating a slug if needed
11
  protected $post_id; // Used to store the current post_id when bulk editing posts
12
- private $tax_query_lang;
13
 
14
  /**
15
  * Constructor: setups filters and actions
@@ -20,8 +19,6 @@ class PLL_Admin_Filters_Term {
20
  $this->links = &$polylang->links;
21
  $this->model = &$polylang->model;
22
  $this->options = &$polylang->options;
23
- $this->curlang = &$polylang->curlang;
24
- $this->filter_lang = &$polylang->filter_lang;
25
  $this->pref_lang = &$polylang->pref_lang;
26
 
27
  foreach ( $this->model->get_translated_taxonomies() as $tax ) {
@@ -30,15 +27,12 @@ class PLL_Admin_Filters_Term {
30
 
31
  // Adds the language field and translations tables in the 'Edit Category' and 'Edit Tag' panels
32
  add_action( $tax . '_edit_form_fields', array( $this, 'edit_term_form' ) );
33
-
34
- // Adds action related to languages when deleting categories and post tags
35
- add_action( 'pre_delete_term', array( $this, 'delete_term' ) );
36
  }
37
 
38
  // Adds actions related to languages when creating or saving categories and post tags
39
  add_filter( 'wp_dropdown_cats', array( $this, 'wp_dropdown_cats' ) );
40
- add_action( 'create_term', array( $this, 'save_term' ), 999, 3 );
41
- add_action( 'edit_term', array( $this, 'save_term' ), 999, 3 ); // late as it may conflict with other plugins, see http://wordpress.org/support/topic/polylang-and-wordpress-seo-by-yoast
42
  add_action( 'pre_post_update', array( $this, 'pre_post_update' ) );
43
  add_filter( 'pre_term_name', array( $this, 'pre_term_name' ) );
44
  add_filter( 'pre_term_slug', array( $this, 'pre_term_slug' ), 10, 2 );
@@ -47,14 +41,6 @@ class PLL_Admin_Filters_Term {
47
  add_action( 'wp_ajax_term_lang_choice', array( $this, 'term_lang_choice' ) );
48
  add_action( 'wp_ajax_pll_terms_not_translated', array( $this, 'ajax_terms_not_translated' ) );
49
 
50
- // Adds cache domain when querying terms
51
- add_filter( 'get_terms_args', array( $this, 'get_terms_args' ), 10, 2 );
52
-
53
- // Filters categories and post tags by language
54
- add_filter( 'terms_clauses', array( $this, 'terms_clauses' ), 10, 3 );
55
- add_action( 'pre_get_posts', array( $this, 'set_tax_query_lang' ), 999 );
56
- add_action( 'posts_selection', array( $this, 'unset_tax_query_lang' ), 0 );
57
-
58
  // Allows to get the default categories in all languages
59
  add_filter( 'option_default_category', array( $this, 'option_default_category' ) );
60
  add_action( 'update_option_default_category', array( $this, 'update_option_default_category' ), 10, 2 );
@@ -81,19 +67,22 @@ class PLL_Admin_Filters_Term {
81
 
82
  wp_nonce_field( 'pll_language', '_pll_nonce' );
83
 
84
- printf( '
85
- <div class="form-field">
86
  <label for="term_lang_choice">%s</label>
87
  <div id="select-add-term-language">%s</div>
88
  <p>%s</p>
89
  </div>',
90
  esc_html__( 'Language', 'polylang' ),
91
- $dropdown->walk( $this->model->get_languages_list(), array(
92
- 'name' => 'term_lang_choice',
93
- 'value' => 'term_id',
94
- 'selected' => $lang ? $lang->term_id : '',
95
- 'flag' => true,
96
- ) ),
 
 
 
97
  esc_html__( 'Sets the language', 'polylang' )
98
  );
99
 
@@ -134,8 +123,8 @@ class PLL_Admin_Filters_Term {
134
  // Disable the language dropdown and the translations input fields for default categories to prevent removal
135
  $disabled = in_array( get_option( 'default_category' ), $this->model->term->get_translations( $term_id ) );
136
 
137
- printf( '
138
- <tr class="form-field">
139
  <th scope="row">
140
  %s
141
  <label for="term_lang_choice">%s</label>
@@ -147,13 +136,16 @@ class PLL_Admin_Filters_Term {
147
  </tr>',
148
  wp_nonce_field( 'pll_language', '_pll_nonce', true, false ),
149
  esc_html__( 'Language', 'polylang' ),
150
- $dropdown->walk( $this->model->get_languages_list(), array(
151
- 'name' => 'term_lang_choice',
152
- 'value' => 'term_id',
153
- 'selected' => $lang ? $lang->term_id : '',
154
- 'disabled' => $disabled,
155
- 'flag' => true,
156
- ) ),
 
 
 
157
  esc_html__( 'Sets the language', 'polylang' )
158
  );
159
 
@@ -198,26 +190,6 @@ class PLL_Admin_Filters_Term {
198
  }
199
  }
200
 
201
- /**
202
- * Allows to set a language by default for terms if it has no language yet
203
- *
204
- * @since 1.5.4
205
- *
206
- * @param int $term_id
207
- * @param string $taxonomy
208
- */
209
- protected function set_default_language( $term_id, $taxonomy ) {
210
- if ( ! $this->model->term->get_language( $term_id ) ) {
211
- // Sets language from term parent if exists thanks to Scott Kingsley Clark
212
- if ( ( $term = get_term( $term_id, $taxonomy ) ) && ! empty( $term->parent ) && $parent_lang = $this->model->term->get_language( $term->parent ) ) {
213
- $this->model->term->set_language( $term_id, $parent_lang );
214
- }
215
- else {
216
- $this->model->term->set_language( $term_id, $this->pref_lang );
217
- }
218
- }
219
- }
220
-
221
  /**
222
  * Saves language
223
  *
@@ -259,12 +231,15 @@ class PLL_Admin_Filters_Term {
259
  // No WP function to get all terms with the exact same name so let's use a custom query
260
  // $terms = get_terms( $taxonomy, array( 'name' => $term->name, 'hide_empty' => false, 'fields' => 'ids' ) ); should be OK in 4.2
261
  // I may need to rework the loop below
262
- $terms = $wpdb->get_results( $wpdb->prepare( "
263
- SELECT t.term_id FROM $wpdb->terms AS t
264
- INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id
265
- WHERE tt.taxonomy = %s AND t.name = %s",
266
- $taxonomy, $term->name
267
- ) );
 
 
 
268
 
269
  // If we have several terms with the same name, they are translations of each other
270
  if ( count( $terms ) > 1 ) {
@@ -312,10 +287,6 @@ class PLL_Admin_Filters_Term {
312
  check_admin_referer( 'pll_language', '_pll_nonce' );
313
  $this->model->term->set_language( $term_id, $this->model->get_language( $_POST['post_lang_choice'] ) );
314
  }
315
-
316
- else {
317
- $this->set_default_language( $term_id, $taxonomy );
318
- }
319
  }
320
 
321
  /**
@@ -367,22 +338,6 @@ class PLL_Admin_Filters_Term {
367
  if ( isset( $_POST['term_tr_lang'] ) ) {
368
  $translations = $this->save_translations( $term_id );
369
  }
370
-
371
- /**
372
- * Fires after the term language and translations are saved
373
- *
374
- * @since 1.2
375
- *
376
- * @param int $term_id term id
377
- * @param string $taxonomy taxonomy name
378
- * @param array $translations the list of translations term ids
379
- */
380
- do_action( 'pll_save_term', $term_id, $taxonomy, empty( $translations ) ? $this->model->term->get_translations( $term_id ) : $translations );
381
- }
382
-
383
- // Attempts to set a default language even if no capability
384
- else {
385
- $this->set_default_language( $term_id, $taxonomy );
386
  }
387
  }
388
 
@@ -434,19 +389,6 @@ class PLL_Admin_Filters_Term {
434
  return $slug;
435
  }
436
 
437
- /**
438
- * Called when a category or post tag is deleted
439
- * Deletes language and translations
440
- *
441
- * @since 0.1
442
- *
443
- * @param int $term_id
444
- */
445
- public function delete_term( $term_id ) {
446
- $this->model->term->delete_translation( $term_id );
447
- $this->model->term->delete_language( $term_id );
448
- }
449
-
450
  /**
451
  * Ajax response for edit term form
452
  *
@@ -475,14 +417,14 @@ class PLL_Admin_Filters_Term {
475
  // $args copied from edit_tags.php except echo
476
  if ( is_taxonomy_hierarchical( $taxonomy ) ) {
477
  $args = array(
478
- 'hide_empty' => 0,
479
- 'hide_if_empty' => false,
480
- 'taxonomy' => $taxonomy,
481
- 'name' => 'parent',
482
- 'orderby' => 'name',
483
- 'hierarchical' => true,
484
  'show_option_none' => __( 'None' ),
485
- 'echo' => 0,
486
  );
487
  $x->Add( array( 'what' => 'parent', 'data' => wp_dropdown_categories( $args ) ) );
488
  }
@@ -537,9 +479,9 @@ class PLL_Admin_Filters_Term {
537
 
538
  if ( $lang && $lang->slug == $translation_language->slug && ! $this->model->term->get_translation( $term->term_id, $term_language ) ) {
539
  $return[] = array(
540
- 'id' => $term->term_id,
541
  'value' => $term->name,
542
- 'link' => $this->links->edit_term_translation_link( $term->term_id, $taxonomy, $post_type ),
543
  );
544
  }
545
  }
@@ -548,113 +490,21 @@ class PLL_Admin_Filters_Term {
548
  // Not in add term for as term_id is not set
549
  if ( 'undefined' !== $_GET['term_id'] && $term_id = $this->model->term->get_translation( (int) $_GET['term_id'], $translation_language ) ) {
550
  $term = get_term( $term_id, $taxonomy );
551
- array_unshift( $return, array(
552
- 'id' => $term_id,
553
- 'value' => $term->name,
554
- 'link' => $this->links->edit_term_translation_link( $term->term_id, $taxonomy, $post_type ),
555
- ) );
 
 
 
556
  }
557
 
558
  wp_die( json_encode( $return ) );
559
  }
560
 
561
  /**
562
- * Get the language(s) to filter get_terms
563
- *
564
- * @since 1.7.6
565
- *
566
- * @param array $taxonomies queried taxonomies
567
- * @param array $args get_terms arguments
568
- * @return object|string|bool the language(s) to use in the filter, false otherwise
569
- */
570
- protected function get_queried_language( $taxonomies, $args ) {
571
- // Does nothing except on taxonomies which are filterable
572
- // Since WP 4.7, make sure not to filter wp_get_object_terms()
573
- if ( ! $this->model->is_translated_taxonomy( $taxonomies ) || ! empty( $args['object_ids'] ) ) {
574
- return false;
575
- }
576
-
577
- if ( isset( $this->tax_query_lang ) ) {
578
- $args['lang'] = $this->tax_query_lang;
579
- }
580
-
581
- // If get_terms is queried with a 'lang' parameter
582
- if ( isset( $args['lang'] ) ) {
583
- return $args['lang'];
584
- }
585
-
586
- // On tags page, everything should be filtered according to the admin language filter except the parent dropdown
587
- if ( 'edit-tags.php' === $GLOBALS['pagenow'] && empty( $args['class'] ) ) {
588
- return $this->filter_lang;
589
- }
590
-
591
- return $this->curlang;
592
- }
593
-
594
- /**
595
- * Adds language dependent cache domain when querying terms
596
- * Useful as the 'lang' parameter is not included in cache key by WordPress
597
- *
598
- * @since 1.3
599
- *
600
- * @param array $args
601
- * @param array $taxonomies
602
- * @return array modified arguments
603
- */
604
- public function get_terms_args( $args, $taxonomies ) {
605
- // don't break _get_term_hierarchy()
606
- if ( 'all' === $args['get'] && 'id' === $args['orderby'] && 'id=>parent' === $args['fields'] ) {
607
- $args['lang'] = '';
608
- }
609
-
610
- if ( $lang = $this->get_queried_language( $taxonomies, $args ) ) {
611
- $lang = is_string( $lang ) && strpos( $lang, ',' ) ? explode( ',', $lang ) : $lang;
612
- $key = '_' . ( is_array( $lang ) ? implode( ',', $lang ) : $this->model->get_language( $lang )->slug );
613
- $args['cache_domain'] = empty( $args['cache_domain'] ) ? 'pll' . $key : $args['cache_domain'] . $key;
614
- }
615
- return $args;
616
- }
617
-
618
- /**
619
- * Filters categories and post tags by language(s) when needed on admin side
620
- *
621
- * @since 0.5
622
- *
623
- * @param array $clauses list of sql clauses
624
- * @param array $taxonomies list of taxonomies
625
- * @param array $args get_terms arguments
626
- * @return array modified sql clauses
627
- */
628
- public function terms_clauses( $clauses, $taxonomies, $args ) {
629
- $lang = $this->get_queried_language( $taxonomies, $args );
630
- return ! empty( $lang ) ? $this->model->terms_clauses( $clauses, $lang ) : $clauses; // adds our clauses to filter by current language
631
- }
632
-
633
- /**
634
- * Sets the WP_Term_Query language when doing a WP_Query
635
- * Needed since WP 4.9
636
- *
637
- * @since 2.3.2
638
- *
639
- * @param object $query WP_Query object
640
- */
641
- public function set_tax_query_lang( $query ) {
642
- $this->tax_query_lang = isset( $query->query_vars['lang'] ) ? $query->query_vars['lang'] : '';
643
- }
644
-
645
- /**
646
- * Removes the WP_Term_Query language filter for WP_Query
647
- * Needed since WP 4.9
648
- *
649
- * @since 2.3.2
650
- */
651
- public function unset_tax_query_lang() {
652
- unset( $this->tax_query_lang );
653
- }
654
-
655
- /**
656
- * Hack to avoid displaying delete link for the default category in all languages
657
- * Also returns the default category in the right language when called from wp_delete_term
658
  *
659
  * @since 1.2
660
  *
@@ -662,28 +512,9 @@ class PLL_Admin_Filters_Term {
662
  * @return int
663
  */
664
  public function option_default_category( $value ) {
665
- // Filters the default category in note below the category list table and in settings->writing dropdown
666
  if ( isset( $this->pref_lang ) && $tr = $this->model->term->get( $value, $this->pref_lang ) ) {
667
  $value = $tr;
668
  }
669
-
670
- // FIXME backward compatibility with WP < 4.7
671
- if ( version_compare( $GLOBALS['wp_version'], '4.7alpha', '<' ) ) {
672
- $traces = debug_backtrace();
673
- $n = version_compare( PHP_VERSION, '7', '>=' ) ? 3 : 4; // PHP 7 does not include call_user_func_array
674
-
675
- if ( isset( $traces[ $n ] ) ) {
676
- // FIXME 'column_name' for backward compatibility with WP < 4.3
677
- if ( in_array( $traces[ $n ]['function'], array( 'column_cb', 'column_name', 'handle_row_actions' ) ) && in_array( $traces[ $n ]['args'][0]->term_id, $this->model->term->get_translations( $value ) ) ) {
678
- return $traces[ $n ]['args'][0]->term_id;
679
- }
680
-
681
- if ( 'wp_delete_term' == $traces[ $n ]['function'] ) {
682
- return $this->model->term->get( $value, $this->model->term->get_language( $traces[ $n ]['args'][0] ) );
683
- }
684
- }
685
- }
686
-
687
  return $value;
688
  }
689
 
6
  * @since 1.2
7
  */
8
  class PLL_Admin_Filters_Term {
9
+ public $links, $model, $options, $pref_lang;
10
  protected $pre_term_name; // Used to store the term name before creating a slug if needed
11
  protected $post_id; // Used to store the current post_id when bulk editing posts
 
12
 
13
  /**
14
  * Constructor: setups filters and actions
19
  $this->links = &$polylang->links;
20
  $this->model = &$polylang->model;
21
  $this->options = &$polylang->options;
 
 
22
  $this->pref_lang = &$polylang->pref_lang;
23
 
24
  foreach ( $this->model->get_translated_taxonomies() as $tax ) {
27
 
28
  // Adds the language field and translations tables in the 'Edit Category' and 'Edit Tag' panels
29
  add_action( $tax . '_edit_form_fields', array( $this, 'edit_term_form' ) );
 
 
 
30
  }
31
 
32
  // Adds actions related to languages when creating or saving categories and post tags
33
  add_filter( 'wp_dropdown_cats', array( $this, 'wp_dropdown_cats' ) );
34
+ add_action( 'create_term', array( $this, 'save_term' ), 900, 3 );
35
+ add_action( 'edit_term', array( $this, 'save_term' ), 900, 3 ); // Late as it may conflict with other plugins, see http://wordpress.org/support/topic/polylang-and-wordpress-seo-by-yoast
36
  add_action( 'pre_post_update', array( $this, 'pre_post_update' ) );
37
  add_filter( 'pre_term_name', array( $this, 'pre_term_name' ) );
38
  add_filter( 'pre_term_slug', array( $this, 'pre_term_slug' ), 10, 2 );
41
  add_action( 'wp_ajax_term_lang_choice', array( $this, 'term_lang_choice' ) );
42
  add_action( 'wp_ajax_pll_terms_not_translated', array( $this, 'ajax_terms_not_translated' ) );
43
 
 
 
 
 
 
 
 
 
44
  // Allows to get the default categories in all languages
45
  add_filter( 'option_default_category', array( $this, 'option_default_category' ) );
46
  add_action( 'update_option_default_category', array( $this, 'update_option_default_category' ), 10, 2 );
67
 
68
  wp_nonce_field( 'pll_language', '_pll_nonce' );
69
 
70
+ printf(
71
+ '<div class="form-field">
72
  <label for="term_lang_choice">%s</label>
73
  <div id="select-add-term-language">%s</div>
74
  <p>%s</p>
75
  </div>',
76
  esc_html__( 'Language', 'polylang' ),
77
+ $dropdown->walk(
78
+ $this->model->get_languages_list(),
79
+ array(
80
+ 'name' => 'term_lang_choice',
81
+ 'value' => 'term_id',
82
+ 'selected' => $lang ? $lang->term_id : '',
83
+ 'flag' => true,
84
+ )
85
+ ),
86
  esc_html__( 'Sets the language', 'polylang' )
87
  );
88
 
123
  // Disable the language dropdown and the translations input fields for default categories to prevent removal
124
  $disabled = in_array( get_option( 'default_category' ), $this->model->term->get_translations( $term_id ) );
125
 
126
+ printf(
127
+ '<tr class="form-field">
128
  <th scope="row">
129
  %s
130
  <label for="term_lang_choice">%s</label>
136
  </tr>',
137
  wp_nonce_field( 'pll_language', '_pll_nonce', true, false ),
138
  esc_html__( 'Language', 'polylang' ),
139
+ $dropdown->walk(
140
+ $this->model->get_languages_list(),
141
+ array(
142
+ 'name' => 'term_lang_choice',
143
+ 'value' => 'term_id',
144
+ 'selected' => $lang ? $lang->term_id : '',
145
+ 'disabled' => $disabled,
146
+ 'flag' => true,
147
+ )
148
+ ),
149
  esc_html__( 'Sets the language', 'polylang' )
150
  );
151
 
190
  }
191
  }
192
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
193
  /**
194
  * Saves language
195
  *
231
  // No WP function to get all terms with the exact same name so let's use a custom query
232
  // $terms = get_terms( $taxonomy, array( 'name' => $term->name, 'hide_empty' => false, 'fields' => 'ids' ) ); should be OK in 4.2
233
  // I may need to rework the loop below
234
+ $terms = $wpdb->get_results(
235
+ $wpdb->prepare(
236
+ "SELECT t.term_id FROM $wpdb->terms AS t
237
+ INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id
238
+ WHERE tt.taxonomy = %s AND t.name = %s",
239
+ $taxonomy,
240
+ $term->name
241
+ )
242
+ );
243
 
244
  // If we have several terms with the same name, they are translations of each other
245
  if ( count( $terms ) > 1 ) {
287
  check_admin_referer( 'pll_language', '_pll_nonce' );
288
  $this->model->term->set_language( $term_id, $this->model->get_language( $_POST['post_lang_choice'] ) );
289
  }
 
 
 
 
290
  }
291
 
292
  /**
338
  if ( isset( $_POST['term_tr_lang'] ) ) {
339
  $translations = $this->save_translations( $term_id );
340
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
341
  }
342
  }
343
 
389
  return $slug;
390
  }
391
 
 
 
 
 
 
 
 
 
 
 
 
 
 
392
  /**
393
  * Ajax response for edit term form
394
  *
417
  // $args copied from edit_tags.php except echo
418
  if ( is_taxonomy_hierarchical( $taxonomy ) ) {
419
  $args = array(
420
+ 'hide_empty' => 0,
421
+ 'hide_if_empty' => false,
422
+ 'taxonomy' => $taxonomy,
423
+ 'name' => 'parent',
424
+ 'orderby' => 'name',
425
+ 'hierarchical' => true,
426
  'show_option_none' => __( 'None' ),
427
+ 'echo' => 0,
428
  );
429
  $x->Add( array( 'what' => 'parent', 'data' => wp_dropdown_categories( $args ) ) );
430
  }
479
 
480
  if ( $lang && $lang->slug == $translation_language->slug && ! $this->model->term->get_translation( $term->term_id, $term_language ) ) {
481
  $return[] = array(
482
+ 'id' => $term->term_id,
483
  'value' => $term->name,
484
+ 'link' => $this->links->edit_term_translation_link( $term->term_id, $taxonomy, $post_type ),
485
  );
486
  }
487
  }
490
  // Not in add term for as term_id is not set
491
  if ( 'undefined' !== $_GET['term_id'] && $term_id = $this->model->term->get_translation( (int) $_GET['term_id'], $translation_language ) ) {
492
  $term = get_term( $term_id, $taxonomy );
493
+ array_unshift(
494
+ $return,
495
+ array(
496
+ 'id' => $term_id,
497
+ 'value' => $term->name,
498
+ 'link' => $this->links->edit_term_translation_link( $term->term_id, $taxonomy, $post_type ),
499
+ )
500
+ );
501
  }
502
 
503
  wp_die( json_encode( $return ) );
504
  }
505
 
506
  /**
507
+ * Filters the default category in note below the category list table and in settings->writing dropdown
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
508
  *
509
  * @since 1.2
510
  *
512
  * @return int
513
  */
514
  public function option_default_category( $value ) {
 
515
  if ( isset( $this->pref_lang ) && $tr = $this->model->term->get( $value, $this->pref_lang ) ) {
516
  $value = $tr;
517
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
518
  return $value;
519
  }
520
 
admin/admin-filters.php CHANGED
@@ -60,7 +60,8 @@ class PLL_Admin_Filters extends PLL_Filters {
60
  // Saving the widget reloads the form. And curiously the action is in $_REQUEST but neither in $_POST, not in $_GET.
61
  if ( ( isset( $screen ) && 'widgets' === $screen->base ) || ( isset( $_REQUEST['action'] ) && 'save-widget' === $_REQUEST['action'] ) || isset( $GLOBALS['wp_customize'] ) ) {
62
  $dropdown = new PLL_Walker_Dropdown();
63
- printf( '<p><label for="%1$s">%2$s %3$s</label></p>',
 
64
  esc_attr( $widget->id . '_lang_choice' ),
65
  esc_html__( 'The widget is displayed for:', 'polylang' ),
66
  $dropdown->walk(
@@ -69,9 +70,9 @@ class PLL_Admin_Filters extends PLL_Filters {
69
  $this->model->get_languages_list()
70
  ),
71
  array(
72
- 'name' => $widget->id . '_lang_choice',
73
- 'class' => 'tags-input',
74
- 'selected' => empty( $instance['pll_lang'] ) ? '' : $instance['pll_lang'],
75
  )
76
  )
77
  );
@@ -108,13 +109,6 @@ class PLL_Admin_Filters extends PLL_Filters {
108
  * @param int $user_id
109
  */
110
  public function personal_options_update( $user_id ) {
111
- // Admin language
112
- // FIXME Backward compatibility with WP < 4.7
113
- if ( version_compare( $GLOBALS['wp_version'], '4.7alpha', '<' ) ) {
114
- $user_lang = in_array( $_POST['user_lang'], $this->model->get_languages_list( array( 'fields' => 'locale' ) ) ) ? $_POST['user_lang'] : 0;
115
- update_user_meta( $user_id, 'locale', $user_lang );
116
- }
117
-
118
  // Biography translations
119
  foreach ( $this->model->get_languages_list() as $lang ) {
120
  $meta = $lang->slug == $this->options['default_lang'] ? 'description' : 'description_' . $lang->slug;
@@ -127,44 +121,21 @@ class PLL_Admin_Filters extends PLL_Filters {
127
  }
128
 
129
  /**
130
- * Form for language user preference in user profile
131
  *
132
  * @since 0.4
133
  *
134
  * @param object $profileuser
135
  */
136
  public function personal_options( $profileuser ) {
137
- // FIXME: Backward compatibility with WP < 4.7
138
- if ( version_compare( $GLOBALS['wp_version'], '4.7alpha', '<' ) ) {
139
- $dropdown = new PLL_Walker_Dropdown();
140
- printf( '
141
- <tr>
142
- <th><label for="user_lang">%s</label></th>
143
- <td>%s</td>
144
- </tr>',
145
- esc_html__( 'Admin language', 'polylang' ),
146
- $dropdown->walk(
147
- array_merge(
148
- array( (object) array( 'locale' => 0, 'name' => __( 'WordPress default', 'polylang' ) ) ),
149
- $this->model->get_languages_list()
150
- ),
151
- array(
152
- 'name' => 'user_lang',
153
- 'value' => 'locale',
154
- 'selected' => get_user_meta( $profileuser->ID, 'locale', true ),
155
- )
156
- )
157
- );
158
- }
159
-
160
- // Hidden information to modify the biography form with js
161
  foreach ( $this->model->get_languages_list() as $lang ) {
162
  $meta = $lang->slug == $this->options['default_lang'] ? 'description' : 'description_' . $lang->slug;
163
 
164
  /** This filter is documented in wp-includes/user.php */
165
  $description = apply_filters( 'user_description', get_user_meta( $profileuser->ID, $meta, true ) ); // Applies WP default filter wp_kses_data
166
 
167
- printf( '<input type="hidden" class="biography" name="%s___%s" value="%s" />',
 
168
  esc_attr( $lang->slug ),
169
  esc_attr( $lang->name ),
170
  esc_attr( $description )
@@ -198,7 +169,7 @@ class PLL_Admin_Filters extends PLL_Filters {
198
  * @param array $locales Not used
199
  * @return array list of locales to update
200
  */
201
- function update_check_locales( $locales ) {
202
  return $this->model->get_languages_list( array( 'fields' => 'locale' ) );
203
  }
204
 
60
  // Saving the widget reloads the form. And curiously the action is in $_REQUEST but neither in $_POST, not in $_GET.
61
  if ( ( isset( $screen ) && 'widgets' === $screen->base ) || ( isset( $_REQUEST['action'] ) && 'save-widget' === $_REQUEST['action'] ) || isset( $GLOBALS['wp_customize'] ) ) {
62
  $dropdown = new PLL_Walker_Dropdown();
63
+ printf(
64
+ '<p><label for="%1$s">%2$s %3$s</label></p>',
65
  esc_attr( $widget->id . '_lang_choice' ),
66
  esc_html__( 'The widget is displayed for:', 'polylang' ),
67
  $dropdown->walk(
70
  $this->model->get_languages_list()
71
  ),
72
  array(
73
+ 'name' => $widget->id . '_lang_choice',
74
+ 'class' => 'tags-input pll-lang-choice',
75
+ 'selected' => empty( $instance['pll_lang'] ) ? '' : $instance['pll_lang'],
76
  )
77
  )
78
  );
109
  * @param int $user_id
110
  */
111
  public function personal_options_update( $user_id ) {
 
 
 
 
 
 
 
112
  // Biography translations
113
  foreach ( $this->model->get_languages_list() as $lang ) {
114
  $meta = $lang->slug == $this->options['default_lang'] ? 'description' : 'description_' . $lang->slug;
121
  }
122
 
123
  /**
124
+ * Outputs hidden information to modify the biography form with js
125
  *
126
  * @since 0.4
127
  *
128
  * @param object $profileuser
129
  */
130
  public function personal_options( $profileuser ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131
  foreach ( $this->model->get_languages_list() as $lang ) {
132
  $meta = $lang->slug == $this->options['default_lang'] ? 'description' : 'description_' . $lang->slug;
133
 
134
  /** This filter is documented in wp-includes/user.php */
135
  $description = apply_filters( 'user_description', get_user_meta( $profileuser->ID, $meta, true ) ); // Applies WP default filter wp_kses_data
136
 
137
+ printf(
138
+ '<input type="hidden" class="biography" name="%s___%s" value="%s" />',
139
  esc_attr( $lang->slug ),
140
  esc_attr( $lang->name ),
141
  esc_attr( $description )
169
  * @param array $locales Not used
170
  * @return array list of locales to update
171
  */
172
+ public function update_check_locales( $locales ) {
173
  return $this->model->get_languages_list( array( 'fields' => 'locale' ) );
174
  }
175
 
admin/admin-model.php CHANGED
@@ -318,8 +318,8 @@ class PLL_Admin_Model extends PLL_Model {
318
  }
319
 
320
  if ( ! empty( $values ) ) {
321
- $values = array_unique( $values );
322
- $wpdb->query( "INSERT INTO $wpdb->term_relationships ( object_id, term_taxonomy_id ) VALUES " . implode( ',', $values ) );
323
  $lang->update_count(); // Updating term count is mandatory ( thanks to AndyDeGroo )
324
  }
325
 
@@ -361,12 +361,13 @@ class PLL_Admin_Model extends PLL_Model {
361
 
362
  // Insert terms
363
  if ( ! empty( $terms ) ) {
364
- $terms = array_unique( $terms );
365
- $wpdb->query( "INSERT INTO $wpdb->terms ( slug, name ) VALUES " . implode( ',', $terms ) );
366
  }
367
 
368
  // Get all terms with their term_id
369
- $terms = $wpdb->get_results( "SELECT term_id, slug FROM $wpdb->terms WHERE slug IN ( " . implode( ',', $slugs ) . ' )' );
 
370
 
371
  // Prepare terms taxonomy relationship
372
  foreach ( $terms as $term ) {
@@ -376,8 +377,8 @@ class PLL_Admin_Model extends PLL_Model {
376
 
377
  // Insert term_taxonomy
378
  if ( ! empty( $tts ) ) {
379
- $tts = array_unique( $tts );
380
- $wpdb->query( "INSERT INTO $wpdb->term_taxonomy ( term_id, taxonomy, description, count ) VALUES " . implode( ',', $tts ) );
381
  }
382
 
383
  // Get all terms with term_taxonomy_id
@@ -397,7 +398,8 @@ class PLL_Admin_Model extends PLL_Model {
397
 
398
  // Insert term_relationships
399
  if ( ! empty( $trs ) ) {
400
- $wpdb->query( "INSERT INTO $wpdb->term_relationships ( object_id, term_taxonomy_id ) VALUES " . implode( ',', $trs ) );
 
401
  $trs = array_unique( $trs );
402
  }
403
 
@@ -427,32 +429,38 @@ class PLL_Admin_Model extends PLL_Model {
427
  */
428
  $limit = (int) apply_filters( 'get_objects_with_no_lang_limit', $limit );
429
 
430
- $posts = get_posts( array(
431
- 'numberposts' => $limit,
432
- 'nopaging' => $limit <= 0,
433
- 'post_type' => $this->get_translated_post_types(),
434
- 'post_status' => 'any',
435
- 'fields' => 'ids',
436
- 'tax_query' => array(
437
- array(
438
- 'taxonomy' => 'language',
439
- 'terms' => $this->get_languages_list( array( 'fields' => 'term_id' ) ),
440
- 'operator' => 'NOT IN',
 
 
441
  ),
442
- ),
443
- ) );
444
-
445
- $terms = $wpdb->get_col( sprintf( "
446
- SELECT {$wpdb->term_taxonomy}.term_id FROM {$wpdb->term_taxonomy}
447
- WHERE taxonomy IN ('%s')
448
- AND {$wpdb->term_taxonomy}.term_id NOT IN (
449
- SELECT object_id FROM {$wpdb->term_relationships} WHERE term_taxonomy_id IN (%s)
450
  )
451
- %s",
452
- implode( "','", array_map( 'esc_sql', $this->get_translated_taxonomies() ) ),
453
- implode( ',', array_map( 'intval', $this->get_languages_list( array( 'fields' => 'tl_term_taxonomy_id' ) ) ) ),
454
- $limit > 0 ? "LIMIT {$limit}" : ''
455
- ) );
 
 
 
 
 
 
 
 
 
 
 
 
456
 
457
  /**
458
  * Filter the list of untranslated posts ids and terms ids
@@ -501,26 +509,30 @@ class PLL_Admin_Model extends PLL_Model {
501
 
502
  // Delete relationships
503
  if ( ! empty( $dr ) ) {
504
- $wpdb->query( "
505
- DELETE FROM $wpdb->term_relationships
 
506
  WHERE object_id IN ( " . implode( ',', $dr['id'] ) . ' )
507
- AND term_taxonomy_id IN ( ' . implode( ',', $dr['tt'] ) . ' )
508
- ' );
 
509
  }
510
 
511
  // Delete terms
512
  if ( ! empty( $dt ) ) {
513
- $wpdb->query( "DELETE FROM $wpdb->terms WHERE term_id IN ( " . implode( ',', $dt['t'] ) . ' )' );
514
- $wpdb->query( "DELETE FROM $wpdb->term_taxonomy WHERE term_taxonomy_id IN ( " . implode( ',', $dt['tt'] ) . ' )' );
515
  }
516
 
517
  // Update terms
518
  if ( ! empty( $ut ) ) {
519
- $wpdb->query( "
520
- UPDATE $wpdb->term_taxonomy
 
521
  SET description = ( CASE term_id " . implode( ' ', $ut['case'] ) . ' END )
522
- WHERE term_id IN ( ' . implode( ',', $ut['in'] ) . ' )
523
- ' );
 
524
  }
525
 
526
  if ( ! empty( $term_ids ) ) {
318
  }
319
 
320
  if ( ! empty( $values ) ) {
321
+ // PHPCS:ignore WordPress.DB.PreparedSQL.NotPrepared
322
+ $wpdb->query( "INSERT INTO {$wpdb->term_relationships} ( object_id, term_taxonomy_id ) VALUES " . implode( ',', array_unique( $values ) ) );
323
  $lang->update_count(); // Updating term count is mandatory ( thanks to AndyDeGroo )
324
  }
325
 
361
 
362
  // Insert terms
363
  if ( ! empty( $terms ) ) {
364
+ // PHPCS:ignore WordPress.DB.PreparedSQL.NotPrepared
365
+ $wpdb->query( "INSERT INTO {$wpdb->terms} ( slug, name ) VALUES " . implode( ',', array_unique( $terms ) ) );
366
  }
367
 
368
  // Get all terms with their term_id
369
+ // PHPCS:ignore WordPress.DB.PreparedSQL.NotPrepared
370
+ $terms = $wpdb->get_results( "SELECT term_id, slug FROM {$wpdb->terms} WHERE slug IN ( " . implode( ',', $slugs ) . ' )' );
371
 
372
  // Prepare terms taxonomy relationship
373
  foreach ( $terms as $term ) {
377
 
378
  // Insert term_taxonomy
379
  if ( ! empty( $tts ) ) {
380
+ // PHPCS:ignore WordPress.DB.PreparedSQL.NotPrepared
381
+ $wpdb->query( "INSERT INTO {$wpdb->term_taxonomy} ( term_id, taxonomy, description, count ) VALUES " . implode( ',', array_unique( $tts ) ) );
382
  }
383
 
384
  // Get all terms with term_taxonomy_id
398
 
399
  // Insert term_relationships
400
  if ( ! empty( $trs ) ) {
401
+ // PHPCS:ignore WordPress.DB.PreparedSQL.NotPrepared
402
+ $wpdb->query( "INSERT INTO {$wpdb->term_relationships} ( object_id, term_taxonomy_id ) VALUES " . implode( ',', $trs ) );
403
  $trs = array_unique( $trs );
404
  }
405
 
429
  */
430
  $limit = (int) apply_filters( 'get_objects_with_no_lang_limit', $limit );
431
 
432
+ $posts = get_posts(
433
+ array(
434
+ 'numberposts' => $limit,
435
+ 'nopaging' => $limit <= 0,
436
+ 'post_type' => $this->get_translated_post_types(),
437
+ 'post_status' => 'any',
438
+ 'fields' => 'ids',
439
+ 'tax_query' => array(
440
+ array(
441
+ 'taxonomy' => 'language',
442
+ 'terms' => $this->get_languages_list( array( 'fields' => 'term_id' ) ),
443
+ 'operator' => 'NOT IN',
444
+ ),
445
  ),
 
 
 
 
 
 
 
 
446
  )
447
+ );
448
+
449
+ // PHPCS:disable WordPress.DB.PreparedSQL.NotPrepared
450
+ $terms = $wpdb->get_col(
451
+ sprintf(
452
+ "SELECT {$wpdb->term_taxonomy}.term_id FROM {$wpdb->term_taxonomy}
453
+ WHERE taxonomy IN ('%s')
454
+ AND {$wpdb->term_taxonomy}.term_id NOT IN (
455
+ SELECT object_id FROM {$wpdb->term_relationships} WHERE term_taxonomy_id IN (%s)
456
+ )
457
+ %s",
458
+ implode( "','", array_map( 'esc_sql', $this->get_translated_taxonomies() ) ),
459
+ implode( ',', array_map( 'intval', $this->get_languages_list( array( 'fields' => 'tl_term_taxonomy_id' ) ) ) ),
460
+ $limit > 0 ? "LIMIT {$limit}" : ''
461
+ )
462
+ );
463
+ // PHPCS:enable
464
 
465
  /**
466
  * Filter the list of untranslated posts ids and terms ids
509
 
510
  // Delete relationships
511
  if ( ! empty( $dr ) ) {
512
+ // PHPCS:disable WordPress.DB.PreparedSQL.NotPrepared
513
+ $wpdb->query(
514
+ "DELETE FROM $wpdb->term_relationships
515
  WHERE object_id IN ( " . implode( ',', $dr['id'] ) . ' )
516
+ AND term_taxonomy_id IN ( ' . implode( ',', $dr['tt'] ) . ' )'
517
+ );
518
+ // PHPCS:enable
519
  }
520
 
521
  // Delete terms
522
  if ( ! empty( $dt ) ) {
523
+ $wpdb->query( "DELETE FROM $wpdb->terms WHERE term_id IN ( " . implode( ',', $dt['t'] ) . ' )' ); // PHPCS:ignore WordPress.DB.PreparedSQL.NotPrepared
524
+ $wpdb->query( "DELETE FROM $wpdb->term_taxonomy WHERE term_taxonomy_id IN ( " . implode( ',', $dt['tt'] ) . ' )' ); // PHPCS:ignore WordPress.DB.PreparedSQL.NotPrepared
525
  }
526
 
527
  // Update terms
528
  if ( ! empty( $ut ) ) {
529
+ // PHPCS:disable WordPress.DB.PreparedSQL.NotPrepared
530
+ $wpdb->query(
531
+ "UPDATE $wpdb->term_taxonomy
532
  SET description = ( CASE term_id " . implode( ' ', $ut['case'] ) . ' END )
533
+ WHERE term_id IN ( ' . implode( ',', $ut['in'] ) . ' )'
534
+ );
535
+ // PHPCS:enable
536
  }
537
 
538
  if ( ! empty( $term_ids ) ) {
admin/admin-nav-menu.php CHANGED
@@ -104,13 +104,15 @@ class PLL_Admin_Nav_Menu extends PLL_Nav_Menu {
104
  $data['title'] = __( 'Language switcher', 'polylang' ); // The title
105
 
106
  // Get all language switcher menu items
107
- $items = get_posts( array(
108
- 'numberposts' => -1,
109
- 'nopaging' => true,
110
- 'post_type' => 'nav_menu_item',
111
- 'fields' => 'ids',
112
- 'meta_key' => '_pll_menu_item',
113
- ) );
 
 
114
 
115
  // The options values for the language switcher
116
  $data['val'] = array();
@@ -272,7 +274,7 @@ class PLL_Admin_Nav_Menu extends PLL_Nav_Menu {
272
  *
273
  * @param int $term_id nav menu id
274
  */
275
- function delete_nav_menu( $term_id ) {
276
  if ( isset( $this->options['nav_menus'] ) ) {
277
  foreach ( $this->options['nav_menus'] as $theme => $locations ) {
278
  foreach ( $locations as $loc => $languages ) {
104
  $data['title'] = __( 'Language switcher', 'polylang' ); // The title
105
 
106
  // Get all language switcher menu items
107
+ $items = get_posts(
108
+ array(
109
+ 'numberposts' => -1,
110
+ 'nopaging' => true,
111
+ 'post_type' => 'nav_menu_item',
112
+ 'fields' => 'ids',
113
+ 'meta_key' => '_pll_menu_item',
114
+ )
115
+ );
116
 
117
  // The options values for the language switcher
118
  $data['val'] = array();
274
  *
275
  * @param int $term_id nav menu id
276
  */
277
+ public function delete_nav_menu( $term_id ) {
278
  if ( isset( $this->options['nav_menus'] ) ) {
279
  foreach ( $this->options['nav_menus'] as $theme => $locations ) {
280
  foreach ( $locations as $loc => $languages ) {
admin/admin-notices.php CHANGED
@@ -33,7 +33,7 @@ class PLL_Admin_Notices {
33
  * @param string $name Notice name
34
  * @param string $html Content of the notice
35
  */
36
- static public function add_notice( $name, $html ) {
37
  self::$notices[ $name ] = $html;
38
  }
39
 
@@ -44,7 +44,7 @@ class PLL_Admin_Notices {
44
  *
45
  * @return array
46
  */
47
- static public function get_notices() {
48
  return self::$notices;
49
  }
50
 
@@ -56,7 +56,7 @@ class PLL_Admin_Notices {
56
  * @param string $notice Notice name
57
  * @return bool
58
  */
59
- static public function is_dismissed( $notice ) {
60
  $dismissed = get_user_meta( get_current_user_id(), 'pll_dismissed_notices', true );
61
  return is_array( $dismissed ) && in_array( $notice, $dismissed );
62
  }
@@ -72,13 +72,16 @@ class PLL_Admin_Notices {
72
  $screen = get_current_screen();
73
  $screen_id = sanitize_title( __( 'Languages', 'polylang' ) );
74
 
75
- return in_array( $screen->id, array(
76
- 'dashboard',
77
- 'plugins',
78
- 'toplevel_page_mlang',
79
- $screen_id . '_page_mlang_strings',
80
- $screen_id . '_page_mlang_settings',
81
- ) );
 
 
 
82
  }
83
 
84
  /**
@@ -88,7 +91,7 @@ class PLL_Admin_Notices {
88
  *
89
  * @param string $notice
90
  */
91
- static public function dismiss( $notice ) {
92
  if ( ! $dismissed = get_user_meta( get_current_user_id(), 'pll_dismissed_notices', true ) ) {
93
  $dismissed = array();
94
  }
@@ -152,7 +155,7 @@ class PLL_Admin_Notices {
152
  printf(
153
  '<a class="notice-dismiss" href="%s"><span class="screen-reader-text">%s</span></a>',
154
  esc_url( wp_nonce_url( add_query_arg( 'pll-hide-notice', $name ), $name, '_pll_notice_nonce' ) ),
155
- __( 'Dismiss this notice.' )
156
  );
157
  }
158
 
@@ -170,7 +173,7 @@ class PLL_Admin_Notices {
170
  <?php
171
  printf(
172
  /* translators: %1$s is link start tag, %2$s is link end tag. */
173
- __( 'We have noticed that you are using Polylang with WooCommerce. We recommend you to use %1$sPolylang for WooCommerce%2$s to ensure the compatibility.', 'polylang' ),
174
  '<a href="https://polylang.pro/downloads/polylang-for-woocommerce/">',
175
  '</a>'
176
  );
@@ -195,7 +198,7 @@ class PLL_Admin_Notices {
195
  <?php
196
  printf(
197
  /* translators: %1$s is link start tag, %2$s is link end tag. */
198
- __( 'We have noticed that you are using Polylang for some time. We hope that you love it! We would be thrilled if you could %1$sgive us a 5 stars rating%2$s.', 'polylang' ),
199
  '<a href="https://wordpress.org/support/plugin/polylang/reviews/?rate=5#new-post">',
200
  '</a>'
201
  );
33
  * @param string $name Notice name
34
  * @param string $html Content of the notice
35
  */
36
+ public static function add_notice( $name, $html ) {
37
  self::$notices[ $name ] = $html;
38
  }
39
 
44
  *
45
  * @return array
46
  */
47
+ public static function get_notices() {
48
  return self::$notices;
49
  }
50
 
56
  * @param string $notice Notice name
57
  * @return bool
58
  */
59
+ public static function is_dismissed( $notice ) {
60
  $dismissed = get_user_meta( get_current_user_id(), 'pll_dismissed_notices', true );
61
  return is_array( $dismissed ) && in_array( $notice, $dismissed );
62
  }
72
  $screen = get_current_screen();
73
  $screen_id = sanitize_title( __( 'Languages', 'polylang' ) );
74
 
75
+ return in_array(
76
+ $screen->id,
77
+ array(
78
+ 'dashboard',
79
+ 'plugins',
80
+ 'toplevel_page_mlang',
81
+ $screen_id . '_page_mlang_strings',
82
+ $screen_id . '_page_mlang_settings',
83
+ )
84
+ );
85
  }
86
 
87
  /**
91
  *
92
  * @param string $notice
93
  */
94
+ public static function dismiss( $notice ) {
95
  if ( ! $dismissed = get_user_meta( get_current_user_id(), 'pll_dismissed_notices', true ) ) {
96
  $dismissed = array();
97
  }
155
  printf(
156
  '<a class="notice-dismiss" href="%s"><span class="screen-reader-text">%s</span></a>',
157
  esc_url( wp_nonce_url( add_query_arg( 'pll-hide-notice', $name ), $name, '_pll_notice_nonce' ) ),
158
+ esc_html__( 'Dismiss this notice.' )
159
  );
160
  }
161
 
173
  <?php
174
  printf(
175
  /* translators: %1$s is link start tag, %2$s is link end tag. */
176
+ esc_html__( 'We have noticed that you are using Polylang with WooCommerce. We recommend you to use %1$sPolylang for WooCommerce%2$s to ensure the compatibility.', 'polylang' ),
177
  '<a href="https://polylang.pro/downloads/polylang-for-woocommerce/">',
178
  '</a>'
179
  );
198
  <?php
199
  printf(
200
  /* translators: %1$s is link start tag, %2$s is link end tag. */
201
+ esc_html__( 'We have noticed that you are using Polylang for some time. We hope that you love it! We would be thrilled if you could %1$sgive us a 5 stars rating%2$s.', 'polylang' ),
202
  '<a href="https://wordpress.org/support/plugin/polylang/reviews/?rate=5#new-post">',
203
  '</a>'
204
  );
admin/admin-static-pages.php CHANGED
@@ -43,7 +43,7 @@ class PLL_Admin_Static_Pages extends PLL_Static_Pages {
43
  * @param string $post_type Current post type
44
  * @param object $post Current post
45
  */
46
- function add_meta_boxes( $post_type, $post ) {
47
  if ( 'page' === $post_type ) {
48
  add_filter( 'option_page_for_posts', array( $this, 'translate_page_for_posts' ) );
49
 
43
  * @param string $post_type Current post type
44
  * @param object $post Current post
45
  */
46
+ public function add_meta_boxes( $post_type, $post ) {
47
  if ( 'page' === $post_type ) {
48
  add_filter( 'option_page_for_posts', array( $this, 'translate_page_for_posts' ) );
49
 
admin/admin-strings.php CHANGED
@@ -14,7 +14,7 @@ class PLL_Admin_Strings {
14
  *
15
  * @since 1.6
16
  */
17
- static public function init() {
18
  // default strings translations sanitization
19
  add_filter( 'pll_sanitize_string_translation', array( __CLASS__, 'sanitize_string_translation' ), 10, 2 );
20
  }
@@ -29,7 +29,7 @@ class PLL_Admin_Strings {
29
  * @param string $context Optional, the group in which the string is registered, defaults to 'polylang'
30
  * @param bool $multiline Optional, whether the string table should display a multiline textarea or a single line input, defaults to single line
31
  */
32
- static public function register_string( $name, $string, $context = 'Polylang', $multiline = false ) {
33
  // Backward compatibility with Polylang older than 1.1
34
  if ( is_bool( $context ) ) {
35
  $multiline = $context;
@@ -48,7 +48,7 @@ class PLL_Admin_Strings {
48
  *
49
  * @return array list of all registered strings
50
  */
51
- static public function &get_strings() {
52
  self::$default_strings = array(
53
  'options' => array(
54
  'blogname' => __( 'Site Title' ),
@@ -117,7 +117,7 @@ class PLL_Admin_Strings {
117
  * @param string $name unique name for the string
118
  * @return string
119
  */
120
- static public function sanitize_string_translation( $translation, $name ) {
121
  $translation = wp_unslash( trim( $translation ) );
122
 
123
  if ( false !== ( $option = array_search( $name, self::$default_strings['options'], true ) ) ) {
14
  *
15
  * @since 1.6
16
  */
17
+ public static function init() {
18
  // default strings translations sanitization
19
  add_filter( 'pll_sanitize_string_translation', array( __CLASS__, 'sanitize_string_translation' ), 10, 2 );
20
  }
29
  * @param string $context Optional, the group in which the string is registered, defaults to 'polylang'
30
  * @param bool $multiline Optional, whether the string table should display a multiline textarea or a single line input, defaults to single line
31
  */
32
+ public static function register_string( $name, $string, $context = 'Polylang', $multiline = false ) {
33
  // Backward compatibility with Polylang older than 1.1
34
  if ( is_bool( $context ) ) {
35
  $multiline = $context;
48
  *
49
  * @return array list of all registered strings
50
  */
51
+ public static function &get_strings() {
52
  self::$default_strings = array(
53
  'options' => array(
54
  'blogname' => __( 'Site Title' ),
117
  * @param string $name unique name for the string
118
  * @return string
119
  */
120
+ public static function sanitize_string_translation( $translation, $name ) {
121
  $translation = wp_unslash( trim( $translation ) );
122
 
123
  if ( false !== ( $option = array_search( $name, self::$default_strings['options'], true ) ) ) {
admin/admin.php CHANGED
@@ -5,21 +5,25 @@
5
  * accessible in $polylang global object
6
  *
7
  * Properties:
8
- * options => inherited, reference to Polylang options array
9
- * model => inherited, reference to PLL_Model object
10
- * links_model => inherited, reference to PLL_Links_Model object
11
- * links => inherited, reference to PLL_Admin_Links object
12
- * static_pages => inherited, reference to PLL_Admin_Static_Pages object
13
- * filters_links => inherited, reference to PLL_Filters_Links object
14
- * curlang => inherited, optional, current language used to filter the content (language of the post or term being edited, equal to filter_lang otherwise)
15
- * filter_lang => inherited, optional, current status of the admin languages filter (in the admin bar)
16
- * pref_lang => inherited, preferred language used as default when saving posts or terms
17
- * filters => reference to PLL_Filters object
18
- * filters_columns => reference to PLL_Admin_Filters_Columns object
19
- * filters_post => reference to PLL_Admin_Filters_Post object
20
- * filters_term => reference to PLL_Admin_filters_Term object
21
- * nav_menu => reference to PLL_Admin_Nav_Menu object
22
- * filters_media => optional, reference to PLL_Admin_Filters_Media object
 
 
 
 
23
  *
24
  * @since 1.2
25
  */
@@ -79,7 +83,7 @@ class PLL_Admin extends PLL_Admin_Base {
79
  * @param array $plugin_data Not used
80
  * @param object $r Plugin update data
81
  */
82
- function plugin_update_message( $plugin_data, $r ) {
83
  if ( isset( $r->upgrade_notice ) ) {
84
  printf( '<p style="margin: 3px 0 0 0; border-top: 1px solid #ddd; padding-top: 3px">%s</p>', esc_html( $r->upgrade_notice ) );
85
  }
@@ -92,7 +96,7 @@ class PLL_Admin extends PLL_Admin_Base {
92
  */
93
  public function add_filters() {
94
  // All these are separated just for convenience and maintainability
95
- $classes = array( 'Filters', 'Filters_Columns', 'Filters_Post', 'Filters_Term', 'Nav_Menu', 'Sync' );
96
 
97
  // Don't load media filters if option is disabled or if user has no right
98
  if ( $this->options['media_support'] && ( $obj = get_post_type_object( 'attachment' ) ) && ( current_user_can( $obj->cap->edit_posts ) || current_user_can( $obj->cap->create_posts ) ) ) {
@@ -112,5 +116,8 @@ class PLL_Admin extends PLL_Admin_Base {
112
  $class = apply_filters( 'pll_' . $obj, 'PLL_Admin_' . $class );
113
  $this->$obj = new $class( $this );
114
  }
 
 
 
115
  }
116
  }
5
  * accessible in $polylang global object
6
  *
7
  * Properties:
8
+ * options => inherited, reference to Polylang options array
9
+ * model => inherited, reference to PLL_Model object
10
+ * links_model => inherited, reference to PLL_Links_Model object
11
+ * links => inherited, reference to PLL_Admin_Links object
12
+ * static_pages => inherited, reference to PLL_Admin_Static_Pages object
13
+ * filters_links => inherited, reference to PLL_Filters_Links object
14
+ * curlang => inherited, optional, current language used to filter the content (language of the post or term being edited, equal to filter_lang otherwise)
15
+ * filter_lang => inherited, optional, current status of the admin languages filter (in the admin bar)
16
+ * pref_lang => inherited, preferred language used as default when saving posts or terms
17
+ * posts => reference to PLL_CRUD_Posts object
18
+ * terms => reference to PLL_CRUD_Terms object
19
+ * filters => reference to PLL_Admin_Filters object
20
+ * filters_columns => reference to PLL_Admin_Filters_Columns object
21
+ * filters_post => reference to PLL_Admin_Filters_Post object
22
+ * filters_term => reference to PLL_Admin_filters_Term object
23
+ * nav_menu => reference to PLL_Admin_Nav_Menu object
24
+ * sync => reference to PLL_Admin_Sync object
25
+ * classic_editor => reference to PLL_Admin_Classic_Editor object
26
+ * filters_media => optional, reference to PLL_Admin_Filters_Media object
27
  *
28
  * @since 1.2
29
  */
83
  * @param array $plugin_data Not used
84
  * @param object $r Plugin update data
85
  */
86
+ public function plugin_update_message( $plugin_data, $r ) {
87
  if ( isset( $r->upgrade_notice ) ) {
88
  printf( '<p style="margin: 3px 0 0 0; border-top: 1px solid #ddd; padding-top: 3px">%s</p>', esc_html( $r->upgrade_notice ) );
89
  }
96
  */
97
  public function add_filters() {
98
  // All these are separated just for convenience and maintainability
99
+ $classes = array( 'Filters', 'Filters_Columns', 'Filters_Post', 'Filters_Term', 'Nav_Menu', 'Sync', 'Classic_Editor' );
100
 
101
  // Don't load media filters if option is disabled or if user has no right
102
  if ( $this->options['media_support'] && ( $obj = get_post_type_object( 'attachment' ) ) && ( current_user_can( $obj->cap->edit_posts ) || current_user_can( $obj->cap->create_posts ) ) ) {
116
  $class = apply_filters( 'pll_' . $obj, 'PLL_Admin_' . $class );
117
  $this->$obj = new $class( $this );
118
  }
119
+
120
+ $this->posts = new PLL_CRUD_Posts( $this );
121
+ $this->terms = new PLL_CRUD_Terms( $this );
122
  }
123
  }
admin/view-translations-post.php CHANGED
@@ -48,8 +48,8 @@ if ( ! defined( 'ABSPATH' ) ) {
48
  ?>
49
  <td class = "pll-translation-column">
50
  <?php
51
- printf( '
52
- <label class="screen-reader-text" for="tr_lang_%1$s">%2$s</label>
53
  <input type="hidden" name="post_tr_lang[%1$s]" id="htr_lang_%1$s" value="%3$s" />
54
  <span lang="%6$s" dir="%7$s"><input type="text" class="tr_lang" id="tr_lang_%1$s" value="%4$s"%5$s /></span>',
55
  esc_attr( $language->slug ),
48
  ?>
49
  <td class = "pll-translation-column">
50
  <?php
51
+ printf(
52
+ '<label class="screen-reader-text" for="tr_lang_%1$s">%2$s</label>
53
  <input type="hidden" name="post_tr_lang[%1$s]" id="htr_lang_%1$s" value="%3$s" />
54
  <span lang="%6$s" dir="%7$s"><input type="text" class="tr_lang" id="tr_lang_%1$s" value="%4$s"%5$s /></span>',
55
  esc_attr( $language->slug ),
admin/view-translations-term.php CHANGED
@@ -67,8 +67,8 @@ else {
67
  ?>
68
  <td class = "pll-translation-column">
69
  <?php
70
- printf( '
71
- <label class="screen-reader-text" for="tr_lang_%1$s">%2$s</label>
72
  <input type="hidden" class="htr_lang" name="term_tr_lang[%1$s]" id="htr_lang_%1$s" value="%3$s" />
73
  <span lang="%6$s" dir="%7$s"><input type="text" class="tr_lang" id="tr_lang_%1$s" value="%4$s"%5$s /></span>',
74
  esc_attr( $language->slug ),
67
  ?>
68
  <td class = "pll-translation-column">
69
  <?php
70
+ printf(
71
+ '<label class="screen-reader-text" for="tr_lang_%1$s">%2$s</label>
72
  <input type="hidden" class="htr_lang" name="term_tr_lang[%1$s]" id="htr_lang_%1$s" value="%3$s" />
73
  <span lang="%6$s" dir="%7$s"><input type="text" class="tr_lang" id="tr_lang_%1$s" value="%4$s"%5$s /></span>',
74
  esc_attr( $language->slug ),
changelog.txt CHANGED
@@ -1470,4 +1470,3 @@ This version does include important changes in database. More than ever, make a
1470
 
1471
  = 0.1 (2011-09-22) =
1472
  * Initial release
1473
-
1470
 
1471
  = 0.1 (2011-09-22) =
1472
  * Initial release
 
css/admin.css CHANGED
@@ -236,7 +236,7 @@ td[class*='column-language_'] {
236
 
237
  #term-translations p {
238
  /* same style as label */
239
- font-size: 12px;
240
  font-style: normal;
241
  padding: 2px;
242
  color: #23282d;
236
 
237
  #term-translations p {
238
  /* same style as label */
239
+ font-weight: 400;
240
  font-style: normal;
241
  padding: 2px;
242
  color: #23282d;
css/admin.min.css CHANGED
@@ -1 +1 @@
1
- #pll-licenses-table td,.translation label{vertical-align:top}#post-translations a,.pll-notice a.notice-dismiss{text-decoration:none}#add-lang select{width:95%}.column-locale,.languages .column-slug{width:15%}.column-default_lang{width:5%}.column-count,.column-flag,.column-term_group{width:10%}.icon-default-lang:before{font-family:dashicons;content:"\f155"}.form-field input[type=radio]{width:auto;margin-right:2px}#pll-about-box p,#pll-recommended p{text-align:justify}#pll-about-box input{margin:0;padding:0;float:right}.stringstranslations .column-context,.stringstranslations .column-name{width:10%}.stringstranslations .column-string{width:33%}.translation label{display:inline-block;width:23%}.translation input,.translation textarea{width:72%}.pll-settings{margin-top:20px}.pll-settings .plugin-title{width:25%}#wpbody-content .pll-settings .pll-configure tr{display:table-row}#wpbody-content .pll-settings .pll-configure td{display:table-cell}#wpbody-content .pll-settings .pll-configure>td{padding:20px 20px 20px 40px}.pll-configure legend{font-size:14px;font-weight:600;margin-bottom:.5em}.pll-configure td .description{margin-top:2px;margin-bottom:.5em}.pll-configure p.submit{margin-top:20px}.pll-configure .button{margin-right:20px}.pll-configure fieldset{margin-bottom:1.5em}.pll-inline-block-list{margin:0}.pll-inline-block-list li{display:inline-block;margin:0;width:250px}#pll-domains-table td{padding:2px 2px 2px 1.5em;-webkit-box-shadow:none;box-shadow:none;border:none}.pll-settings-url-col{display:inline-block;width:49%;vertical-align:top}#pll-licenses-table label{font-size:1em;font-weight:600}.pll-configure .pll-deactivate-license{margin:0 0 0 20px}td[class*=column-language_],th[class*=column-language_]{width:1.5em}.pll-dir-rtl input[type=text],.pll-dir-rtl textarea{direction:rtl}.pll-dir-ltr input[type=text],.pll-dir-ltr textarea{direction:ltr}.pll-dir-ltr .tr_lang,.pll-dir-rtl .tr_lang{direction:inherit}#post-translations p{float:left}#post-translations table{table-layout:fixed;width:100%;clear:both}#post-translations .pll-column-icon,#post-translations .pll-language-column{width:20px}#post-translations .tr_lang{width:100%}#post-translations td{padding:2px}#post-translations .spinner,#term-translations .spinner{float:none;margin:0;background-position:center;width:auto}.pll-column-icon{text-align:center}#select-post-language .pll-select-flag{padding:4px;margin-right:32px}#select-media-language .pll-select-flag{padding:4px;margin-right:10px}.pll-media-edit-column{float:right}.pll-translation-flag{margin-right:14px}#select-add-term-language .pll-select-flag{padding:11px;margin-right:13px}#select-edit-term-language .pll-select-flag{padding:11px;margin-right:4px}#term-translations p{font-size:12px;font-style:normal;padding:2px;color:#23282d}#add-term-translations,#edit-term-translations{width:95%}#term-translations .pll-language-column{line-height:28px;width:20%}#add-term-translations .pll-language-column,#term-translations .pll-edit-column{width:20px}#edit-term-translations .pll-language-column{padding:15px 10px;font-weight:400}.pll_icon_tick:before{content:"\f147"}.pll_icon_add:before{content:"\f132"}.pll_icon_edit:before{content:"\f464"}[class^=pll_icon_]{font:20px/1 dashicons;vertical-align:middle}#wpadminbar #wp-admin-bar-languages .ab-item img{margin:0 8px 0 2px}#wpadminbar #wp-admin-bar-languages #wp-admin-bar-all .ab-item .ab-icon{float:none;top:4px}#wpadminbar #wp-admin-bar-languages .ab-icon:before{content:"\f326";top:1px}.pll-notice.notice{padding-right:38px;position:relative}@media screen and (max-width:782px){#wpbody-content .pll-settings .pll-configure>td{padding:20px}#wpbody-content .pll-settings #cb{padding:20px 9px}.pll-inline-block{width:auto}.pll-settings-url-col{display:block;width:100%}#wpbody-content .pll-settings #pll-licenses-table td{display:block}.pll-configure .pll-deactivate-license{margin:10px 0 5px}.stringstranslations .column-context,.stringstranslations .column-name{display:none}.translation label{display:block;width:95%;padding-left:0}.translation input{width:95%}#edit-term-translations .pll-language-name,#select-add-term-language .pll-select-flag,#select-edit-term-language .pll-select-flag{display:none}#edit-term-translations{width:100%}#add-term-translations .pll-language-column{line-height:38px}#edit-term-translations td{padding:8px 10px}#edit-term-translations .pll-edit-column,#edit-term-translations .pll-language-column{width:20px}.term-translations .pll-edit-column,.term-translations .pll-language-column,.term-translations .pll-translation-column{display:table-cell}.term-translations .hidden{display:none}#wpadminbar #wp-admin-bar-languages{display:block}#wpadminbar #wp-admin-bar-languages>.ab-item{width:50px;text-align:center}#wpadminbar #wp-admin-bar-languages>.ab-item .ab-icon:before{font:32px/1 dashicons;top:-1px}#wpadminbar #wp-admin-bar-languages>.ab-item img{margin:19px 0}#wpadminbar #wp-admin-bar-languages #wp-admin-bar-all .ab-item .ab-icon{margin-right:6px;font-size:20px!important;line-height:20px!important}}
1
+ #pll-licenses-table td,.translation label{vertical-align:top}#post-translations a,.pll-notice a.notice-dismiss{text-decoration:none}#add-lang select{width:95%}.column-locale,.languages .column-slug{width:15%}.column-default_lang{width:5%}.column-count,.column-flag,.column-term_group{width:10%}.icon-default-lang:before{font-family:dashicons;content:"\f155"}.form-field input[type=radio]{width:auto;margin-right:2px}#pll-about-box p,#pll-recommended p{text-align:justify}#pll-about-box input{margin:0;padding:0;float:right}.stringstranslations .column-context,.stringstranslations .column-name{width:10%}.stringstranslations .column-string{width:33%}.translation label{display:inline-block;width:23%}.translation input,.translation textarea{width:72%}.pll-settings{margin-top:20px}.pll-settings .plugin-title{width:25%}#wpbody-content .pll-settings .pll-configure tr{display:table-row}#wpbody-content .pll-settings .pll-configure td{display:table-cell}#wpbody-content .pll-settings .pll-configure>td{padding:20px 20px 20px 40px}.pll-configure legend{font-size:14px;font-weight:600;margin-bottom:.5em}.pll-configure td .description{margin-top:2px;margin-bottom:.5em}.pll-configure p.submit{margin-top:20px}.pll-configure .button{margin-right:20px}.pll-configure fieldset{margin-bottom:1.5em}.pll-inline-block-list{margin:0}.pll-inline-block-list li{display:inline-block;margin:0;width:250px}#pll-domains-table td{padding:2px 2px 2px 1.5em;-webkit-box-shadow:none;box-shadow:none;border:none}.pll-settings-url-col{display:inline-block;width:49%;vertical-align:top}#pll-licenses-table label{font-size:1em;font-weight:600}.pll-configure .pll-deactivate-license{margin:0 0 0 20px}td[class*=column-language_],th[class*=column-language_]{width:1.5em}.pll-dir-rtl input[type=text],.pll-dir-rtl textarea{direction:rtl}.pll-dir-ltr input[type=text],.pll-dir-ltr textarea{direction:ltr}.pll-dir-ltr .tr_lang,.pll-dir-rtl .tr_lang{direction:inherit}#post-translations p{float:left}#post-translations table{table-layout:fixed;width:100%;clear:both}#post-translations .pll-column-icon,#post-translations .pll-language-column{width:20px}#post-translations .tr_lang{width:100%}#post-translations td{padding:2px}#post-translations .spinner,#term-translations .spinner{float:none;margin:0;background-position:center;width:auto}.pll-column-icon{text-align:center}#select-post-language .pll-select-flag{padding:4px;margin-right:32px}#select-media-language .pll-select-flag{padding:4px;margin-right:10px}.pll-media-edit-column{float:right}.pll-translation-flag{margin-right:14px}#select-add-term-language .pll-select-flag{padding:11px;margin-right:13px}#select-edit-term-language .pll-select-flag{padding:11px;margin-right:4px}#term-translations p{font-weight:400;font-style:normal;padding:2px;color:#23282d}#add-term-translations,#edit-term-translations{width:95%}#term-translations .pll-language-column{line-height:28px;width:20%}#add-term-translations .pll-language-column,#term-translations .pll-edit-column{width:20px}#edit-term-translations .pll-language-column{padding:15px 10px;font-weight:400}.pll_icon_tick:before{content:"\f147"}.pll_icon_add:before{content:"\f132"}.pll_icon_edit:before{content:"\f464"}[class^=pll_icon_]{font:20px/1 dashicons;vertical-align:middle}#wpadminbar #wp-admin-bar-languages .ab-item img{margin:0 8px 0 2px}#wpadminbar #wp-admin-bar-languages #wp-admin-bar-all .ab-item .ab-icon{float:none;top:4px}#wpadminbar #wp-admin-bar-languages .ab-icon:before{content:"\f326";top:1px}.pll-notice.notice{padding-right:38px;position:relative}@media screen and (max-width:782px){#wpbody-content .pll-settings .pll-configure>td{padding:20px}#wpbody-content .pll-settings #cb{padding:20px 9px}.pll-inline-block{width:auto}.pll-settings-url-col{display:block;width:100%}#wpbody-content .pll-settings #pll-licenses-table td{display:block}.pll-configure .pll-deactivate-license{margin:10px 0 5px}.stringstranslations .column-context,.stringstranslations .column-name{display:none}.translation label{display:block;width:95%;padding-left:0}.translation input{width:95%}#edit-term-translations .pll-language-name,#select-add-term-language .pll-select-flag,#select-edit-term-language .pll-select-flag{display:none}#edit-term-translations{width:100%}#add-term-translations .pll-language-column{line-height:38px}#edit-term-translations td{padding:8px 10px}#edit-term-translations .pll-edit-column,#edit-term-translations .pll-language-column{width:20px}.term-translations .pll-edit-column,.term-translations .pll-language-column,.term-translations .pll-translation-column{display:table-cell}.term-translations .hidden{display:none}#wpadminbar #wp-admin-bar-languages{display:block}#wpadminbar #wp-admin-bar-languages>.ab-item{width:50px;text-align:center}#wpadminbar #wp-admin-bar-languages>.ab-item .ab-icon:before{font:32px/1 dashicons;top:-1px}#wpadminbar #wp-admin-bar-languages>.ab-item img{margin:19px 0}#wpadminbar #wp-admin-bar-languages #wp-admin-bar-all .ab-item .ab-icon{margin-right:6px;font-size:20px!important;line-height:20px!important}}
css/selectmenu.css CHANGED
@@ -101,7 +101,7 @@
101
 
102
  .ui-selectmenu-button span.ui-selectmenu-text {
103
  text-align: left;
104
- padding: 0.4em 2.1em 0.4em 2em;
105
  display: block;
106
  line-height: 23px;
107
  overflow: hidden;
101
 
102
  .ui-selectmenu-button span.ui-selectmenu-text {
103
  text-align: left;
104
+ padding: 0.2em 2.1em 0.2em 2em;
105
  display: block;
106
  line-height: 23px;
107
  overflow: hidden;
css/selectmenu.min.css CHANGED
@@ -1 +1 @@
1
- .ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-menu{list-style:none;padding:0;margin:0;display:block;outline:0}.ui-menu .ui-menu{position:absolute}.ui-menu .ui-menu-item{position:relative;margin:0;padding:3px 1em 3px .4em;min-height:0;list-style-image:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item{padding-left:2em}.ui-menu .ui-icon,.ui-selectmenu-text .ui-icon{position:absolute;top:0;bottom:0;left:.2em;margin:auto 0}.ui-menu .ui-menu-icon{left:auto;right:0}.ui-selectmenu-menu{padding:0;margin:0;position:absolute;top:0;left:0;display:none}.ui-selectmenu-menu .ui-menu{overflow:auto;overflow-x:hidden;padding-bottom:1px}.ui-selectmenu-menu .ui-menu .ui-selectmenu-optgroup{font-size:1em;font-weight:700;line-height:23px;padding:2px .4em;margin:.5em 0 0;height:auto;border:0}.ui-selectmenu-open{display:block}.ui-selectmenu-button{display:inline-block;overflow:hidden;position:relative;text-decoration:none}.ui-selectmenu-button span.ui-icon{right:.5em;left:auto;margin-top:-10px;position:absolute;top:50%}.ui-selectmenu-button span.ui-selectmenu-text{text-align:left;padding:.4em 2.1em .4em 2em;display:block;line-height:23px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-state-default,.ui-widget-content,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default{background:#fff;border:1px solid #ddd;box-shadow:0 1px 2px rgba(0,0,0,.07) inset;color:#32373c}.ui-widget-content .ui-state-focus,.ui-widget-content .ui-state-hover{background:#f5f5f5}.ui-selectmenu-button.ui-state-focus{border:1px solid #5b9dd9;box-shadow:0 0 2px rgba(30,140,190,.8)}.ui-icon-triangle-1-s:before{content:"\f140";font:20px/1 dashicons}.ui-widget-content{max-height:231px;box-shadow:0 2px 6px rgba(100,100,100,.3)}
1
+ .ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-menu{list-style:none;padding:0;margin:0;display:block;outline:0}.ui-menu .ui-menu{position:absolute}.ui-menu .ui-menu-item{position:relative;margin:0;padding:3px 1em 3px .4em;min-height:0;list-style-image:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item{padding-left:2em}.ui-menu .ui-icon,.ui-selectmenu-text .ui-icon{position:absolute;top:0;bottom:0;left:.2em;margin:auto 0}.ui-menu .ui-menu-icon{left:auto;right:0}.ui-selectmenu-menu{padding:0;margin:0;position:absolute;top:0;left:0;display:none}.ui-selectmenu-menu .ui-menu{overflow:auto;overflow-x:hidden;padding-bottom:1px}.ui-selectmenu-menu .ui-menu .ui-selectmenu-optgroup{font-size:1em;font-weight:700;line-height:23px;padding:2px .4em;margin:.5em 0 0;height:auto;border:0}.ui-selectmenu-open{display:block}.ui-selectmenu-button{display:inline-block;overflow:hidden;position:relative;text-decoration:none}.ui-selectmenu-button span.ui-icon{right:.5em;left:auto;margin-top:-10px;position:absolute;top:50%}.ui-selectmenu-button span.ui-selectmenu-text{text-align:left;padding:.2em 2.1em .2em 2em;display:block;line-height:23px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-state-default,.ui-widget-content,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default{background:#fff;border:1px solid #ddd;box-shadow:0 1px 2px rgba(0,0,0,.07) inset;color:#32373c}.ui-widget-content .ui-state-focus,.ui-widget-content .ui-state-hover{background:#f5f5f5}.ui-selectmenu-button.ui-state-focus{border:1px solid #5b9dd9;box-shadow:0 0 2px rgba(30,140,190,.8)}.ui-icon-triangle-1-s:before{content:"\f140";font:20px/1 dashicons}.ui-widget-content{max-height:231px;box-shadow:0 2px 6px rgba(100,100,100,.3)}
frontend/choose-lang.php CHANGED
@@ -119,7 +119,7 @@ abstract class PLL_Choose_Lang {
119
 
120
  if ( isset( $_SERVER['HTTP_ACCEPT_LANGUAGE'] ) ) {
121
  // Break up string into pieces ( languages and q factors )
122
- preg_match_all( '/([a-z]{1,8}(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*( 1|0\.[0-9]+))?/i', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $lang_parse );
123
 
124
  $k = $lang_parse[1];
125
  $v = $lang_parse[4];
@@ -127,7 +127,7 @@ abstract class PLL_Choose_Lang {
127
  if ( $n = count( $k ) ) {
128
  // Set default to 1 for any without q factor
129
  foreach ( $v as $key => $val ) {
130
- if ( '' === $val ) {
131
  $v[ $key ] = 1;
132
  }
133
  }
@@ -153,7 +153,9 @@ abstract class PLL_Choose_Lang {
153
  }
154
  }
155
 
156
- $languages = $this->model->get_languages_list( array( 'hide_empty' => true ) ); // hides languages with no post
 
 
157
 
158
  /**
159
  * Filter the list of languages to use to match the browser preferences
@@ -164,16 +166,16 @@ abstract class PLL_Choose_Lang {
164
  */
165
  $languages = apply_filters( 'pll_languages_for_browser_preferences', $languages );
166
 
167
- // looks through sorted list and use first one that matches our language list
168
  foreach ( array_keys( $accept_langs ) as $accept_lang ) {
169
- // first loop to match the exact locale
170
  foreach ( $languages as $language ) {
171
  if ( 0 === strcasecmp( $accept_lang, $language->get_locale( 'display' ) ) ) {
172
  return $language->slug;
173
  }
174
  }
175
 
176
- // second loop to match the language set
177
  foreach ( $languages as $language ) {
178
  if ( 0 === stripos( $accept_lang, $language->slug ) || 0 === stripos( $language->get_locale( 'display' ), $accept_lang ) ) {
179
  return $language->slug;
@@ -264,7 +266,7 @@ abstract class PLL_Choose_Lang {
264
  */
265
  if ( $redirect = apply_filters( 'pll_redirect_home', $redirect ) ) {
266
  $this->maybe_setcookie();
267
- wp_redirect( $redirect );
268
  exit;
269
  }
270
  }
119
 
120
  if ( isset( $_SERVER['HTTP_ACCEPT_LANGUAGE'] ) ) {
121
  // Break up string into pieces ( languages and q factors )
122
+ preg_match_all( '/([a-z]{1,8}(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*((?>1|0)(?>\.[0-9]+)?))?/i', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $lang_parse );
123
 
124
  $k = $lang_parse[1];
125
  $v = $lang_parse[4];
127
  if ( $n = count( $k ) ) {
128
  // Set default to 1 for any without q factor
129
  foreach ( $v as $key => $val ) {
130
+ if ( '' === $val || (float) $val > 1 ) {
131
  $v[ $key ] = 1;
132
  }
133
  }
153
  }
154
  }
155
 
156
+ $accept_langs = wp_list_filter( $accept_langs, array( '0' ), 'NOT' ); // Remove languages markes as unacceptable (q=0).
157
+
158
+ $languages = $this->model->get_languages_list( array( 'hide_empty' => true ) ); // Hides languages with no post
159
 
160
  /**
161
  * Filter the list of languages to use to match the browser preferences
166
  */
167
  $languages = apply_filters( 'pll_languages_for_browser_preferences', $languages );
168
 
169
+ // Looks through sorted list and use first one that matches our language list
170
  foreach ( array_keys( $accept_langs ) as $accept_lang ) {
171
+ // First loop to match the exact locale
172
  foreach ( $languages as $language ) {
173
  if ( 0 === strcasecmp( $accept_lang, $language->get_locale( 'display' ) ) ) {
174
  return $language->slug;
175
  }
176
  }
177
 
178
+ // Second loop to match the language set
179
  foreach ( $languages as $language ) {
180
  if ( 0 === stripos( $accept_lang, $language->slug ) || 0 === stripos( $language->get_locale( 'display' ), $accept_lang ) ) {
181
  return $language->slug;
266
  */
267
  if ( $redirect = apply_filters( 'pll_redirect_home', $redirect ) ) {
268
  $this->maybe_setcookie();
269
+ wp_redirect( $redirect, 302, POLYLANG );
270
  exit;
271
  }
272
  }
frontend/frontend-auto-translate.php CHANGED
@@ -164,13 +164,15 @@ class PLL_Frontend_Auto_Translate {
164
 
165
  if ( ! empty( $post_types ) ) {
166
  // No function to get post by name except get_posts itself
167
- $id = $wpdb->get_var( sprintf( "
168
- SELECT ID from {$wpdb->posts}
169
- WHERE {$wpdb->posts}.post_type IN ( '%s' )
170
- AND post_name='%s'",
171
- implode( "', '", esc_sql( $post_types ) ),
172
- esc_sql( $qv['name'] )
173
- ) );
 
 
174
  $qv['name'] = ( $id && ( $tr_id = $this->get_post( $id ) ) && $tr = get_post( $tr_id ) ) ? $tr->post_name : $qv['name'];
175
  }
176
  }
164
 
165
  if ( ! empty( $post_types ) ) {
166
  // No function to get post by name except get_posts itself
167
+ $id = $wpdb->get_var(
168
+ sprintf(
169
+ "SELECT ID from {$wpdb->posts}
170
+ WHERE {$wpdb->posts}.post_type IN ( '%s' )
171
+ AND post_name='%s'",
172
+ implode( "', '", esc_sql( $post_types ) ),
173
+ esc_sql( $qv['name'] )
174
+ )
175
+ );
176
  $qv['name'] = ( $id && ( $tr_id = $this->get_post( $id ) ) && $tr = get_post( $tr_id ) ) ? $tr->post_name : $qv['name'];
177
  }
178
  }
frontend/frontend-filters-links.php CHANGED
@@ -236,12 +236,15 @@ class PLL_Frontend_Filters_Links extends PLL_Filters_Links {
236
  *
237
  * @param array $args
238
  */
239
- $white_list = apply_filters( 'pll_home_url_white_list', array(
240
- array( 'file' => $theme_root ),
241
- array( 'function' => 'wp_nav_menu' ),
242
- array( 'function' => 'login_footer' ),
243
- array( 'function' => 'get_custom_logo' ),
244
- ) );
 
 
 
245
  }
246
 
247
  // We don't want to filter the home url in these cases
@@ -257,10 +260,13 @@ class PLL_Frontend_Filters_Links extends PLL_Filters_Links {
257
  *
258
  * @param array $args
259
  */
260
- $black_list = apply_filters( 'pll_home_url_black_list', array(
261
- array( 'file' => 'searchform.php' ), // Since WP 3.6 searchform.php is passed through get_search_form
262
- array( 'function' => 'get_search_form' ),
263
- ) );
 
 
 
264
  }
265
 
266
  $traces = version_compare( PHP_VERSION, '5.2.5', '>=' ) ? debug_backtrace( false ) : debug_backtrace();
@@ -392,7 +398,7 @@ class PLL_Frontend_Filters_Links extends PLL_Filters_Links {
392
 
393
  // The language is not correctly set so let's redirect to the correct url for this object
394
  if ( $do_redirect && $redirect_url && $requested_url != $redirect_url ) {
395
- wp_redirect( $redirect_url, 301 );
396
  exit;
397
  }
398
 
236
  *
237
  * @param array $args
238
  */
239
+ $white_list = apply_filters(
240
+ 'pll_home_url_white_list',
241
+ array(
242
+ array( 'file' => $theme_root ),
243
+ array( 'function' => 'wp_nav_menu' ),
244
+ array( 'function' => 'login_footer' ),
245
+ array( 'function' => 'get_custom_logo' ),
246
+ )
247
+ );
248
  }
249
 
250
  // We don't want to filter the home url in these cases
260
  *
261
  * @param array $args
262
  */
263
+ $black_list = apply_filters(
264
+ 'pll_home_url_black_list',
265
+ array(
266
+ array( 'file' => 'searchform.php' ), // Since WP 3.6 searchform.php is passed through get_search_form
267
+ array( 'function' => 'get_search_form' ),
268
+ )
269
+ );
270
  }
271
 
272
  $traces = version_compare( PHP_VERSION, '5.2.5', '>=' ) ? debug_backtrace( false ) : debug_backtrace();
398
 
399
  // The language is not correctly set so let's redirect to the correct url for this object
400
  if ( $do_redirect && $redirect_url && $requested_url != $redirect_url ) {
401
+ wp_redirect( $redirect_url, 301, POLYLANG );
402
  exit;
403
  }
404
 
frontend/frontend-filters-search.php CHANGED
@@ -64,7 +64,7 @@ class PLL_Frontend_Filters_Search {
64
  *
65
  * @since 1.2
66
  */
67
- function add_admin_bar_menus() {
68
  remove_action( 'admin_bar_menu', 'wp_admin_bar_search_menu', 4 );
69
  add_action( 'admin_bar_menu', array( $this, 'admin_bar_search_menu' ), 4 );
70
  }
@@ -84,15 +84,17 @@ class PLL_Frontend_Filters_Search {
84
  $form .= '<input type="submit" class="adminbar-button" value="' . esc_attr__( 'Search' ) . '"/>';
85
  $form .= '</form>';
86
 
87
- $wp_admin_bar->add_menu( array(
88
- 'parent' => 'top-secondary',
89
- 'id' => 'search',
90
- 'title' => $this->get_search_form( $form ), // Pass the get_search_form filter
91
- 'meta' => array(
92
- 'class' => 'admin-bar-search',
93
- 'tabindex' => -1,
94
- ),
95
- ) );
 
 
96
  }
97
 
98
  /**
64
  *
65
  * @since 1.2
66
  */
67
+ public function add_admin_bar_menus() {
68
  remove_action( 'admin_bar_menu', 'wp_admin_bar_search_menu', 4 );
69
  add_action( 'admin_bar_menu', array( $this, 'admin_bar_search_menu' ), 4 );
70
  }
84
  $form .= '<input type="submit" class="adminbar-button" value="' . esc_attr__( 'Search' ) . '"/>';
85
  $form .= '</form>';
86
 
87
+ $wp_admin_bar->add_menu(
88
+ array(
89
+ 'parent' => 'top-secondary',
90
+ 'id' => 'search',
91
+ 'title' => $this->get_search_form( $form ), // Pass the get_search_form filter
92
+ 'meta' => array(
93
+ 'class' => 'admin-bar-search',
94
+ 'tabindex' => -1,
95
+ ),
96
+ )
97
+ );
98
  }
99
 
100
  /**
frontend/frontend-filters.php CHANGED
@@ -6,7 +6,7 @@
6
  * @since 1.2
7
  */
8
  class PLL_Frontend_Filters extends PLL_Filters {
9
- private $tax_query_lang;
10
 
11
  /**
12
  * Constructor: setups filters and actions
@@ -18,20 +18,14 @@ class PLL_Frontend_Filters extends PLL_Filters {
18
  public function __construct( &$polylang ) {
19
  parent::__construct( $polylang );
20
 
 
 
21
  // Filters the WordPress locale
22
  add_filter( 'locale', array( $this, 'get_locale' ) );
23
 
24
  // Filter sticky posts by current language
25
  add_filter( 'option_sticky_posts', array( $this, 'option_sticky_posts' ) );
26
 
27
- // Adds cache domain when querying terms
28
- add_filter( 'get_terms_args', array( $this, 'get_terms_args' ) );
29
-
30
- // Filters categories and post tags by language
31
- add_filter( 'terms_clauses', array( $this, 'terms_clauses' ), 10, 3 );
32
- add_action( 'pre_get_posts', array( $this, 'set_tax_query_lang' ), 999 );
33
- add_action( 'posts_selection', array( $this, 'unset_tax_query_lang' ), 0 );
34
-
35
  // Rewrites archives links to filter them by language
36
  add_filter( 'getarchives_join', array( $this, 'getarchives_join' ), 10, 2 );
37
  add_filter( 'getarchives_where', array( $this, 'getarchives_where' ), 10, 2 );
@@ -52,15 +46,6 @@ class PLL_Frontend_Filters extends PLL_Filters {
52
  // Translates biography
53
  add_filter( 'get_user_metadata', array( $this, 'get_user_metadata' ), 10, 4 );
54
 
55
- // Set posts and terms language when created from frontend ( ex with P2 theme )
56
- add_action( 'save_post', array( $this, 'save_post' ), 200, 2 );
57
- add_action( 'create_term', array( $this, 'save_term' ), 10, 3 );
58
- add_action( 'edit_term', array( $this, 'save_term' ), 10, 3 );
59
-
60
- if ( $this->options['media_support'] ) {
61
- add_action( 'add_attachment', array( $this, 'set_default_language' ) );
62
- }
63
-
64
  // Support theme customizer
65
  // FIXME of course does not work if 'transport' is set to 'postMessage'
66
  if ( isset( $_POST['wp_customize'], $_POST['customized'] ) ) {
@@ -108,6 +93,7 @@ class PLL_Frontend_Filters extends PLL_Filters {
108
  $_posts = array_fill_keys( $languages, array() ); // Init with empty arrays
109
  $languages = implode( ',', $languages );
110
 
 
111
  $relations = $wpdb->get_results( "SELECT object_id, term_taxonomy_id FROM {$wpdb->term_relationships} WHERE object_id IN ({$posts}) AND term_taxonomy_id IN ({$languages})" );
112
 
113
  foreach ( $relations as $relation ) {
@@ -122,72 +108,6 @@ class PLL_Frontend_Filters extends PLL_Filters {
122
  return $posts;
123
  }
124
 
125
- /**
126
- * Adds language dependent cache domain when querying terms
127
- * useful as the 'lang' parameter is not included in cache key by WordPress
128
- *
129
- * @since 1.3
130
- *
131
- * @param array $args
132
- * @return array
133
- */
134
- public function get_terms_args( $args ) {
135
- if ( isset( $args['lang'] ) ) {
136
- $lang = $args['lang'];
137
- } elseif ( isset( $this->tax_query_lang ) ) {
138
- $lang = $args['lang'] = empty( $this->tax_query_lang ) && ! empty( $args['slug'] ) ? $this->curlang->slug : $this->tax_query_lang;
139
- } else {
140
- $lang = $this->curlang->slug;
141
- }
142
-
143
- $key = '_' . ( is_array( $lang ) ? implode( ',', $lang ) : $lang );
144
- $args['cache_domain'] = empty( $args['cache_domain'] ) ? 'pll' . $key : $args['cache_domain'] . $key;
145
- return $args;
146
- }
147
-
148
- /**
149
- * Filters categories and post tags by language when needed
150
- *
151
- * @since 0.2
152
- *
153
- * @param array $clauses sql clauses
154
- * @param array $taxonomies
155
- * @param array $args get_terms arguments
156
- * @return array modified sql clauses
157
- */
158
- public function terms_clauses( $clauses, $taxonomies, $args ) {
159
- // Does nothing except on taxonomies which are filterable
160
- // Since WP 4.7, make sure not to filter wp_get_object_terms()
161
- if ( ! $this->model->is_translated_taxonomy( $taxonomies ) || ! empty( $args['object_ids'] ) ) {
162
- return $clauses;
163
- }
164
-
165
- // Adds our clauses to filter by language
166
- return $this->model->terms_clauses( $clauses, isset( $args['lang'] ) ? $args['lang'] : $this->curlang );
167
- }
168
-
169
- /**
170
- * Sets the WP_Term_Query language when doing a WP_Query
171
- * Needed since WP 4.9
172
- *
173
- * @since 2.3.2
174
- *
175
- * @param object $query WP_Query object
176
- */
177
- public function set_tax_query_lang( $query ) {
178
- $this->tax_query_lang = isset( $query->query_vars['lang'] ) ? $query->query_vars['lang'] : '';
179
- }
180
-
181
- /**
182
- * Removes the WP_Term_Query language filter for WP_Query
183
- * Needed since WP 4.9
184
- *
185
- * @since 2.3.2
186
- */
187
- public function unset_tax_query_lang() {
188
- unset( $this->tax_query_lang );
189
- }
190
-
191
  /**
192
  * Modifies the sql request for wp_get_archives to filter by the current language
193
  *
@@ -220,7 +140,7 @@ class PLL_Frontend_Filters extends PLL_Filters {
220
  *
221
  * @since 0.3
222
  *
223
- * @param array $instance widget settings
224
  * @param object $widget WP_Widget object
225
  * @return bool|array false if we hide the widget, unmodified $instance otherwise
226
  */
@@ -233,6 +153,7 @@ class PLL_Frontend_Filters extends PLL_Filters {
233
  * Needed to allow is_active_sidebar() to return false if all widgets are not for the current language. See #54
234
  *
235
  * @since 2.1
 
236
  *
237
  * @param array $sidebars_widgets An associative array of sidebars and their widgets
238
  * @return array
@@ -240,8 +161,14 @@ class PLL_Frontend_Filters extends PLL_Filters {
240
  public function sidebars_widgets( $sidebars_widgets ) {
241
  global $wp_registered_widgets;
242
 
 
 
 
 
 
 
243
  foreach ( $sidebars_widgets as $sidebar => $widgets ) {
244
- if ( 'wp_inactive_widgets' == $sidebar || empty( $widgets ) ) {
245
  continue;
246
  }
247
 
@@ -253,7 +180,7 @@ class PLL_Frontend_Filters extends PLL_Filters {
253
  }
254
 
255
  $widget_settings = $wp_registered_widgets[ $widget ]['callback'][0]->get_settings();
256
- $number = $wp_registered_widgets[ $widget ]['params'][0]['number'];
257
 
258
  // Remove the widget if not visible in the current language
259
  if ( ! empty( $widget_settings[ $number ]['pll_lang'] ) && $widget_settings[ $number ]['pll_lang'] !== $this->curlang->slug ) {
@@ -262,6 +189,8 @@ class PLL_Frontend_Filters extends PLL_Filters {
262
  }
263
  }
264
 
 
 
265
  return $sidebars_widgets;
266
  }
267
 
@@ -308,64 +237,6 @@ class PLL_Frontend_Filters extends PLL_Filters {
308
  return 'description' === $meta_key && $this->curlang->slug !== $this->options['default_lang'] ? get_user_meta( $id, 'description_' . $this->curlang->slug, $single ) : $null;
309
  }
310
 
311
- /**
312
- * Allows to set a language by default for posts if it has no language yet
313
- *
314
- * @since 1.5.4
315
- *
316
- * @param int $post_id
317
- */
318
- public function set_default_language( $post_id ) {
319
- if ( ! $this->model->post->get_language( $post_id ) ) {
320
- if ( isset( $_REQUEST['lang'] ) ) {
321
- $this->model->post->set_language( $post_id, $_REQUEST['lang'] );
322
- } elseif ( ( $parent_id = wp_get_post_parent_id( $post_id ) ) && $parent_lang = $this->model->post->get_language( $parent_id ) ) {
323
- $this->model->post->set_language( $post_id, $parent_lang );
324
- } else {
325
- $this->model->post->set_language( $post_id, $this->curlang );
326
- }
327
- }
328
- }
329
-
330
- /**
331
- * Called when a post ( or page ) is saved, published or updated
332
- * Does nothing except on post types which are filterable
333
- * Sets the language but does not allow to modify it
334
- *
335
- * @since 1.1
336
- *
337
- * @param int $post_id
338
- * @param object $post
339
- */
340
- public function save_post( $post_id, $post ) {
341
- if ( $this->model->is_translated_post_type( $post->post_type ) ) {
342
- $this->set_default_language( $post_id );
343
- }
344
- }
345
-
346
- /**
347
- * Called when a category or post tag is created or edited
348
- * Does nothing except on taxonomies which are filterable
349
- * Sets the language but does not allow to modify it
350
- *
351
- * @since 1.1
352
- *
353
- * @param int $term_id
354
- * @param int $tt_id Term taxonomy id
355
- * @param string $taxonomy
356
- */
357
- public function save_term( $term_id, $tt_id, $taxonomy ) {
358
- if ( $this->model->is_translated_taxonomy( $taxonomy ) && ! $this->model->term->get_language( $term_id ) ) {
359
- if ( isset( $_REQUEST['lang'] ) ) {
360
- $this->model->term->set_language( $term_id, $_REQUEST['lang'] );
361
- } elseif ( ( $term = get_term( $term_id, $taxonomy ) ) && ! empty( $term->parent ) && $parent_lang = $this->model->term->get_language( $term->parent ) ) {
362
- $this->model->term->set_language( $term_id, $parent_lang );
363
- } else {
364
- $this->model->term->set_language( $term_id, $this->curlang );
365
- }
366
- }
367
- }
368
-
369
  /**
370
  * Filters the translation files to load when doing ajax on front
371
  * This is needed because WP the language files associated to the user locale when a user is logged in
6
  * @since 1.2
7
  */
8
  class PLL_Frontend_Filters extends PLL_Filters {
9
+ public $cache;
10
 
11
  /**
12
  * Constructor: setups filters and actions
18
  public function __construct( &$polylang ) {
19
  parent::__construct( $polylang );
20
 
21
+ $this->cache = new PLL_Cache();
22
+
23
  // Filters the WordPress locale
24
  add_filter( 'locale', array( $this, 'get_locale' ) );
25
 
26
  // Filter sticky posts by current language
27
  add_filter( 'option_sticky_posts', array( $this, 'option_sticky_posts' ) );
28
 
 
 
 
 
 
 
 
 
29
  // Rewrites archives links to filter them by language
30
  add_filter( 'getarchives_join', array( $this, 'getarchives_join' ), 10, 2 );
31
  add_filter( 'getarchives_where', array( $this, 'getarchives_where' ), 10, 2 );
46
  // Translates biography
47
  add_filter( 'get_user_metadata', array( $this, 'get_user_metadata' ), 10, 4 );
48
 
 
 
 
 
 
 
 
 
 
49
  // Support theme customizer
50
  // FIXME of course does not work if 'transport' is set to 'postMessage'
51
  if ( isset( $_POST['wp_customize'], $_POST['customized'] ) ) {
93
  $_posts = array_fill_keys( $languages, array() ); // Init with empty arrays
94
  $languages = implode( ',', $languages );
95
 
96
+ // PHPCS:ignore WordPress.DB.PreparedSQL.NotPrepared
97
  $relations = $wpdb->get_results( "SELECT object_id, term_taxonomy_id FROM {$wpdb->term_relationships} WHERE object_id IN ({$posts}) AND term_taxonomy_id IN ({$languages})" );
98
 
99
  foreach ( $relations as $relation ) {
108
  return $posts;
109
  }
110
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
111
  /**
112
  * Modifies the sql request for wp_get_archives to filter by the current language
113
  *
140
  *
141
  * @since 0.3
142
  *
143
+ * @param array $instance Widget settings
144
  * @param object $widget WP_Widget object
145
  * @return bool|array false if we hide the widget, unmodified $instance otherwise
146
  */
153
  * Needed to allow is_active_sidebar() to return false if all widgets are not for the current language. See #54
154
  *
155
  * @since 2.1
156
+ * @since 2.4 The result is cached as the function can be very expensive in case there are a lot of widgets
157
  *
158
  * @param array $sidebars_widgets An associative array of sidebars and their widgets
159
  * @return array
161
  public function sidebars_widgets( $sidebars_widgets ) {
162
  global $wp_registered_widgets;
163
 
164
+ $_sidebars_widgets = $this->cache->get( 'sidebars_widgets' );
165
+
166
+ if ( false !== $_sidebars_widgets ) {
167
+ return $_sidebars_widgets;
168
+ }
169
+
170
  foreach ( $sidebars_widgets as $sidebar => $widgets ) {
171
+ if ( 'wp_inactive_widgets' === $sidebar || empty( $widgets ) ) {
172
  continue;
173
  }
174
 
180
  }
181
 
182
  $widget_settings = $wp_registered_widgets[ $widget ]['callback'][0]->get_settings();
183
+ $number = $wp_registered_widgets[ $widget ]['params'][0]['number'];
184
 
185
  // Remove the widget if not visible in the current language
186
  if ( ! empty( $widget_settings[ $number ]['pll_lang'] ) && $widget_settings[ $number ]['pll_lang'] !== $this->curlang->slug ) {
189
  }
190
  }
191
 
192
+ $this->cache->set( 'sidebars_widgets', $sidebars_widgets );
193
+
194
  return $sidebars_widgets;
195
  }
196
 
237
  return 'description' === $meta_key && $this->curlang->slug !== $this->options['default_lang'] ? get_user_meta( $id, 'description_' . $this->curlang->slug, $single ) : $null;
238
  }
239
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
240
  /**
241
  * Filters the translation files to load when doing ajax on front
242
  * This is needed because WP the language files associated to the user locale when a user is logged in
frontend/frontend-nav-menu.php CHANGED
@@ -96,7 +96,10 @@ class PLL_Frontend_Nav_Menu extends PLL_Nav_Menu {
96
  if ( $options = get_post_meta( $item->ID, '_pll_menu_item', true ) ) {
97
  $i = 0;
98
 
99
- $switcher = new PLL_Switcher;
 
 
 
100
  $args = array_merge( array( 'raw' => 1 ), $options );
101
  $the_languages = $switcher->the_languages( PLL()->links, $args );
102
 
96
  if ( $options = get_post_meta( $item->ID, '_pll_menu_item', true ) ) {
97
  $i = 0;
98
 
99
+ /** This filter is documented in include/switcher.php */
100
+ $options = apply_filters( 'pll_the_languages_args', $options ); // Honor the filter here for 'show_flags', 'show_names' and 'dropdown'.
101
+
102
+ $switcher = new PLL_Switcher();
103
  $args = array_merge( array( 'raw' => 1 ), $options );
104
  $the_languages = $switcher->the_languages( PLL()->links, $args );
105
 
frontend/frontend.php CHANGED
@@ -5,18 +5,21 @@
5
  * accessible as $polylang global object
6
  *
7
  * Properties:
8
- * options => inherited, reference to Polylang options array
9
- * model => inherited, reference to PLL_Model object
10
- * links_model => inherited, reference to PLL_Links_Model object
11
- * links => reference to PLL_Links object
12
- * static_pages => reference to PLL_Frontend_Static_Pages object
13
- * filters_links => inherited, reference to PLL_Frontend_Filters_Links object
14
- * choose_lang => reference to PLL_Choose_lang object
15
- * curlang => current language
16
- * filters => reference to PLL_Filters object
17
- * filters_search => reference to PLL_Frontend_Filters_Search object
18
- * nav_menu => reference to PLL_Frontend_Nav_Menu object
19
- * auto_translate => optional, reference to PLL_Auto_Translate object
 
 
 
20
  *
21
  * @since 1.2
22
  */
@@ -87,6 +90,10 @@ class PLL_Frontend extends PLL_Base {
87
  $this->filters_links = new PLL_Frontend_Filters_Links( $this );
88
  $this->filters = new PLL_Frontend_Filters( $this );
89
  $this->filters_search = new PLL_Frontend_Filters_Search( $this );
 
 
 
 
90
 
91
  // Auto translate for Ajax
92
  if ( ( ! defined( 'PLL_AUTO_TRANSLATE' ) || PLL_AUTO_TRANSLATE ) && wp_doing_ajax() ) {
5
  * accessible as $polylang global object
6
  *
7
  * Properties:
8
+ * options => inherited, reference to Polylang options array
9
+ * model => inherited, reference to PLL_Model object
10
+ * links_model => inherited, reference to PLL_Links_Model object
11
+ * links => reference to PLL_Links object
12
+ * static_pages => reference to PLL_Frontend_Static_Pages object
13
+ * choose_lang => reference to PLL_Choose_lang object
14
+ * curlang => current language
15
+ * filters => reference to PLL_Frontend_Filters object
16
+ * filters_links => reference to PLL_Frontend_Filters_Links object
17
+ * filters_search => reference to PLL_Frontend_Filters_Search object
18
+ * posts => reference to PLL_CRUD_Posts object
19
+ * terms => reference to PLL_CRUD_Terms object
20
+ * nav_menu => reference to PLL_Frontend_Nav_Menu object
21
+ * sync => reference to PLL_Sync object
22
+ * auto_translate => optional, reference to PLL_Auto_Translate object
23
  *
24
  * @since 1.2
25
  */
90
  $this->filters_links = new PLL_Frontend_Filters_Links( $this );
91
  $this->filters = new PLL_Frontend_Filters( $this );
92
  $this->filters_search = new PLL_Frontend_Filters_Search( $this );
93
+ $this->posts = new PLL_CRUD_Posts( $this );
94
+ $this->terms = new PLL_CRUD_Terms( $this );
95
+
96
+ $this->sync = new PLL_Sync( $this );
97
 
98
  // Auto translate for Ajax
99
  if ( ( ! defined( 'PLL_AUTO_TRANSLATE' ) || PLL_AUTO_TRANSLATE ) && wp_doing_ajax() ) {
include/api.php CHANGED
@@ -25,7 +25,7 @@
25
  */
26
  function pll_the_languages( $args = '' ) {
27
  if ( PLL() instanceof PLL_Frontend ) {
28
- $switcher = new PLL_Switcher;
29
  return $switcher->the_languages( PLL()->links, $args );
30
  }
31
  return '';
@@ -123,7 +123,7 @@ function pll_register_string( $name, $string, $context = 'polylang', $multiline
123
  * @return string the string translation in the current language
124
  */
125
  function pll__( $string ) {
126
- return is_scalar( $string ) ? __( $string, 'pll_string' ) : $string;
127
  }
128
 
129
  /**
@@ -374,6 +374,6 @@ function pll_count_posts( $lang, $args = array() ) {
374
  *
375
  * @since 1.8
376
  */
377
- function PLL() {
378
  return $GLOBALS['polylang'];
379
  }
25
  */
26
  function pll_the_languages( $args = '' ) {
27
  if ( PLL() instanceof PLL_Frontend ) {
28
+ $switcher = new PLL_Switcher();
29
  return $switcher->the_languages( PLL()->links, $args );
30
  }
31
  return '';
123
  * @return string the string translation in the current language
124
  */
125
  function pll__( $string ) {
126
+ return is_scalar( $string ) ? __( $string, 'pll_string' ) : $string; // PHPCS:ignore WordPress.WP.I18n.NonSingularStringLiteralText
127
  }
128
 
129
  /**
374
  *
375
  * @since 1.8
376
  */
377
+ function PLL() { // PHPCS:ignore WordPress.NamingConventions.ValidFunctionName
378
  return $GLOBALS['polylang'];
379
  }
include/base.php CHANGED
@@ -112,10 +112,15 @@ abstract class PLL_Base {
112
  if ( WP_DEBUG ) {
113
  $debug = debug_backtrace();
114
  $i = 1 + empty( $debug[1]['line'] ); // The file and line are in $debug[2] if the function was called using call_user_func
115
- trigger_error( sprintf(
116
- '%1$s was called incorrectly in %3$s on line %4$s: the call to $polylang->%1$s() has been deprecated in Polylang 1.2, use PLL()->%2$s->%1$s() instead.' . "\nError handler",
117
- $func, $prop, $debug[ $i ]['file'], $debug[ $i ]['line']
118
- ) );
 
 
 
 
 
119
  }
120
  return call_user_func_array( array( $obj, $func ), $args );
121
  }
112
  if ( WP_DEBUG ) {
113
  $debug = debug_backtrace();
114
  $i = 1 + empty( $debug[1]['line'] ); // The file and line are in $debug[2] if the function was called using call_user_func
115
+ trigger_error(
116
+ sprintf(
117
+ '%1$s was called incorrectly in %3$s on line %4$s: the call to $polylang->%1$s() has been deprecated in Polylang 1.2, use PLL()->%2$s->%1$s() instead.' . "\nError handler",
118
+ $func,
119
+ $prop,
120
+ $debug[ $i ]['file'],
121
+ $debug[ $i ]['line']
122
+ )
123
+ );
124
  }
125
  return call_user_func_array( array( $obj, $func ), $args );
126
  }
include/class-polylang.php CHANGED
@@ -68,7 +68,7 @@ class Polylang {
68
  }
69
 
70
  $class = str_replace( '_', '-', strtolower( substr( $class, 4 ) ) );
71
- $to_find = array( 'media', 'share', 'slug', 'slugs', 'sync', 'translate', 'wpml', 'xdata', 'rest' );
72
  $dir = implode( '-', array_intersect( explode( '-', $class ), $to_find ) );
73
 
74
  $dirs = array(
@@ -97,7 +97,7 @@ class Polylang {
97
  *
98
  * @return bool
99
  */
100
- static public function is_ajax_on_front() {
101
  // Special test for plupload which does not use jquery ajax and thus does not pass our ajax prefilter
102
  // Special test for customize_save done in frontend but for which we want to load the admin
103
  $in = isset( $_REQUEST['action'] ) && in_array( $_REQUEST['action'], array( 'upload-attachment', 'customize_save' ) );
@@ -119,7 +119,7 @@ class Polylang {
119
  *
120
  * @since 1.6
121
  */
122
- static public function define_constants() {
123
  // Cookie name. no cookie will be used if set to false
124
  if ( ! defined( 'PLL_COOKIE' ) ) {
125
  define( 'PLL_COOKIE', 'pll_language' );
68
  }
69
 
70
  $class = str_replace( '_', '-', strtolower( substr( $class, 4 ) ) );
71
+ $to_find = array( 'media', 'share', 'slug', 'slugs', 'sync', 'translate', 'wpml', 'xdata', 'rest', 'bulk' );
72
  $dir = implode( '-', array_intersect( explode( '-', $class ), $to_find ) );
73
 
74
  $dirs = array(
97
  *
98
  * @return bool
99
  */
100
+ public static function is_ajax_on_front() {
101
  // Special test for plupload which does not use jquery ajax and thus does not pass our ajax prefilter
102
  // Special test for customize_save done in frontend but for which we want to load the admin
103
  $in = isset( $_REQUEST['action'] ) && in_array( $_REQUEST['action'], array( 'upload-attachment', 'customize_save' ) );
119
  *
120
  * @since 1.6
121
  */
122
+ public static function define_constants() {
123
  // Cookie name. no cookie will be used if set to false
124
  if ( ! defined( 'PLL_COOKIE' ) ) {
125
  define( 'PLL_COOKIE', 'pll_language' );
include/crud-posts.php ADDED
@@ -0,0 +1,234 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Adds actions and filters related to languages when creating, updating or deleting posts
5
+ * Actions a filters used when reaing posts are handled separately
6
+ *
7
+ * @since 2.4
8
+ */
9
+ class PLL_CRUD_Posts {
10
+
11
+ /**
12
+ * Constructor
13
+ *
14
+ * @since 2.4
15
+ *
16
+ * @param object $polylang
17
+ */
18
+ public function __construct( &$polylang ) {
19
+ $this->model = &$polylang->model;
20
+ $this->pref_lang = &$polylang->pref_lang;
21
+ $this->curlang = &$polylang->curlang;
22
+
23
+ add_action( 'save_post', array( $this, 'save_post' ), 10, 2 );
24
+ add_action( 'set_object_terms', array( $this, 'set_object_terms' ), 10, 4 );
25
+ add_filter( 'wp_insert_post_parent', array( $this, 'wp_insert_post_parent' ), 10, 4 );
26
+ add_action( 'before_delete_post', array( $this, 'delete_post' ) );
27
+
28
+ // Specific for media
29
+ if ( $polylang->options['media_support'] ) {
30
+ add_action( 'add_attachment', array( $this, 'set_default_language' ) );
31
+ add_action( 'delete_attachment', array( $this, 'delete_post' ) );
32
+ add_filter( 'wp_delete_file', array( $this, 'wp_delete_file' ) );
33
+ }
34
+ }
35
+
36
+ /**
37
+ * Allows to set a language by default for posts if it has no language yet
38
+ *
39
+ * @since 1.5
40
+ *
41
+ * @param int $post_id
42
+ */
43
+ public function set_default_language( $post_id ) {
44
+ if ( ! $this->model->post->get_language( $post_id ) ) {
45
+ if ( ! empty( $_GET['new_lang'] ) && $lang = $this->model->get_language( $_GET['new_lang'] ) ) {
46
+ // Defined only on admin.
47
+ $this->model->post->set_language( $post_id, $lang );
48
+ } elseif ( ! isset( $this->pref_lang ) && ! empty( $_REQUEST['lang'] ) && $lang = $this->model->get_language( $_REQUEST['lang'] ) ) {
49
+ // Testing $this->pref_lang makes this test pass only on admin.
50
+ $this->model->post->set_language( $post_id, $lang );
51
+ } elseif ( ( $parent_id = wp_get_post_parent_id( $post_id ) ) && $parent_lang = $this->model->post->get_language( $parent_id ) ) {
52
+ $this->model->post->set_language( $post_id, $parent_lang );
53
+ } elseif ( isset( $this->pref_lang ) ) {
54
+ // Always defined on admin, never defined on frontend
55
+ $this->model->post->set_language( $post_id, $this->pref_lang );
56
+ } else {
57
+ // Only on frontend due to the previous test always true on admin
58
+ $this->model->post->set_language( $post_id, $this->curlang );
59
+ }
60
+ }
61
+ }
62
+
63
+ /**
64
+ * Called when a post ( or page ) is saved, published or updated
65
+ *
66
+ * @since 0.1
67
+ * @since 2.3 Does not save the language and translations anymore, unless the post has no language yet
68
+ *
69
+ * @param int $post_id
70
+ * @param object $post
71
+ */
72
+ public function save_post( $post_id, $post ) {
73
+ // Does nothing except on post types which are filterable
74
+ if ( $this->model->is_translated_post_type( $post->post_type ) ) {
75
+ if ( $id = wp_is_post_revision( $post_id ) ) {
76
+ $post_id = $id;
77
+ }
78
+
79
+ $lang = $this->model->post->get_language( $post_id );
80
+
81
+ if ( empty( $lang ) ) {
82
+ $this->set_default_language( $post_id );
83
+ }
84
+
85
+ /**
86
+ * Fires after the post language and translations are saved
87
+ *
88
+ * @since 1.2
89
+ *
90
+ * @param int $post_id Post id
91
+ * @param object $post Post object
92
+ * @param array $translations The list of translations post ids
93
+ */
94
+ do_action( 'pll_save_post', $post_id, $post, $this->model->post->get_translations( $post_id ) );
95
+ }
96
+ }
97
+
98
+ /**
99
+ * Make sure saved terms are in the right language (especially tags with same name in different languages)
100
+ *
101
+ * @since 2.3
102
+ *
103
+ * @param int $object_id Object ID.
104
+ * @param array $terms An array of object terms.
105
+ * @param array $tt_ids An array of term taxonomy IDs.
106
+ * @param string $taxonomy Taxonomy slug.
107
+ */
108
+ public function set_object_terms( $object_id, $terms, $tt_ids, $taxonomy ) {
109
+ static $avoid_recursion;
110
+
111
+ if ( ! $avoid_recursion && $this->model->is_translated_taxonomy( $taxonomy ) && ! empty( $terms ) ) {
112
+ $lang = $this->model->post->get_language( $object_id );
113
+
114
+ if ( ! empty( $lang ) && is_array( $terms ) ) {
115
+ // Convert to term ids if we got tag names
116
+ $strings = array_filter( $terms, 'is_string' );
117
+ if ( ! empty( $strings ) ) {
118
+ $_terms = get_terms( $taxonomy, array( 'name' => $strings, 'object_ids' => $object_id, 'fields' => 'ids' ) );
119
+ $terms = array_merge( array_diff( $terms, $strings ), $_terms );
120
+ }
121
+
122
+ $term_ids = array_combine( $terms, $terms );
123
+ $languages = array_map( array( $this->model->term, 'get_language' ), $term_ids );
124
+ $languages = wp_list_pluck( $languages, 'slug' );
125
+ $wrong_terms = array_diff( $languages, array( $lang->slug ) );
126
+
127
+ if ( ! empty( $wrong_terms ) ) {
128
+ // We got terms in a wrong language
129
+ $wrong_term_ids = array_keys( $wrong_terms );
130
+ $terms = get_the_terms( $object_id, $taxonomy );
131
+ wp_remove_object_terms( $object_id, $wrong_term_ids, $taxonomy );
132
+
133
+ if ( is_array( $terms ) ) {
134
+ $newterms = array();
135
+
136
+ foreach ( $terms as $term ) {
137
+ if ( in_array( $term->term_id, $wrong_term_ids ) ) {
138
+ // Check if the term is in the correct language or if a translation exist ( mainly for default category )
139
+ if ( $newterm = $this->model->term->get( $term->term_id, $lang ) ) {
140
+ $newterms[] = (int) $newterm;
141
+ }
142
+
143
+ // Or choose the correct language for tags ( initially defined by name )
144
+ elseif ( $newterm = $this->model->term_exists( $term->name, $taxonomy, $term->parent, $lang ) ) {
145
+ $newterms[] = (int) $newterm; // Cast is important otherwise we get 'numeric' tags
146
+ }
147
+
148
+ // Or create the term in the correct language
149
+ elseif ( ! is_wp_error( $term_info = wp_insert_term( $term->name, $taxonomy ) ) ) {
150
+ $newterms[] = (int) $term_info['term_id'];
151
+ }
152
+ }
153
+ }
154
+
155
+ $avoid_recursion = true;
156
+ wp_set_object_terms( $object_id, array_unique( $newterms ), $taxonomy, true ); // Append
157
+ $avoid_recursion = false;
158
+ }
159
+ }
160
+ }
161
+ }
162
+ }
163
+
164
+ /**
165
+ * Make sure that the post parent is in the correct language when using bulk edit
166
+ *
167
+ * @since 1.8
168
+ *
169
+ * @param int $post_parent Post parent ID.
170
+ * @param int $post_id Post ID.
171
+ * @param array $new_postarr Array of parsed post data.
172
+ * @param array $postarr Array of sanitized, but otherwise unmodified post data.
173
+ * @return int
174
+ */
175
+ public function wp_insert_post_parent( $post_parent, $post_id, $new_postarr, $postarr ) {
176
+ if ( isset( $postarr['bulk_edit'], $postarr['inline_lang_choice'] ) ) {
177
+ check_admin_referer( 'bulk-posts' );
178
+ $lang = -1 == $postarr['inline_lang_choice'] ?
179
+ $this->model->post->get_language( $post_id ) :
180
+ $this->model->get_language( $postarr['inline_lang_choice'] );
181
+ // Dont break the hierarchy in case the post has no language
182
+ if ( ! empty( $lang ) ) {
183
+ $post_parent = $this->model->post->get_translation( $post_parent, $lang );
184
+ }
185
+ }
186
+ return $post_parent;
187
+ }
188
+
189
+ /**
190
+ * Called when a post, page or media is deleted
191
+ * Don't delete translations if this is a post revision thanks to AndyDeGroo who catched this bug
192
+ * http://wordpress.org/support/topic/plugin-polylang-quick-edit-still-breaks-translation-linking-of-pages-in-072
193
+ *
194
+ * @since 0.1
195
+ *
196
+ * @param int $post_id
197
+ */
198
+ public function delete_post( $post_id ) {
199
+ if ( ! wp_is_post_revision( $post_id ) ) {
200
+ $this->model->post->delete_translation( $post_id );
201
+ }
202
+ }
203
+
204
+ /**
205
+ * Prevents WP deleting files when there are still media using them
206
+ * Thanks to Bruno "Aesqe" Babic and its plugin file gallery in which I took all the ideas for this function
207
+ *
208
+ * @since 0.9
209
+ *
210
+ * @param string $file
211
+ * @return string unmodified $file
212
+ */
213
+ public function wp_delete_file( $file ) {
214
+ global $wpdb;
215
+
216
+ $uploadpath = wp_upload_dir();
217
+
218
+ $ids = $wpdb->get_col(
219
+ $wpdb->prepare(
220
+ "SELECT post_id FROM $wpdb->postmeta
221
+ WHERE meta_key = '_wp_attached_file' AND meta_value = %s",
222
+ substr_replace( $file, '', 0, strlen( trailingslashit( $uploadpath['basedir'] ) ) )
223
+ )
224
+ );
225
+
226
+ if ( ! empty( $ids ) ) {
227
+ // Regenerate intermediate sizes if it's an image ( since we could not prevent WP deleting them before )
228
+ wp_update_attachment_metadata( $ids[0], wp_generate_attachment_metadata( $ids[0], $file ) );
229
+ return ''; // Prevent deleting the main file
230
+ }
231
+
232
+ return $file;
233
+ }
234
+ }
include/crud-terms.php ADDED
@@ -0,0 +1,206 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Adds actions and filters related to languages when creating, reading, updating or deleting posts
5
+ * Acts both on frontend and backend
6
+ *
7
+ * @since 2.4
8
+ */
9
+ class PLL_CRUD_Terms {
10
+ public $model, $curlang, $filter_lang, $pref_lang;
11
+ private $tax_query_lang;
12
+
13
+ /**
14
+ * Constructor
15
+ *
16
+ * @since 2.4
17
+ *
18
+ * @param object $polylang
19
+ */
20
+ public function __construct( &$polylang ) {
21
+ $this->model = &$polylang->model;
22
+ $this->curlang = &$polylang->curlang;
23
+ $this->filter_lang = &$polylang->filter_lang;
24
+ $this->pref_lang = &$polylang->pref_lang;
25
+
26
+ // Saving terms
27
+ add_action( 'create_term', array( $this, 'save_term' ), 999, 3 );
28
+ add_action( 'edit_term', array( $this, 'save_term' ), 999, 3 ); // After PLL_Admin_Filters_Term
29
+
30
+ // Adds cache domain when querying terms
31
+ add_filter( 'get_terms_args', array( $this, 'get_terms_args' ), 10, 2 );
32
+
33
+ // Filters terms by language
34
+ add_filter( 'terms_clauses', array( $this, 'terms_clauses' ), 10, 3 );
35
+ add_action( 'pre_get_posts', array( $this, 'set_tax_query_lang' ), 999 );
36
+ add_action( 'posts_selection', array( $this, 'unset_tax_query_lang' ), 0 );
37
+
38
+ // Deleting terms
39
+ add_action( 'pre_delete_term', array( $this, 'delete_term' ) );
40
+ }
41
+
42
+ /**
43
+ * Allows to set a language by default for terms if it has no language yet
44
+ *
45
+ * @since 1.5.4
46
+ *
47
+ * @param int $term_id
48
+ * @param string $taxonomy
49
+ */
50
+ protected function set_default_language( $term_id, $taxonomy ) {
51
+ if ( ! $this->model->term->get_language( $term_id ) ) {
52
+ if ( ! isset( $this->pref_lang ) && ! empty( $_REQUEST['lang'] ) && $lang = $this->model->get_language( $_REQUEST['lang'] ) ) {
53
+ // Testing $this->pref_lang makes this test pass only on frontend.
54
+ $this->model->term->set_language( $term_id, $lang );
55
+ } elseif ( ( $term = get_term( $term_id, $taxonomy ) ) && ! empty( $term->parent ) && $parent_lang = $this->model->term->get_language( $term->parent ) ) {
56
+ // Sets language from term parent if exists thanks to Scott Kingsley Clark
57
+ $this->model->term->set_language( $term_id, $parent_lang );
58
+ } elseif ( isset( $this->pref_lang ) ) {
59
+ // Always defined on admin, never defined on frontend
60
+ $this->model->term->set_language( $term_id, $this->pref_lang );
61
+ } else {
62
+ // Only on frontend due to the previous test always true on admin
63
+ $this->model->term->set_language( $term_id, $this->curlang );
64
+ }
65
+ }
66
+ }
67
+
68
+ /**
69
+ * Called when a category or post tag is created or edited
70
+ * Does nothing except on taxonomies which are filterable
71
+ *
72
+ * @since 0.1
73
+ *
74
+ * @param int $term_id
75
+ * @param int $tt_id Term taxonomy id
76
+ * @param string $taxonomy
77
+ */
78
+ public function save_term( $term_id, $tt_id, $taxonomy ) {
79
+ if ( $this->model->is_translated_taxonomy( $taxonomy ) ) {
80
+
81
+ $lang = $this->model->term->get_language( $term_id );
82
+
83
+ if ( empty( $lang ) ) {
84
+ $this->set_default_language( $term_id, $taxonomy );
85
+ }
86
+
87
+ /**
88
+ * Fires after the term language and translations are saved
89
+ *
90
+ * @since 1.2
91
+ *
92
+ * @param int $term_id term id
93
+ * @param string $taxonomy taxonomy name
94
+ * @param array $translations the list of translations term ids
95
+ */
96
+ do_action( 'pll_save_term', $term_id, $taxonomy, $this->model->term->get_translations( $term_id ) );
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Get the language(s) to filter get_terms
102
+ *
103
+ * @since 1.7.6
104
+ *
105
+ * @param array $taxonomies queried taxonomies
106
+ * @param array $args get_terms arguments
107
+ * @return object|string|bool the language(s) to use in the filter, false otherwise
108
+ */
109
+ protected function get_queried_language( $taxonomies, $args ) {
110
+ // Does nothing except on taxonomies which are filterable
111
+ // Since WP 4.7, make sure not to filter wp_get_object_terms()
112
+ if ( ! $this->model->is_translated_taxonomy( $taxonomies ) || ! empty( $args['object_ids'] ) ) {
113
+ return false;
114
+ }
115
+
116
+ // If get_terms is queried with a 'lang' parameter
117
+ if ( isset( $args['lang'] ) ) {
118
+ return $args['lang'];
119
+ }
120
+
121
+ // On tags page, everything should be filtered according to the admin language filter except the parent dropdown
122
+ if ( 'edit-tags.php' === $GLOBALS['pagenow'] && empty( $args['class'] ) ) {
123
+ return $this->filter_lang;
124
+ }
125
+
126
+ return $this->curlang;
127
+ }
128
+
129
+ /**
130
+ * Adds language dependent cache domain when querying terms
131
+ * Useful as the 'lang' parameter is not included in cache key by WordPress
132
+ *
133
+ * @since 1.3
134
+ *
135
+ * @param array $args
136
+ * @param array $taxonomies
137
+ * @return array modified arguments
138
+ */
139
+ public function get_terms_args( $args, $taxonomies ) {
140
+ // Don't break _get_term_hierarchy()
141
+ if ( 'all' === $args['get'] && 'id' === $args['orderby'] && 'id=>parent' === $args['fields'] ) {
142
+ $args['lang'] = '';
143
+ }
144
+
145
+ if ( isset( $this->tax_query_lang ) ) {
146
+ $args['lang'] = empty( $this->tax_query_lang ) && ! empty( $this->curlang ) && ! empty( $args['slug'] ) ? $this->curlang->slug : $this->tax_query_lang;
147
+ }
148
+
149
+ if ( $lang = $this->get_queried_language( $taxonomies, $args ) ) {
150
+ $lang = is_string( $lang ) && strpos( $lang, ',' ) ? explode( ',', $lang ) : $lang;
151
+ $key = '_' . ( is_array( $lang ) ? implode( ',', $lang ) : $this->model->get_language( $lang )->slug );
152
+ $args['cache_domain'] = empty( $args['cache_domain'] ) ? 'pll' . $key : $args['cache_domain'] . $key;
153
+ }
154
+ return $args;
155
+ }
156
+
157
+ /**
158
+ * Filters categories and post tags by language(s) when needed on admin side
159
+ *
160
+ * @since 0.2
161
+ *
162
+ * @param array $clauses list of sql clauses
163
+ * @param array $taxonomies list of taxonomies
164
+ * @param array $args get_terms arguments
165
+ * @return array modified sql clauses
166
+ */
167
+ public function terms_clauses( $clauses, $taxonomies, $args ) {
168
+ $lang = $this->get_queried_language( $taxonomies, $args );
169
+ return $this->model->terms_clauses( $clauses, $lang );
170
+ }
171
+
172
+ /**
173
+ * Sets the WP_Term_Query language when doing a WP_Query
174
+ * Needed since WP 4.9
175
+ *
176
+ * @since 2.3.2
177
+ *
178
+ * @param object $query WP_Query object
179
+ */
180
+ public function set_tax_query_lang( $query ) {
181
+ $this->tax_query_lang = isset( $query->query_vars['lang'] ) ? $query->query_vars['lang'] : '';
182
+ }
183
+
184
+ /**
185
+ * Removes the WP_Term_Query language filter for WP_Query
186
+ * Needed since WP 4.9
187
+ *
188
+ * @since 2.3.2
189
+ */
190
+ public function unset_tax_query_lang() {
191
+ unset( $this->tax_query_lang );
192
+ }
193
+
194
+ /**
195
+ * Called when a category or post tag is deleted
196
+ * Deletes language and translations
197
+ *
198
+ * @since 0.1
199
+ *
200
+ * @param int $term_id
201
+ */
202
+ public function delete_term( $term_id ) {
203
+ $this->model->term->delete_translation( $term_id );
204
+ $this->model->term->delete_language( $term_id );
205
+ }
206
+ }
include/filters.php CHANGED
@@ -146,7 +146,7 @@ class PLL_Filters {
146
  $once = true; // avoid infinite loop
147
 
148
  $r = array(
149
- 'lang' => 0, // So this query is not filtered
150
  'numberposts' => -1,
151
  'nopaging' => true,
152
  'post_type' => $args['post_type'],
146
  $once = true; // avoid infinite loop
147
 
148
  $r = array(
149
+ 'lang' => 0, // So this query is not filtered
150
  'numberposts' => -1,
151
  'nopaging' => true,
152
  'post_type' => $args['post_type'],
include/language.php CHANGED
@@ -99,21 +99,70 @@ class PLL_Language {
99
 
100
  // Polylang builtin flags
101
  if ( ! empty( $this->flag_code ) && file_exists( POLYLANG_DIR . ( $file = '/flags/' . $this->flag_code . '.png' ) ) ) {
102
- $flags['flag']['url'] = esc_url_raw( plugins_url( $file, POLYLANG_FILE ) );
 
103
 
104
- // If base64 encoded flags are preferred
105
- if ( ! defined( 'PLL_ENCODED_FLAGS' ) || PLL_ENCODED_FLAGS ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
  $flags['flag']['src'] = 'data:image/png;base64,' . base64_encode( file_get_contents( POLYLANG_DIR . $file ) );
107
  } else {
108
- $flags['flag']['src'] = esc_url( plugins_url( $file, POLYLANG_FILE ) );
109
  }
110
  }
111
 
 
 
112
  // Custom flags ?
113
- if ( file_exists( PLL_LOCAL_DIR . ( $file = '/' . $this->locale . '.png' ) ) || file_exists( PLL_LOCAL_DIR . ( $file = '/' . $this->locale . '.jpg' ) ) ) {
114
- $url = content_url( '/polylang' . $file );
115
- $flags['custom_flag']['url'] = esc_url_raw( $url );
116
- $flags['custom_flag']['src'] = esc_url( $url );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
  }
118
 
119
  /**
@@ -139,12 +188,15 @@ class PLL_Language {
139
  * @param string $flag html markup of the flag or empty string
140
  * @param string $slug language code
141
  */
142
- $this->{$key} = apply_filters( 'pll_get_flag', empty( $flag['src'] ) ? '' :
143
- sprintf(
144
- '<img src="%s" title="%s" alt="%s" />',
 
145
  $flag['src'],
146
  esc_attr( $title ),
147
- esc_attr( $this->name )
 
 
148
  ),
149
  $this->slug
150
  );
@@ -166,13 +218,7 @@ class PLL_Language {
166
  }
167
 
168
  // Set url scheme, also for default flags
169
- if ( is_ssl() ) {
170
- $this->flag = str_replace( 'http://', 'https://', $this->flag );
171
- $this->flag_url = str_replace( 'http://', 'https://', $this->flag_url );
172
- } else {
173
- $this->flag = str_replace( 'https://', 'http://', $this->flag );
174
- $this->flag_url = str_replace( 'https://', 'http://', $this->flag_url );
175
- }
176
  }
177
 
178
  /**
@@ -205,15 +251,8 @@ class PLL_Language {
205
  * @since 1.6.4
206
  */
207
  public function set_home_url_scheme() {
208
- if ( is_ssl() ) {
209
- $this->home_url = str_replace( 'http://', 'https://', $this->home_url );
210
- $this->search_url = str_replace( 'http://', 'https://', $this->search_url );
211
- }
212
-
213
- else {
214
- $this->home_url = str_replace( 'https://', 'http://', $this->home_url );
215
- $this->search_url = str_replace( 'https://', 'http://', $this->search_url );
216
- }
217
  }
218
 
219
  /**
99
 
100
  // Polylang builtin flags
101
  if ( ! empty( $this->flag_code ) && file_exists( POLYLANG_DIR . ( $file = '/flags/' . $this->flag_code . '.png' ) ) ) {
102
+ $flags['flag']['url'] = $_url = plugins_url( $file, POLYLANG_FILE );
103
+ }
104
 
105
+ /**
106
+ * Filter flag informations
107
+ * 'url' => Flag url
108
+ * 'src' => Optional, src attribute value if different of the url, for example if base64 encoded
109
+ * 'width' => Optional, flag width in pixels
110
+ * 'height' => Optional, flag height in pixels
111
+ *
112
+ * @since 2.4
113
+ *
114
+ * @param array $flag Information about the flag
115
+ * @param string $code Flag code
116
+ */
117
+ $flags['flag'] = apply_filters( 'pll_flag', $flags['flag'], $this->flag_code );
118
+
119
+ if ( empty( $flags['flag']['src'] ) ) {
120
+ // If using predefined flags and base64 encoded flags are preferred
121
+ if ( $flags['flag']['url'] === $_url && ( ! defined( 'PLL_ENCODED_FLAGS' ) || PLL_ENCODED_FLAGS ) ) {
122
  $flags['flag']['src'] = 'data:image/png;base64,' . base64_encode( file_get_contents( POLYLANG_DIR . $file ) );
123
  } else {
124
+ $flags['flag']['src'] = esc_url( set_url_scheme( $flags['flag']['url'], 'relative' ) );
125
  }
126
  }
127
 
128
+ $flags['flag']['url'] = esc_url_raw( $flags['flag']['url'] );
129
+
130
  // Custom flags ?
131
+ $directories = array(
132
+ PLL_LOCAL_DIR,
133
+ get_stylesheet_directory() . '/polylang',
134
+ get_template_directory() . '/polylang',
135
+ );
136
+
137
+ foreach ( $directories as $dir ) {
138
+ if ( file_exists( $file = "{$dir}/{$this->locale}.png" ) || file_exists( $file = "{$dir}/{$this->locale}.jpg" ) || file_exists( $file = "{$dir}/{$this->locale}.svg" ) ) {
139
+ $flags['custom_flag']['url'] = site_url( '/' . str_replace( ABSPATH, '', $file ) );
140
+ break;
141
+ }
142
+ }
143
+
144
+ /**
145
+ * Filter the custom flag informations
146
+ * 'url' => Flag url
147
+ * 'src' => Optional, src attribute value if different of the url, for example if base64 encoded
148
+ * 'width' => Optional, flag width in pixels
149
+ * 'height' => Optional, flag height in pixels
150
+ *
151
+ * @since 2.4
152
+ *
153
+ * @param array $flag Information about the custom flag
154
+ * @param string $code Flag code
155
+ */
156
+ $flags['custom_flag'] = apply_filters( 'pll_custom_flag', empty( $flags['custom_flag'] ) ? null : $flags['custom_flag'], $this->flag_code );
157
+
158
+ if ( ! empty( $flags['custom_flag']['url'] ) ) {
159
+ if ( empty( $flags['custom_flag']['src'] ) ) {
160
+ $flags['custom_flag']['src'] = esc_url( set_url_scheme( $flags['custom_flag']['url'], 'relative' ) );
161
+ }
162
+
163
+ $flags['custom_flag']['url'] = esc_url_raw( $flags['custom_flag']['url'] );
164
+ } else {
165
+ unset( $flags['custom_flag'] );
166
  }
167
 
168
  /**
188
  * @param string $flag html markup of the flag or empty string
189
  * @param string $slug language code
190
  */
191
+ $this->{$key} = apply_filters(
192
+ 'pll_get_flag',
193
+ empty( $flag['src'] ) ? '' : sprintf(
194
+ '<img src="%s" title="%s" alt="%s"%s%s />',
195
  $flag['src'],
196
  esc_attr( $title ),
197
+ esc_attr( $this->name ),
198
+ empty( $flag['width'] ) ? '' : sprintf( ' width="%s"', (int) $flag['width'] ),
199
+ empty( $flag['height'] ) ? '' : sprintf( ' height="%s"', (int) $flag['height'] )
200
  ),
201
  $this->slug
202
  );
218
  }
219
 
220
  // Set url scheme, also for default flags
221
+ $this->flag_url = set_url_scheme( $this->flag_url );
 
 
 
 
 
 
222
  }
223
 
224
  /**
251
  * @since 1.6.4
252
  */
253
  public function set_home_url_scheme() {
254
+ $this->home_url = set_url_scheme( $this->home_url );
255
+ $this->search_url = set_url_scheme( $this->search_url );
 
 
 
 
 
 
 
256
  }
257
 
258
  /**
include/license.php CHANGED
@@ -21,7 +21,7 @@ class PLL_License {
21
  * @param string $author
22
  * @param string $api_url optional
23
  */
24
- function __construct( $file, $item_name, $version, $author, $api_url = null ) {
25
  $this->id = sanitize_title( $item_name );
26
  $this->file = $file;
27
  $this->name = $item_name;
21
  * @param string $author
22
  * @param string $api_url optional
23
  */
24
+ public function __construct( $file, $item_name, $version, $author, $api_url = null ) {
25
  $this->id = sanitize_title( $item_name );
26
  $this->file = $file;
27
  $this->name = $item_name;
include/links-default.php CHANGED
@@ -46,7 +46,7 @@ class PLL_Links_Default extends PLL_Links_Model {
46
  * @param string $url url to modify
47
  * @return string modified url
48
  */
49
- function remove_paged_from_link( $url ) {
50
  return remove_query_arg( 'paged', $url );
51
  }
52
 
46
  * @param string $url url to modify
47
  * @return string modified url
48
  */
49
+ public function remove_paged_from_link( $url ) {
50
  return remove_query_arg( 'paged', $url );
51
  }
52
 
include/links-directory.php CHANGED
@@ -79,7 +79,7 @@ class PLL_Links_Directory extends PLL_Links_Permalinks {
79
  * @param string $url url to modify
80
  * @return string modified url
81
  */
82
- function remove_language_from_link( $url ) {
83
  foreach ( $this->model->get_languages_list() as $language ) {
84
  if ( ! $this->options['hide_default'] || $this->options['default_lang'] != $language->slug ) {
85
  $languages[] = $language->slug;
@@ -141,7 +141,7 @@ class PLL_Links_Directory extends PLL_Links_Permalinks {
141
  *
142
  * @since 1.2
143
  */
144
- function add_permastruct() {
145
  // Language information always in front of the uri ( 'with_front' => false )
146
  // The 3rd parameter structure has been modified in WP 3.4
147
  // Leads to error 404 for pages when there is no language created yet
79
  * @param string $url url to modify
80
  * @return string modified url
81
  */
82
+ public function remove_language_from_link( $url ) {
83
  foreach ( $this->model->get_languages_list() as $language ) {
84
  if ( ! $this->options['hide_default'] || $this->options['default_lang'] != $language->slug ) {
85
  $languages[] = $language->slug;
141
  *
142
  * @since 1.2
143
  */
144
+ public function add_permastruct() {
145
  // Language information always in front of the uri ( 'with_front' => false )
146
  // The 3rd parameter structure has been modified in WP 3.4
147
  // Leads to error 404 for pages when there is no language created yet
include/links-domain.php CHANGED
@@ -68,7 +68,7 @@ class PLL_Links_Domain extends PLL_Links_Abstract_Domain {
68
  * @param object $lang PLL_Language object
69
  * @return string
70
  */
71
- function home_url( $lang ) {
72
  return trailingslashit( empty( $this->options['domains'][ $lang->slug ] ) ? $this->home : $this->options['domains'][ $lang->slug ] );
73
  }
74
 
68
  * @param object $lang PLL_Language object
69
  * @return string
70
  */
71
+ public function home_url( $lang ) {
72
  return trailingslashit( empty( $this->options['domains'][ $lang->slug ] ) ? $this->home : $this->options['domains'][ $lang->slug ] );
73
  }
74
 
include/model.php CHANGED
@@ -438,6 +438,7 @@ class PLL_Model {
438
  $where .= $wpdb->prepare( ' AND tt.parent = %d', $parent );
439
  }
440
 
 
441
  return $wpdb->get_var( $select . $join . $where );
442
  }
443
 
@@ -525,6 +526,7 @@ class PLL_Model {
525
  }
526
  }
527
 
 
528
  $res = $wpdb->get_results( $select . $join . $where . $groupby, ARRAY_A );
529
  foreach ( (array) $res as $row ) {
530
  $counts[ $row['term_taxonomy_id'] ] = $row['num_posts'];
@@ -611,10 +613,16 @@ class PLL_Model {
611
  $debug = debug_backtrace();
612
  $i = 1 + empty( $debug[1]['line'] ); // the file and line are in $debug[2] if the function was called using call_user_func
613
 
614
- trigger_error( sprintf(
615
- '%1$s was called incorrectly in %4$s on line %5$s: the call to $polylang->model->%1$s() has been deprecated in Polylang 1.8, use PLL()->model->%2$s->%3$s() instead.' . "\nError handler",
616
- $func, $o, $f, $debug[ $i ]['file'], $debug[ $i ]['line']
617
- ) );
 
 
 
 
 
 
618
  }
619
  return call_user_func_array( array( $this->$o, $f ), $args );
620
  }
438
  $where .= $wpdb->prepare( ' AND tt.parent = %d', $parent );
439
  }
440
 
441
+ // PHPCS:ignore WordPress.DB.PreparedSQL.NotPrepared
442
  return $wpdb->get_var( $select . $join . $where );
443
  }
444
 
526
  }
527
  }
528
 
529
+ // PHPCS:ignore WordPress.DB.PreparedSQL.NotPrepared
530
  $res = $wpdb->get_results( $select . $join . $where . $groupby, ARRAY_A );
531
  foreach ( (array) $res as $row ) {
532
  $counts[ $row['term_taxonomy_id'] ] = $row['num_posts'];
613
  $debug = debug_backtrace();
614
  $i = 1 + empty( $debug[1]['line'] ); // the file and line are in $debug[2] if the function was called using call_user_func
615
 
616
+ trigger_error(
617
+ sprintf(
618
+ '%1$s was called incorrectly in %4$s on line %5$s: the call to $polylang->model->%1$s() has been deprecated in Polylang 1.8, use PLL()->model->%2$s->%3$s() instead.' . "\nError handler",
619
+ $func,
620
+ $o,
621
+ $f,
622
+ $debug[ $i ]['file'],
623
+ $debug[ $i ]['line']
624
+ )
625
+ );
626
  }
627
  return call_user_func_array( array( $this->$o, $f ), $args );
628
  }
include/olt-manager.php CHANGED
@@ -27,7 +27,7 @@ class PLL_OLT_Manager {
27
 
28
  // Overriding load text domain only on front since WP 4.7
29
  // FIXME test get_user_locale for backward compatibility with WP < 4.7
30
- if ( is_admin() && function_exists( 'get_user_locale' ) ) {
31
  return;
32
  }
33
 
@@ -39,11 +39,9 @@ class PLL_OLT_Manager {
39
  add_filter( 'gettext', array( $this, 'gettext' ), 10, 3 );
40
  add_filter( 'gettext_with_context', array( $this, 'gettext_with_context' ), 10, 4 );
41
 
42
- if ( ! Polylang::is_ajax_on_front() ) {
43
- // Loads text domains
44
- add_action( 'pll_language_defined', array( $this, 'load_textdomains' ), 2 ); // After PLL_Frontend::pll_language_defined
45
- add_action( 'pll_no_language_defined', array( $this, 'load_textdomains' ) );
46
- }
47
  }
48
 
49
  /**
@@ -53,7 +51,7 @@ class PLL_OLT_Manager {
53
  *
54
  * @return object
55
  */
56
- static public function instance() {
57
  if ( empty( self::$instance ) ) {
58
  self::$instance = new self();
59
  }
@@ -218,9 +216,11 @@ class PLL_OLT_Manager {
218
  foreach ( $type->labels as $key => $label ) {
219
  if ( is_string( $label ) && isset( $this->labels[ $label ] ) ) {
220
  if ( empty( $translated[ $label ] ) ) {
 
221
  $type->labels->$key = $translated[ $label ] = isset( $this->labels[ $label ]['context'] ) ?
222
  _x( $label, $this->labels[ $label ]['context'], $this->labels[ $label ]['domain'] ) :
223
  __( $label, $this->labels[ $label ]['domain'] );
 
224
  }
225
  else {
226
  $type->labels->$key = $translated[ $label ];
27
 
28
  // Overriding load text domain only on front since WP 4.7
29
  // FIXME test get_user_locale for backward compatibility with WP < 4.7
30
+ if ( is_admin() && ! Polylang::is_ajax_on_front() && function_exists( 'get_user_locale' ) ) {
31
  return;
32
  }
33
 
39
  add_filter( 'gettext', array( $this, 'gettext' ), 10, 3 );
40
  add_filter( 'gettext_with_context', array( $this, 'gettext_with_context' ), 10, 4 );
41
 
42
+ // Loads text domains
43
+ add_action( 'pll_language_defined', array( $this, 'load_textdomains' ), 2 ); // After PLL_Frontend::pll_language_defined
44
+ add_action( 'pll_no_language_defined', array( $this, 'load_textdomains' ) );
 
 
45
  }
46
 
47
  /**
51
  *
52
  * @return object
53
  */
54
+ public static function instance() {
55
  if ( empty( self::$instance ) ) {
56
  self::$instance = new self();
57
  }
216
  foreach ( $type->labels as $key => $label ) {
217
  if ( is_string( $label ) && isset( $this->labels[ $label ] ) ) {
218
  if ( empty( $translated[ $label ] ) ) {
219
+ // PHPCS:disable WordPress.WP.I18n
220
  $type->labels->$key = $translated[ $label ] = isset( $this->labels[ $label ]['context'] ) ?
221
  _x( $label, $this->labels[ $label ]['context'], $this->labels[ $label ]['domain'] ) :
222
  __( $label, $this->labels[ $label ]['domain'] );
223
+ // PHPCS:enable
224
  }
225
  else {
226
  $type->labels->$key = $translated[ $label ];
include/pointer.php CHANGED
@@ -73,8 +73,8 @@ class PLL_Pointer {
73
 
74
  // All the buttons use the standard WP ajax action to remember the pointer has been dismissed
75
  foreach ( $this->args['buttons'] as $button ) {
76
- $b .= sprintf( "
77
- $( '<a>' ).addClass( '%s' ).html( '%s' ).css( 'margin-left', '10px' ).click( function() {
78
  $.post( ajaxurl, {
79
  pointer: '%s',
80
  action: 'dismiss-wp-pointer'
@@ -90,8 +90,8 @@ class PLL_Pointer {
90
  }
91
  }
92
 
93
- $js = sprintf( "
94
- //<![CDATA[
95
  jQuery( document ).ready( function( $ ) {
96
  var pointer = $( '#%s' ).pointer( {
97
  content: '%s',
73
 
74
  // All the buttons use the standard WP ajax action to remember the pointer has been dismissed
75
  foreach ( $this->args['buttons'] as $button ) {
76
+ $b .= sprintf(
77
+ "$( '<a>' ).addClass( '%s' ).html( '%s' ).css( 'margin-left', '10px' ).click( function() {
78
  $.post( ajaxurl, {
79
  pointer: '%s',
80
  action: 'dismiss-wp-pointer'
90
  }
91
  }
92
 
93
+ $js = sprintf(
94
+ "//<![CDATA[
95
  jQuery( document ).ready( function( $ ) {
96
  var pointer = $( '#%s' ).pointer( {
97
  content: '%s',
include/switcher.php CHANGED
@@ -17,7 +17,7 @@ class PLL_Switcher {
17
  * @param string $key optional either 'string' or 'default', defaults to 'string'
18
  * @return array list of switcher options strings or default values
19
  */
20
- static public function get_switcher_options( $type = 'widget', $key = 'string' ) {
21
  $options = array(
22
  'dropdown' => array( 'string' => __( 'Displays as dropdown', 'polylang' ), 'default' => 0 ),
23
  'show_names' => array( 'string' => __( 'Displays language names', 'polylang' ), 'default' => 1 ),
@@ -194,8 +194,8 @@ class PLL_Switcher {
194
  }
195
 
196
  // Accept only few valid characters for the urls_x variable name ( as the widget id includes '-' which is invalid )
197
- $out .= sprintf( '
198
- <script type="text/javascript">
199
  //<![CDATA[
200
  var %1$s = %2$s;
201
  document.getElementById( "%3$s" ).onchange = function() {
@@ -203,7 +203,9 @@ class PLL_Switcher {
203
  }
204
  //]]>
205
  </script>',
206
- 'urls_' . preg_replace( '#[^a-zA-Z0-9]#', '', $args['dropdown'] ), json_encode( $urls ), esc_js( $args['name'] )
 
 
207
  );
208
  }
209
 
17
  * @param string $key optional either 'string' or 'default', defaults to 'string'
18
  * @return array list of switcher options strings or default values
19
  */
20
+ public static function get_switcher_options( $type = 'widget', $key = 'string' ) {
21
  $options = array(
22
  'dropdown' => array( 'string' => __( 'Displays as dropdown', 'polylang' ), 'default' => 0 ),
23
  'show_names' => array( 'string' => __( 'Displays language names', 'polylang' ), 'default' => 1 ),
194
  }
195
 
196
  // Accept only few valid characters for the urls_x variable name ( as the widget id includes '-' which is invalid )
197
+ $out .= sprintf(
198
+ '<script type="text/javascript">
199
  //<![CDATA[
200
  var %1$s = %2$s;
201
  document.getElementById( "%3$s" ).onchange = function() {
203
  }
204
  //]]>
205
  </script>',
206
+ 'urls_' . preg_replace( '#[^a-zA-Z0-9]#', '', $args['dropdown'] ),
207
+ json_encode( $urls ),
208
+ esc_js( $args['name'] )
209
  );
210
  }
211
 
include/translated-post.php CHANGED
@@ -98,21 +98,24 @@ class PLL_Translated_Post extends PLL_Translated_Object {
98
  * @since 1.2
99
  */
100
  public function register_taxonomy() {
101
- register_taxonomy( 'language', $this->model->get_translated_post_types(), array(
102
- 'labels' => array(
103
- 'name' => __( 'Languages', 'polylang' ),
104
- 'singular_name' => __( 'Language', 'polylang' ),
105
- 'all_items' => __( 'All languages', 'polylang' ),
106
- ),
107
- // FIXME backward compatibility with WP 4.4.x: we must keep public to true for WP to accept our query var
108
- 'public' => version_compare( $GLOBALS['wp_version'], '4.4', '>=' ) && version_compare( $GLOBALS['wp_version'], '4.5', '<' ),
109
- 'show_ui' => false, // hide the taxonomy on admin side, needed for WP 4.4.x
110
- 'show_in_nav_menus' => false, // no metabox for nav menus, needed for WP 4.4.x
111
- 'publicly_queryable' => true, // since WP 4.5
112
- 'query_var' => 'lang',
113
- 'rewrite' => $this->model->options['force_lang'] < 2, // no rewrite for domains and sub-domains
114
- '_pll' => true, // polylang taxonomy
115
- ) );
 
 
 
116
  }
117
 
118
  /**
98
  * @since 1.2
99
  */
100
  public function register_taxonomy() {
101
+ register_taxonomy(
102
+ 'language',
103
+ $this->model->get_translated_post_types(),
104
+ array(
105
+ 'labels' => array(
106
+ 'name' => __( 'Languages', 'polylang' ),
107
+ 'singular_name' => __( 'Language', 'polylang' ),
108
+ 'all_items' => __( 'All languages', 'polylang' ),
109
+ ),
110
+ 'public' => false,
111
+ 'show_ui' => false, // hide the taxonomy on admin side, needed for WP 4.4.x
112
+ 'show_in_nav_menus' => false, // no metabox for nav menus, needed for WP 4.4.x
113
+ 'publicly_queryable' => true, // since WP 4.5
114
+ 'query_var' => 'lang',
115
+ 'rewrite' => $this->model->options['force_lang'] < 2, // no rewrite for domains and sub-domains
116
+ '_pll' => true, // polylang taxonomy
117
+ )
118
+ );
119
  }
120
 
121
  /**
include/translated-term.php CHANGED
@@ -192,7 +192,7 @@ class PLL_Translated_Term extends PLL_Translated_Object {
192
  *
193
  * @param array $ids An array of term IDs.
194
  */
195
- function clean_term_cache( $ids ) {
196
  clean_object_term_cache( $ids, 'term' );
197
  }
198
  }
192
  *
193
  * @param array $ids An array of term IDs.
194
  */
195
+ public function clean_term_cache( $ids ) {
196
  clean_object_term_cache( $ids, 'term' );
197
  }
198
  }
include/walker-dropdown.php CHANGED
@@ -6,7 +6,7 @@
6
  * @since 1.2
7
  */
8
  class PLL_Walker_Dropdown extends Walker {
9
- var $db_fields = array( 'parent' => 'parent', 'id' => 'id' );
10
 
11
  /**
12
  * Outputs one element
@@ -19,7 +19,7 @@ class PLL_Walker_Dropdown extends Walker {
19
  * @param array $args An array of additional arguments.
20
  * @param int $current_object_id ID of the current item.
21
  */
22
- function start_el( &$output, $element, $depth = 0, $args = array(), $current_object_id = 0 ) {
23
  $value = $args['value'];
24
  $output .= sprintf(
25
  "\t" . '<option value="%1$s"%2$s%3$s>%4$s</option>' . "\n",
@@ -42,7 +42,7 @@ class PLL_Walker_Dropdown extends Walker {
42
  * @param array $args An array of arguments.
43
  * @param string $output Passed by reference. Used to append additional content.
44
  */
45
- function display_element( $element, &$children_elements, $max_depth, $depth = 0, $args, &$output ) {
46
  $element = (object) $element; // Make sure we have an object
47
  $element->parent = $element->id = 0; // Don't care about this
48
  parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
@@ -67,7 +67,7 @@ class PLL_Walker_Dropdown extends Walker {
67
  * @param array $args
68
  * @return string
69
  */
70
- function walk( $elements, $args = array() ) {
71
  $output = '';
72
  $args = wp_parse_args( $args, array( 'value' => 'slug', 'name' => 'lang_choice' ) );
73
 
6
  * @since 1.2
7
  */
8
  class PLL_Walker_Dropdown extends Walker {
9
+ public $db_fields = array( 'parent' => 'parent', 'id' => 'id' );
10
 
11
  /**
12
  * Outputs one element
19
  * @param array $args An array of additional arguments.
20
  * @param int $current_object_id ID of the current item.
21
  */
22
+ public function start_el( &$output, $element, $depth = 0, $args = array(), $current_object_id = 0 ) {
23
  $value = $args['value'];
24
  $output .= sprintf(
25
  "\t" . '<option value="%1$s"%2$s%3$s>%4$s</option>' . "\n",
42
  * @param array $args An array of arguments.
43
  * @param string $output Passed by reference. Used to append additional content.
44
  */
45
+ public function display_element( $element, &$children_elements, $max_depth, $depth = 0, $args, &$output ) {
46
  $element = (object) $element; // Make sure we have an object
47
  $element->parent = $element->id = 0; // Don't care about this
48
  parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
67
  * @param array $args
68
  * @return string
69
  */
70
+ public function walk( $elements, $args = array() ) {
71
  $output = '';
72
  $args = wp_parse_args( $args, array( 'value' => 'slug', 'name' => 'lang_choice' ) );
73
 
include/walker-list.php CHANGED
@@ -6,7 +6,7 @@
6
  * @since 1.2
7
  */
8
  class PLL_Walker_List extends Walker {
9
- var $db_fields = array( 'parent' => 'parent', 'id' => 'id' );
10
 
11
  /**
12
  * Outputs one element
@@ -19,7 +19,7 @@ class PLL_Walker_List extends Walker {
19
  * @param array $args An array of additional arguments.
20
  * @param int $current_object_id ID of the current item.
21
  */
22
- function start_el( &$output, $element, $depth = 0, $args = array(), $current_object_id = 0 ) {
23
  $output .= sprintf(
24
  '%6$s<li class="%1$s"><a lang="%2$s" hreflang="%2$s" href="%3$s">%4$s%5$s</a></li>%7$s',
25
  esc_attr( implode( ' ', $element->classes ) ),
@@ -44,7 +44,7 @@ class PLL_Walker_List extends Walker {
44
  * @param array $args An array of arguments.
45
  * @param string $output Passed by reference. Used to append additional content.
46
  */
47
- function display_element( $element, &$children_elements, $max_depth, $depth = 0, $args, &$output ) {
48
  $element = (object) $element; // Make sure we have an object
49
  $element->parent = $element->id = 0; // Don't care about this
50
  parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
@@ -59,7 +59,7 @@ class PLL_Walker_List extends Walker {
59
  * @param array $args
60
  * @return string
61
  */
62
- function walk( $elements, $args = array() ) {
63
  return parent::walk( $elements, -1, $args );
64
  }
65
  }
6
  * @since 1.2
7
  */
8
  class PLL_Walker_List extends Walker {
9
+ public $db_fields = array( 'parent' => 'parent', 'id' => 'id' );
10
 
11
  /**
12
  * Outputs one element
19
  * @param array $args An array of additional arguments.
20
  * @param int $current_object_id ID of the current item.
21
  */
22
+ public function start_el( &$output, $element, $depth = 0, $args = array(), $current_object_id = 0 ) {
23
  $output .= sprintf(
24
  '%6$s<li class="%1$s"><a lang="%2$s" hreflang="%2$s" href="%3$s">%4$s%5$s</a></li>%7$s',
25
  esc_attr( implode( ' ', $element->classes ) ),
44
  * @param array $args An array of arguments.
45
  * @param string $output Passed by reference. Used to append additional content.
46
  */
47
+ public function display_element( $element, &$children_elements, $max_depth, $depth = 0, $args, &$output ) {
48
  $element = (object) $element; // Make sure we have an object
49
  $element->parent = $element->id = 0; // Don't care about this
50
  parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
59
  * @param array $args
60
  * @return string
61
  */
62
+ public function walk( $elements, $args = array() ) {
63
  return parent::walk( $elements, -1, $args );
64
  }
65
  }
include/widget-languages.php CHANGED
@@ -12,12 +12,12 @@ class PLL_Widget_Languages extends WP_Widget {
12
  *
13
  * @since 0.1
14
  */
15
- function __construct() {
16
  parent::__construct(
17
  'polylang',
18
  __( 'Language Switcher', 'polylang' ),
19
  array(
20
- 'description' => __( 'Displays a language switcher', 'polylang' ),
21
  'customize_selective_refresh' => true,
22
  )
23
  );
@@ -31,7 +31,7 @@ class PLL_Widget_Languages extends WP_Widget {
31
  * @param array $args Display arguments including before_title, after_title, before_widget, and after_widget.
32
  * @param array $instance The settings for the particular instance of the widget
33
  */
34
- function widget( $args, $instance ) {
35
  // Sets a unique id for dropdown
36
  $instance['dropdown'] = empty( $instance['dropdown'] ) ? 0 : $args['widget_id'];
37
 
@@ -63,7 +63,7 @@ class PLL_Widget_Languages extends WP_Widget {
63
  * @param array $old_instance Old settings for this instance
64
  * @return array Settings to save or bool false to cancel saving
65
  */
66
- function update( $new_instance, $old_instance ) {
67
  $instance['title'] = strip_tags( $new_instance['title'] );
68
  foreach ( array_keys( PLL_Switcher::get_switcher_options( 'widget' ) ) as $key ) {
69
  $instance[ $key ] = ! empty( $new_instance[ $key ] ) ? 1 : 0;
@@ -79,7 +79,7 @@ class PLL_Widget_Languages extends WP_Widget {
79
  *
80
  * @param array $instance Current settings
81
  */
82
- function form( $instance ) {
83
  // Default values
84
  $instance = wp_parse_args( (array) $instance, array_merge( array( 'title' => '' ), PLL_Switcher::get_switcher_options( 'widget', 'default' ) ) );
85
 
12
  *
13
  * @since 0.1
14
  */
15
+ public function __construct() {
16
  parent::__construct(
17
  'polylang',
18
  __( 'Language Switcher', 'polylang' ),
19
  array(
20
+ 'description' => __( 'Displays a language switcher', 'polylang' ),
21
  'customize_selective_refresh' => true,
22
  )
23
  );
31
  * @param array $args Display arguments including before_title, after_title, before_widget, and after_widget.
32
  * @param array $instance The settings for the particular instance of the widget
33
  */
34
+ public function widget( $args, $instance ) {
35
  // Sets a unique id for dropdown
36
  $instance['dropdown'] = empty( $instance['dropdown'] ) ? 0 : $args['widget_id'];
37
 
63
  * @param array $old_instance Old settings for this instance
64
  * @return array Settings to save or bool false to cancel saving
65
  */
66
+ public function update( $new_instance, $old_instance ) {
67
  $instance['title'] = strip_tags( $new_instance['title'] );
68
  foreach ( array_keys( PLL_Switcher::get_switcher_options( 'widget' ) ) as $key ) {
69
  $instance[ $key ] = ! empty( $new_instance[ $key ] ) ? 1 : 0;
79
  *
80
  * @param array $instance Current settings
81
  */
82
+ public function form( $instance ) {
83
  // Default values
84
  $instance = wp_parse_args( (array) $instance, array_merge( array( 'title' => '' ), PLL_Switcher::get_switcher_options( 'widget', 'default' ) ) );
85
 
install/install.php CHANGED
@@ -22,13 +22,17 @@ class PLL_Install extends PLL_Install_Base {
22
  load_plugin_textdomain( 'polylang', false, basename( POLYLANG_DIR ) . '/languages' ); // plugin i18n
23
 
24
  if ( version_compare( $wp_version, PLL_MIN_WP_VERSION, '<' ) ) {
25
- die( sprintf( '<p style = "font-family: sans-serif; font-size: 12px; color: #333; margin: -5px">%s</p>',
26
- /* translators: %1$s and %2$s are WordPress version numbers */
27
- sprintf( esc_html__( 'You are using WordPress %1$s. Polylang requires at least WordPress %2$s.', 'polylang' ),
28
- esc_html( $wp_version ),
29
- PLL_MIN_WP_VERSION
 
 
 
 
30
  )
31
- ) );
32
  }
33
  $this->do_for_all_blogs( 'activate', $networkwide );
34
  }
@@ -40,7 +44,7 @@ class PLL_Install extends PLL_Install_Base {
40
  *
41
  * return array
42
  */
43
- static public function get_default_options() {
44
  return array(
45
  'browser' => 1, // Default language for the front page is set by browser preference
46
  'rewrite' => 1, // Remove /language/ in permalinks ( was the opposite before 0.7.2 )
22
  load_plugin_textdomain( 'polylang', false, basename( POLYLANG_DIR ) . '/languages' ); // plugin i18n
23
 
24
  if ( version_compare( $wp_version, PLL_MIN_WP_VERSION, '<' ) ) {
25
+ die(
26
+ sprintf(
27
+ '<p style = "font-family: sans-serif; font-size: 12px; color: #333; margin: -5px">%s</p>',
28
+ sprintf(
29
+ /* translators: %1$s and %2$s are WordPress version numbers */
30
+ esc_html__( 'You are using WordPress %1$s. Polylang requires at least WordPress %2$s.', 'polylang' ),
31
+ esc_html( $wp_version ),
32
+ PLL_MIN_WP_VERSION
33
+ )
34
  )
35
+ );
36
  }
37
  $this->do_for_all_blogs( 'activate', $networkwide );
38
  }
44
  *
45
  * return array
46
  */
47
+ public static function get_default_options() {
48
  return array(
49
  'browser' => 1, // Default language for the front page is set by browser preference
50
  'rewrite' => 1, // Remove /language/ in permalinks ( was the opposite before 0.7.2 )
install/upgrade.php CHANGED
@@ -193,7 +193,7 @@ class PLL_Upgrade {
193
  }
194
 
195
  // Get all terms with a language defined
196
- $terms = $wpdb->get_results( "SELECT term_id, meta_value FROM $wpdb->termmeta WHERE meta_key = '_language'" );
197
  foreach ( $terms as $key => $term ) {
198
  $terms[ $key ] = $wpdb->prepare( '( %d, %d )', $term->term_id, $lang_tt_ids[ $term->meta_value ] );
199
  }
@@ -202,7 +202,8 @@ class PLL_Upgrade {
202
 
203
  // Assign language to each term
204
  if ( ! empty( $terms ) ) {
205
- $wpdb->query( "INSERT INTO $wpdb->term_relationships ( object_id, term_taxonomy_id ) VALUES " . implode( ',', $terms ) );
 
206
  }
207
 
208
  // Translations
@@ -211,6 +212,7 @@ class PLL_Upgrade {
211
  $terms = $slugs = $tts = $trs = array();
212
 
213
  // Get all translated objects
 
214
  $objects = $wpdb->get_col( "SELECT DISTINCT meta_value FROM {$wpdb->$table} WHERE meta_key = '_translations'" );
215
 
216
  if ( empty( $objects ) ) {
@@ -229,10 +231,12 @@ class PLL_Upgrade {
229
 
230
  // Insert terms
231
  if ( ! empty( $terms ) ) {
232
- $wpdb->query( "INSERT INTO $wpdb->terms ( slug, name ) VALUES " . implode( ',', $terms ) );
 
233
  }
234
 
235
  // Get all terms with their term_id
 
236
  $terms = $wpdb->get_results( "SELECT term_id, slug FROM $wpdb->terms WHERE slug IN ( " . implode( ',', $slugs ) . ' )' );
237
 
238
  // Prepare terms taxonomy relationship
@@ -244,7 +248,8 @@ class PLL_Upgrade {
244
 
245
  // Insert term_taxonomy
246
  if ( ! empty( $tts ) ) {
247
- $wpdb->query( "INSERT INTO $wpdb->term_taxonomy ( term_id, taxonomy, description ) VALUES " . implode( ',', $tts ) );
 
248
  }
249
 
250
  // Get all terms with term_taxonomy_id
@@ -264,7 +269,8 @@ class PLL_Upgrade {
264
 
265
  // Insert term_relationships
266
  if ( ! empty( $trs ) ) {
267
- $wpdb->query( "INSERT INTO $wpdb->term_relationships ( object_id, term_taxonomy_id ) VALUES " . implode( ',', $trs ) );
 
268
  }
269
  }
270
 
@@ -318,11 +324,15 @@ class PLL_Upgrade {
318
 
319
  // Create the menu items for the language switcher
320
  if ( ! empty( $has_switcher ) ) {
321
- $menu_item_db_id = wp_update_nav_menu_item( $translations[ $lang->slug ], 0, array(
322
- 'menu-item-title' => __( 'Language switcher', 'polylang' ),
323
- 'menu-item-url' => '#pll_switcher',
324
- 'menu-item-status' => 'publish',
325
- ) );
 
 
 
 
326
 
327
  update_post_meta( $menu_item_db_id, '_pll_menu_item', $switch_options );
328
  }
@@ -488,7 +498,7 @@ class PLL_Upgrade {
488
  *
489
  * @since 1.6
490
  */
491
- static function download_language_packs() {
492
  $languages = pll_languages_list( array( 'fields' => 'locale' ) );
493
 
494
  // Prevents upgrade if the .po file is already here. Let WP manage the upgrades :)
@@ -517,7 +527,7 @@ class PLL_Upgrade {
517
 
518
  if ( ! empty( $translations_to_load ) ) {
519
  require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
520
- $upgrader = new Language_Pack_Upgrader( new Automatic_Upgrader_Skin );
521
  $upgrader->bulk_upgrade( $translations_to_load, array( 'clear_update_cache' => false ) );
522
  }
523
  }
193
  }
194
 
195
  // Get all terms with a language defined
196
+ $terms = $wpdb->get_results( "SELECT term_id, meta_value FROM {$wpdb->termmeta} WHERE meta_key = '_language'" );
197
  foreach ( $terms as $key => $term ) {
198
  $terms[ $key ] = $wpdb->prepare( '( %d, %d )', $term->term_id, $lang_tt_ids[ $term->meta_value ] );
199
  }
202
 
203
  // Assign language to each term
204
  if ( ! empty( $terms ) ) {
205
+ // PHPCS:ignore WordPress.DB.PreparedSQL.NotPrepared
206
+ $wpdb->query( "INSERT INTO {$wpdb->term_relationships} ( object_id, term_taxonomy_id ) VALUES " . implode( ',', $terms ) );
207
  }
208
 
209
  // Translations
212
  $terms = $slugs = $tts = $trs = array();
213
 
214
  // Get all translated objects
215
+ // PHPCS:ignore WordPress.DB.PreparedSQL.NotPrepared
216
  $objects = $wpdb->get_col( "SELECT DISTINCT meta_value FROM {$wpdb->$table} WHERE meta_key = '_translations'" );
217
 
218
  if ( empty( $objects ) ) {
231
 
232
  // Insert terms
233
  if ( ! empty( $terms ) ) {
234
+ // PHPCS:ignore WordPress.DB.PreparedSQL.NotPrepared
235
+ $wpdb->query( "INSERT INTO {$wpdb->terms} ( slug, name ) VALUES " . implode( ',', $terms ) );
236
  }
237
 
238
  // Get all terms with their term_id
239
+ // PHPCS:ignore WordPress.DB.PreparedSQL.NotPrepared
240
  $terms = $wpdb->get_results( "SELECT term_id, slug FROM $wpdb->terms WHERE slug IN ( " . implode( ',', $slugs ) . ' )' );
241
 
242
  // Prepare terms taxonomy relationship
248
 
249
  // Insert term_taxonomy
250
  if ( ! empty( $tts ) ) {
251
+ // PHPCS:ignore WordPress.DB.PreparedSQL.NotPrepared
252
+ $wpdb->query( "INSERT INTO {$wpdb->term_taxonomy} ( term_id, taxonomy, description ) VALUES " . implode( ',', $tts ) );
253
  }
254
 
255
  // Get all terms with term_taxonomy_id
269
 
270
  // Insert term_relationships
271
  if ( ! empty( $trs ) ) {
272
+ // PHPCS:ignore WordPress.DB.PreparedSQL.NotPrepared
273
+ $wpdb->query( "INSERT INTO {$wpdb->term_relationships} ( object_id, term_taxonomy_id ) VALUES " . implode( ',', $trs ) );
274
  }
275
  }
276
 
324
 
325
  // Create the menu items for the language switcher
326
  if ( ! empty( $has_switcher ) ) {
327
+ $menu_item_db_id = wp_update_nav_menu_item(
328
+ $translations[ $lang->slug ],
329
+ 0,
330
+ array(
331
+ 'menu-item-title' => __( 'Language switcher', 'polylang' ),
332
+ 'menu-item-url' => '#pll_switcher',
333
+ 'menu-item-status' => 'publish',
334
+ )
335
+ );
336
 
337
  update_post_meta( $menu_item_db_id, '_pll_menu_item', $switch_options );
338
  }
498
  *
499
  * @since 1.6
500
  */
501
+ public static function download_language_packs() {
502
  $languages = pll_languages_list( array( 'fields' => 'locale' ) );
503
 
504
  // Prevents upgrade if the .po file is already here. Let WP manage the upgrades :)
527
 
528
  if ( ! empty( $translations_to_load ) ) {
529
  require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
530
+ $upgrader = new Language_Pack_Upgrader( new Automatic_Upgrader_Skin() );
531
  $upgrader->bulk_upgrade( $translations_to_load, array( 'clear_update_cache' => false ) );
532
  }
533
  }
js/admin.js CHANGED
@@ -24,14 +24,15 @@ jQuery( document ).ready(function( $ ) {
24
  // extends selectmenu to add flags in menu items
25
  $.widget( "custom.iconselectmenu", $.ui.selectmenu, {
26
  _renderItem: function( ul, item ) {
27
- var li = $( "<li>", { text: item.label } );
 
 
28
 
29
- if ( item.value ) {
30
- $( "<img>", {
31
- src: pll_flag_base_url + item.value + '.png',
32
- "class": "ui-icon"
33
- }).appendTo( li );
34
- }
35
 
36
  return li.appendTo( ul );
37
  }
@@ -39,11 +40,14 @@ jQuery( document ).ready(function( $ ) {
39
 
40
  // allows to display the flag for the selected menu item
41
  function add_icon( event, ui ) {
42
- var value = $( this ).val();
43
- if ( value ) {
 
 
44
  var txt = $( this ).iconselectmenu( "widget" ).children( ":last" );
45
- var img = $( '<img class="ui-icon" >' ).appendTo( txt );
46
- img.attr( "src", pll_flag_base_url + value + '.png' );
 
47
  }
48
  }
49
 
24
  // extends selectmenu to add flags in menu items
25
  $.widget( "custom.iconselectmenu", $.ui.selectmenu, {
26
  _renderItem: function( ul, item ) {
27
+ var li = $( "<li>", { text: item.label } );
28
+ var el = $( item.element );
29
+ var url = el.data( "url" );
30
 
31
+ if ( url ) {
32
+ var w = el.data( "width" );
33
+ var h = el.data( "height" );
34
+ $( "<img class='ui-icon' />" ).prop( "src", url ).prop( "width", w ).prop( "height", h ).appendTo( li );
35
+ }
 
36
 
37
  return li.appendTo( ul );
38
  }
40
 
41
  // allows to display the flag for the selected menu item
42
  function add_icon( event, ui ) {
43
+ var sel = $( this ).find( ":selected" );
44
+ var url = sel.data( "url" );
45
+
46
+ if ( url ) {
47
  var txt = $( this ).iconselectmenu( "widget" ).children( ":last" );
48
+ var w = sel.data( "width" );
49
+ var h = sel.data( "height" );
50
+ $( "<img class='ui-icon' />" ).prop( "src", url ).prop( "width", w ).prop( "height", h ).appendTo( txt );
51
  }
52
  }
53
 
js/admin.min.js CHANGED
@@ -1 +1 @@
1
- jQuery(document).ready(function(e){function t(){var t=e(this).val();if(t){var n=e(this).iconselectmenu("widget").children(":last"),i=e('<img class="ui-icon" >').appendTo(n);i.attr("src",pll_flag_base_url+t+".png")}}var n;e("table.languages").on({focusin:function(){clearTimeout(n),focusedRowActions=e(this).find(".row-actions"),e(".row-actions").not(this).removeClass("visible"),focusedRowActions.addClass("visible")},focusout:function(){n=setTimeout(function(){focusedRowActions.removeClass("visible")},30)}},"tr"),e.widget("custom.iconselectmenu",e.ui.selectmenu,{_renderItem:function(t,n){var i=e("<li>",{text:n.label});return n.value&&e("<img>",{src:pll_flag_base_url+n.value+".png","class":"ui-icon"}).appendTo(i),i.appendTo(t)}}),e("#flag_list").iconselectmenu({create:t,select:t}),e("#lang_list").change(function(){var n=e(this).val().split(":"),i=e("option:selected",this).text().split(" - ");e("#lang_slug").val(n[0]),e("#lang_locale").val(n[1]),e('input[name="rtl"]').val([n[2]]),e("#lang_name").val(i[0]),e('#flag_list option[value="'+n[3]+'"]').attr("selected","selected"),e("#flag_list").iconselectmenu("destroy").iconselectmenu({create:t,select:t})}),e(".translation input").keypress(function(t){13===t.keyCode&&(t.preventDefault(),e("#submit").click())}),e("#the-list").on("click",".configure>a",function(){return e(".pll-configure").hide().prev().show(),e(this).closest("tr").hide().next().show(),!1}),e("#the-list").on("click",".cancel",function(){e(this).closest("tr").hide().prev().show()}),e("#the-list").on("click",".save",function(){var t=e(this).closest("tr"),n=t.attr("id").split("-"),i={action:"pll_save_options",pll_ajax_settings:!0,module:n[n.length-1],_pll_nonce:e("#_pll_nonce").val()};i=t.find(":input").serialize()+"&"+e.param(i),e.post(ajaxurl,i,function(n){var i=wpAjax.parseAjaxResponse(n,"ajax-response");e.each(i.responses,function(){switch(this.what){case"license-update":e("#pll-license-"+this.data).replaceWith(this.supplemental.html);break;case"success":t.hide().prev().show();case"error":e(".settings-error").remove(),e("h1").after(this.data),e(".notice.is-dismissible").each(function(){var t=e(this),n=e('<button type="button" class="notice-dismiss"><span class="screen-reader-text"></span></button>'),i=commonL10n.dismiss||"";n.find(".screen-reader-text").text(i),t.append(n),n.on("click.wp-dismiss-notice",function(n){n.preventDefault(),t.fadeTo(100,0,function(){e(this).slideUp(100,function(){e(this).remove()})})})})}})})}),e(".pll-configure").keypress(function(t){13===t.keyCode&&(t.preventDefault(),e(this).find(".save").click()),27===t.keyCode&&(t.preventDefault(),e(this).find(".cancel").click())}),e("input[name='force_lang']").change(function(){function t(e,t){t?e.show():e.hide()}var n=e(this).val();t(e("#pll-domains-table"),3==n),t(e("#pll-hide-default"),3>n),t(e("#pll-rewrite"),2>n),t(e("#pll-redirect-lang"),2>n)}),e(".pll-deactivate-license").on("click",function(){var t={action:"pll_deactivate_license",pll_ajax_settings:!0,id:e(this).attr("id"),_pll_nonce:e("#_pll_nonce").val()};e.post(ajaxurl,t,function(t){e("#pll-license-"+t.id).replaceWith(t.html)})})});
1
+ jQuery(document).ready(function(e){function t(){var t=e(this).find(":selected"),i=t.data("url");if(i){var n=e(this).iconselectmenu("widget").children(":last"),s=t.data("width"),l=t.data("height");e("<img class='ui-icon' />").prop("src",i).prop("width",s).prop("height",l).appendTo(n)}}var i;e("table.languages").on({focusin:function(){clearTimeout(i),focusedRowActions=e(this).find(".row-actions"),e(".row-actions").not(this).removeClass("visible"),focusedRowActions.addClass("visible")},focusout:function(){i=setTimeout(function(){focusedRowActions.removeClass("visible")},30)}},"tr"),e.widget("custom.iconselectmenu",e.ui.selectmenu,{_renderItem:function(t,i){var n=e("<li>",{text:i.label}),s=e(i.element),l=s.data("url");if(l){var a=s.data("width"),c=s.data("height");e("<img class='ui-icon' />").prop("src",l).prop("width",a).prop("height",c).appendTo(n)}return n.appendTo(t)}}),e("#flag_list").iconselectmenu({create:t,select:t}),e("#lang_list").change(function(){var i=e(this).val().split(":"),n=e("option:selected",this).text().split(" - ");e("#lang_slug").val(i[0]),e("#lang_locale").val(i[1]),e('input[name="rtl"]').val([i[2]]),e("#lang_name").val(n[0]),e('#flag_list option[value="'+i[3]+'"]').attr("selected","selected"),e("#flag_list").iconselectmenu("destroy").iconselectmenu({create:t,select:t})}),e(".translation input").keypress(function(t){13===t.keyCode&&(t.preventDefault(),e("#submit").click())}),e("#the-list").on("click",".configure>a",function(){return e(".pll-configure").hide().prev().show(),e(this).closest("tr").hide().next().show(),!1}),e("#the-list").on("click",".cancel",function(){e(this).closest("tr").hide().prev().show()}),e("#the-list").on("click",".save",function(){var t=e(this).closest("tr"),i=t.attr("id").split("-"),n={action:"pll_save_options",pll_ajax_settings:!0,module:i[i.length-1],_pll_nonce:e("#_pll_nonce").val()};n=t.find(":input").serialize()+"&"+e.param(n),e.post(ajaxurl,n,function(i){var n=wpAjax.parseAjaxResponse(i,"ajax-response");e.each(n.responses,function(){switch(this.what){case"license-update":e("#pll-license-"+this.data).replaceWith(this.supplemental.html);break;case"success":t.hide().prev().show();case"error":e(".settings-error").remove(),e("h1").after(this.data),e(".notice.is-dismissible").each(function(){var t=e(this),i=e('<button type="button" class="notice-dismiss"><span class="screen-reader-text"></span></button>'),n=commonL10n.dismiss||"";i.find(".screen-reader-text").text(n),t.append(i),i.on("click.wp-dismiss-notice",function(i){i.preventDefault(),t.fadeTo(100,0,function(){e(this).slideUp(100,function(){e(this).remove()})})})})}})})}),e(".pll-configure").keypress(function(t){13===t.keyCode&&(t.preventDefault(),e(this).find(".save").click()),27===t.keyCode&&(t.preventDefault(),e(this).find(".cancel").click())}),e("input[name='force_lang']").change(function(){function t(e,t){t?e.show():e.hide()}var i=e(this).val();t(e("#pll-domains-table"),3==i),t(e("#pll-hide-default"),3>i),t(e("#pll-rewrite"),2>i),t(e("#pll-redirect-lang"),2>i)}),e(".pll-deactivate-license").on("click",function(){var t={action:"pll_deactivate_license",pll_ajax_settings:!0,id:e(this).attr("id"),_pll_nonce:e("#_pll_nonce").val()};e.post(ajaxurl,t,function(t){e("#pll-license-"+t.id).replaceWith(t.html)})})});
js/classic-editor.js ADDED
@@ -0,0 +1,157 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // tag suggest in metabox
2
+ (function( $ ){
3
+ $.ajaxPrefilter(function( options, originalOptions, jqXHR ) {
4
+ if ( 'string' === typeof options.data && -1 !== options.url.indexOf( 'action=ajax-tag-search' ) && ( lang = $( '.post_lang_choice' ).val() ) ) {
5
+ options.data = 'lang=' + lang + '&' + options.data;
6
+ }
7
+ });
8
+ })( jQuery );
9
+
10
+ // overrides tagBox.get
11
+ (function( $ ){
12
+ // overrides function to add the language
13
+ tagBox.get = function( id ) {
14
+ var tax = id.substr( id.indexOf( '-' ) + 1 );
15
+
16
+ // add the language in the $_POST variable
17
+ var data = {
18
+ action: 'get-tagcloud',
19
+ lang: $( '.post_lang_choice' ).val(),
20
+ tax: tax
21
+ }
22
+
23
+ $.post( ajaxurl, data, function( r, stat ) {
24
+ if ( 0 == r || 'success' != stat ) {
25
+ r = wpAjax.broken;
26
+ }
27
+
28
+ r = $( '<div id="tagcloud-' + tax + '" class="the-tagcloud">' + r + '</div>' );
29
+ $( 'a', r ).click(function(){
30
+ tagBox.flushTags( $( this ).closest( '.inside' ).children( '.tagsdiv' ), this );
31
+ return false;
32
+ });
33
+
34
+ // add an if else condition to allow modifying the tags outputed when switching the language
35
+ if ( v = $( '.the-tagcloud' ).css( 'display' ) ) {
36
+ $( '.the-tagcloud' ).replaceWith( r );
37
+ $( '.the-tagcloud' ).css( 'display', v );
38
+ }
39
+ else {
40
+ $( '#' + id ).after( r );
41
+ }
42
+ });
43
+ }
44
+ })( jQuery );
45
+
46
+ jQuery( document ).ready(function( $ ) {
47
+ // collect taxonomies - code partly copied from WordPress
48
+ var taxonomies = new Array();
49
+ $( '.categorydiv' ).each(function(){
50
+ var this_id = $( this ).attr( 'id' ), taxonomyParts, taxonomy;
51
+
52
+ taxonomyParts = this_id.split( '-' );
53
+ taxonomyParts.shift();
54
+ taxonomy = taxonomyParts.join( '-' );
55
+ taxonomies.push( taxonomy ); // store the taxonomy for future use
56
+
57
+ // add our hidden field in the new category form - for each hierarchical taxonomy
58
+ // to set the language when creating a new category
59
+ $( '#' + taxonomy + '-add-submit' ).before( $( '<input />' )
60
+ .attr( 'type', 'hidden' )
61
+ .attr( 'id', taxonomy + '-lang' )
62
+ .attr( 'name', 'term_lang_choice' )
63
+ .attr( 'value', $( '.post_lang_choice' ).val() )
64
+ );
65
+ });
66
+
67
+ // ajax for changing the post's language in the languages metabox
68
+ $( '.post_lang_choice' ).change(function() {
69
+ var value = $( this ).val();
70
+ var lang = $( this ).children( 'option[value="' + value + '"]' ).attr( 'lang' );
71
+ var dir = $( '.pll-translation-column > span[lang="' + lang + '"]' ).attr( 'dir' );
72
+
73
+ var data = {
74
+ action: 'post_lang_choice',
75
+ lang: value,
76
+ post_type: $( '#post_type' ).val(),
77
+ taxonomies: taxonomies,
78
+ post_id: $( '#post_ID' ).val(),
79
+ _pll_nonce: $( '#_pll_nonce' ).val()
80
+ }
81
+
82
+ $.post( ajaxurl, data , function( response ) {
83
+ var res = wpAjax.parseAjaxResponse( response, 'ajax-response' );
84
+ $.each( res.responses, function() {
85
+ switch ( this.what ) {
86
+ case 'translations': // translations fields
87
+ $( '.translations' ).html( this.data );
88
+ init_translations();
89
+ break;
90
+ case 'taxonomy': // categories metabox for posts
91
+ var tax = this.data;
92
+ $( '#' + tax + 'checklist' ).html( this.supplemental.all );
93
+ $( '#' + tax + 'checklist-pop' ).html( this.supplemental.populars );
94
+ $( '#new' + tax + '_parent' ).replaceWith( this.supplemental.dropdown );
95
+ $( '#' + tax + '-lang' ).val( $( '.post_lang_choice' ).val() ); // hidden field
96
+ break;
97
+ case 'pages': // parent dropdown list for pages
98
+ $( '#parent_id' ).html( this.data );
99
+ break;
100
+ case 'flag': // flag in front of the select dropdown
101
+ $( '.pll-select-flag' ).html( this.data );
102
+ break;
103
+ case 'permalink': // Sample permalink
104
+ var div = $( '#edit-slug-box' );
105
+ if ( '-1' != this.data && div.children().length ) {
106
+ div.html( this.data );
107
+ }
108
+ break;
109
+ }
110
+ });
111
+
112
+ // modifies the language in the tag cloud
113
+ $( '.tagcloud-link' ).each(function() {
114
+ var id = $( this ).attr( 'id' );
115
+ tagBox.get( id );
116
+ });
117
+
118
+ // Modifies the text direction
119
+ $( 'body' ).removeClass( 'pll-dir-rtl' ).removeClass( 'pll-dir-ltr' ).addClass( 'pll-dir-' + dir );
120
+ $( '#content_ifr' ).contents().find( 'html' ).attr( 'lang', lang ).attr( 'dir', dir );
121
+ $( '#content_ifr' ).contents().find( 'body' ).attr( 'dir', dir );
122
+ });
123
+ });
124
+
125
+ // translations autocomplete input box
126
+ function init_translations() {
127
+ $( '.tr_lang' ).each(function(){
128
+ var tr_lang = $( this ).attr( 'id' ).substring( 8 );
129
+ var td = $( this ).parent().parent().siblings( '.pll-edit-column' );
130
+
131
+ $( this ).autocomplete({
132
+ minLength: 0,
133
+
134
+ source: ajaxurl + '?action=pll_posts_not_translated' +
135
+ '&post_language=' + $( '.post_lang_choice' ).val() +
136
+ '&translation_language=' + tr_lang +
137
+ '&post_type=' + $( '#post_type' ).val() +
138
+ '&_pll_nonce=' + $( '#_pll_nonce' ).val(),
139
+
140
+ select: function( event, ui ) {
141
+ $( '#htr_lang_' + tr_lang ).val( ui.item.id );
142
+ td.html( ui.item.link );
143
+ },
144
+ });
145
+
146
+ // when the input box is emptied
147
+ $( this ).blur(function() {
148
+ if ( ! $( this ).val() ) {
149
+ $( '#htr_lang_' + tr_lang ).val( 0 );
150
+ td.html( td.siblings( '.hidden' ).children().clone() );
151
+ }
152
+ });
153
+ });
154
+ }
155
+
156
+ init_translations();
157
+ });
js/classic-editor.min.js ADDED
@@ -0,0 +1 @@
 
1
+ !function(t){t.ajaxPrefilter(function(a){"string"==typeof a.data&&-1!==a.url.indexOf("action=ajax-tag-search")&&(lang=t(".post_lang_choice").val())&&(a.data="lang="+lang+"&"+a.data)})}(jQuery),function(t){tagBox.get=function(a){var l=a.substr(a.indexOf("-")+1),n={action:"get-tagcloud",lang:t(".post_lang_choice").val(),tax:l};t.post(ajaxurl,n,function(n,e){0!=n&&"success"==e||(n=wpAjax.broken),n=t('<div id="tagcloud-'+l+'" class="the-tagcloud">'+n+"</div>"),t("a",n).click(function(){return tagBox.flushTags(t(this).closest(".inside").children(".tagsdiv"),this),!1}),(v=t(".the-tagcloud").css("display"))?(t(".the-tagcloud").replaceWith(n),t(".the-tagcloud").css("display",v)):t("#"+a).after(n)})}}(jQuery),jQuery(document).ready(function(t){function a(){t(".tr_lang").each(function(){var a=t(this).attr("id").substring(8),l=t(this).parent().parent().siblings(".pll-edit-column");t(this).autocomplete({minLength:0,source:ajaxurl+"?action=pll_posts_not_translated&post_language="+t(".post_lang_choice").val()+"&translation_language="+a+"&post_type="+t("#post_type").val()+"&_pll_nonce="+t("#_pll_nonce").val(),select:function(n,e){t("#htr_lang_"+a).val(e.item.id),l.html(e.item.link)}}),t(this).blur(function(){t(this).val()||(t("#htr_lang_"+a).val(0),l.html(l.siblings(".hidden").children().clone()))})})}var l=new Array;t(".categorydiv").each(function(){var a,n,e=t(this).attr("id");a=e.split("-"),a.shift(),n=a.join("-"),l.push(n),t("#"+n+"-add-submit").before(t("<input />").attr("type","hidden").attr("id",n+"-lang").attr("name","term_lang_choice").attr("value",t(".post_lang_choice").val()))}),t(".post_lang_choice").change(function(){var n=t(this).val(),e=t(this).children('option[value="'+n+'"]').attr("lang"),i=t('.pll-translation-column > span[lang="'+e+'"]').attr("dir"),s={action:"post_lang_choice",lang:n,post_type:t("#post_type").val(),taxonomies:l,post_id:t("#post_ID").val(),_pll_nonce:t("#_pll_nonce").val()};t.post(ajaxurl,s,function(l){var n=wpAjax.parseAjaxResponse(l,"ajax-response");t.each(n.responses,function(){switch(this.what){case"translations":t(".translations").html(this.data),a();break;case"taxonomy":var l=this.data;t("#"+l+"checklist").html(this.supplemental.all),t("#"+l+"checklist-pop").html(this.supplemental.populars),t("#new"+l+"_parent").replaceWith(this.supplemental.dropdown),t("#"+l+"-lang").val(t(".post_lang_choice").val());break;case"pages":t("#parent_id").html(this.data);break;case"flag":t(".pll-select-flag").html(this.data);break;case"permalink":var n=t("#edit-slug-box");"-1"!=this.data&&n.children().length&&n.html(this.data)}}),t(".tagcloud-link").each(function(){var a=t(this).attr("id");tagBox.get(a)}),t("body").removeClass("pll-dir-rtl").removeClass("pll-dir-ltr").addClass("pll-dir-"+i),t("#content_ifr").contents().find("html").attr("lang",e).attr("dir",i),t("#content_ifr").contents().find("body").attr("dir",i)})}),a()});
js/post.js CHANGED
@@ -1,49 +1,12 @@
1
- // tag suggest
2
- // valid for both tag metabox and quick edit
3
  (function( $ ){
4
  $.ajaxPrefilter(function( options, originalOptions, jqXHR ) {
5
- if ( 'string' === typeof options.data && ( -1 !== options.url.indexOf( 'action=ajax-tag-search' ) || -1 !== options.data.indexOf( 'action=ajax-tag-search' ) ) && ( ( lang = $( '.post_lang_choice' ).val() ) || ( lang = $( ':input[name="inline_lang_choice"]' ).val() ) ) ) {
6
  options.data = 'lang=' + lang + '&' + options.data;
7
  }
8
  });
9
  })( jQuery );
10
 
11
- // overrides tagBox.get
12
- (function( $ ){
13
- // overrides function to add the language
14
- tagBox.get = function( id ) {
15
- var tax = id.substr( id.indexOf( '-' ) + 1 );
16
-
17
- // add the language in the $_POST variable
18
- var data = {
19
- action: 'get-tagcloud',
20
- lang: $( '.post_lang_choice' ).val(),
21
- tax: tax
22
- }
23
-
24
- $.post( ajaxurl, data, function( r, stat ) {
25
- if ( 0 == r || 'success' != stat ) {
26
- r = wpAjax.broken;
27
- }
28
-
29
- r = $( '<div id="tagcloud-' + tax + '" class="the-tagcloud">' + r + '</div>' );
30
- $( 'a', r ).click(function(){
31
- tagBox.flushTags( $( this ).closest( '.inside' ).children( '.tagsdiv' ), this );
32
- return false;
33
- });
34
-
35
- // add an if else condition to allow modifying the tags outputed when switching the language
36
- if ( v = $( '.the-tagcloud' ).css( 'display' ) ) {
37
- $( '.the-tagcloud' ).replaceWith( r );
38
- $( '.the-tagcloud' ).css( 'display', v );
39
- }
40
- else {
41
- $( '#' + id ).after( r );
42
- }
43
- });
44
- }
45
- })( jQuery );
46
-
47
  // quick edit
48
  (function( $ ) {
49
  $( document ).bind( 'DOMNodeInserted', function( e ) {
@@ -139,116 +102,3 @@
139
  }
140
  });
141
  })( jQuery );
142
-
143
- jQuery( document ).ready(function( $ ) {
144
- // collect taxonomies - code partly copied from WordPress
145
- var taxonomies = new Array();
146
- $( '.categorydiv' ).each(function(){
147
- var this_id = $( this ).attr( 'id' ), taxonomyParts, taxonomy;
148
-
149
- taxonomyParts = this_id.split( '-' );
150
- taxonomyParts.shift();
151
- taxonomy = taxonomyParts.join( '-' );
152
- taxonomies.push( taxonomy ); // store the taxonomy for future use
153
-
154
- // add our hidden field in the new category form - for each hierarchical taxonomy
155
- // to set the language when creating a new category
156
- $( '#' + taxonomy + '-add-submit' ).before( $( '<input />' )
157
- .attr( 'type', 'hidden' )
158
- .attr( 'id', taxonomy + '-lang' )
159
- .attr( 'name', 'term_lang_choice' )
160
- .attr( 'value', $( '.post_lang_choice' ).val() )
161
- );
162
- });
163
-
164
- // ajax for changing the post's language in the languages metabox
165
- $( '.post_lang_choice' ).change(function() {
166
- var value = $( this ).val();
167
- var lang = $( this ).children( 'option[value="' + value + '"]' ).attr( 'lang' );
168
- var dir = $( '.pll-translation-column > span[lang="' + lang + '"]' ).attr( 'dir' );
169
-
170
- var data = {
171
- action: 'post_lang_choice',
172
- lang: value,
173
- post_type: $( '#post_type' ).val(),
174
- taxonomies: taxonomies,
175
- post_id: $( '#post_ID' ).val(),
176
- _pll_nonce: $( '#_pll_nonce' ).val()
177
- }
178
-
179
- $.post( ajaxurl, data , function( response ) {
180
- var res = wpAjax.parseAjaxResponse( response, 'ajax-response' );
181
- $.each( res.responses, function() {
182
- switch ( this.what ) {
183
- case 'translations': // translations fields
184
- $( '.translations' ).html( this.data );
185
- init_translations();
186
- break;
187
- case 'taxonomy': // categories metabox for posts
188
- var tax = this.data;
189
- $( '#' + tax + 'checklist' ).html( this.supplemental.all );
190
- $( '#' + tax + 'checklist-pop' ).html( this.supplemental.populars );
191
- $( '#new' + tax + '_parent' ).replaceWith( this.supplemental.dropdown );
192
- $( '#' + tax + '-lang' ).val( $( '.post_lang_choice' ).val() ); // hidden field
193
- break;
194
- case 'pages': // parent dropdown list for pages
195
- $( '#parent_id' ).html( this.data );
196
- break;
197
- case 'flag': // flag in front of the select dropdown
198
- $( '.pll-select-flag' ).html( this.data );
199
- break;
200
- case 'permalink': // Sample permalink
201
- var div = $( '#edit-slug-box' );
202
- if ( '-1' != this.data && div.children().length ) {
203
- div.html( this.data );
204
- }
205
- break;
206
- }
207
- });
208
-
209
- // modifies the language in the tag cloud
210
- $( '.tagcloud-link' ).each(function() {
211
- var id = $( this ).attr( 'id' );
212
- tagBox.get( id );
213
- });
214
-
215
- // Modifies the text direction
216
- $( 'body' ).removeClass( 'pll-dir-rtl' ).removeClass( 'pll-dir-ltr' ).addClass( 'pll-dir-' + dir );
217
- $( '#content_ifr' ).contents().find( 'html' ).attr( 'lang', lang ).attr( 'dir', dir );
218
- $( '#content_ifr' ).contents().find( 'body' ).attr( 'dir', dir );
219
- });
220
- });
221
-
222
- // translations autocomplete input box
223
- function init_translations() {
224
- $( '.tr_lang' ).each(function(){
225
- var tr_lang = $( this ).attr( 'id' ).substring( 8 );
226
- var td = $( this ).parent().parent().siblings( '.pll-edit-column' );
227
-
228
- $( this ).autocomplete({
229
- minLength: 0,
230
-
231
- source: ajaxurl + '?action=pll_posts_not_translated' +
232
- '&post_language=' + $( '.post_lang_choice' ).val() +
233
- '&translation_language=' + tr_lang +
234
- '&post_type=' + $( '#post_type' ).val() +
235
- '&_pll_nonce=' + $( '#_pll_nonce' ).val(),
236
-
237
- select: function( event, ui ) {
238
- $( '#htr_lang_' + tr_lang ).val( ui.item.id );
239
- td.html( ui.item.link );
240
- },
241
- });
242
-
243
- // when the input box is emptied
244
- $( this ).blur(function() {
245
- if ( ! $( this ).val() ) {
246
- $( '#htr_lang_' + tr_lang ).val( 0 );
247
- td.html( td.siblings( '.hidden' ).children().clone() );
248
- }
249
- });
250
- });
251
- }
252
-
253
- init_translations();
254
- });
1
+ // tag suggest in quick edit
 
2
  (function( $ ){
3
  $.ajaxPrefilter(function( options, originalOptions, jqXHR ) {
4
+ if ( 'string' === typeof options.data && -1 !== options.data.indexOf( 'action=ajax-tag-search' ) && ( lang = $( ':input[name="inline_lang_choice"]' ).val() ) ) {
5
  options.data = 'lang=' + lang + '&' + options.data;
6
  }
7
  });
8
  })( jQuery );
9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  // quick edit
11
  (function( $ ) {
12
  $( document ).bind( 'DOMNodeInserted', function( e ) {
102
  }
103
  });
104
  })( jQuery );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
js/post.min.js CHANGED
@@ -1 +1 @@
1
- !function(t){t.ajaxPrefilter(function(a,n,e){"string"!=typeof a.data||-1===a.url.indexOf("action=ajax-tag-search")&&-1===a.data.indexOf("action=ajax-tag-search")||!(lang=t(".post_lang_choice").val())&&!(lang=t(':input[name="inline_lang_choice"]').val())||(a.data="lang="+lang+"&"+a.data)})}(jQuery),function(t){tagBox.get=function(a){var n=a.substr(a.indexOf("-")+1),e={action:"get-tagcloud",lang:t(".post_lang_choice").val(),tax:n};t.post(ajaxurl,e,function(e,i){(0==e||"success"!=i)&&(e=wpAjax.broken),e=t('<div id="tagcloud-'+n+'" class="the-tagcloud">'+e+"</div>"),t("a",e).click(function(){return tagBox.flushTags(t(this).closest(".inside").children(".tagsdiv"),this),!1}),(v=t(".the-tagcloud").css("display"))?(t(".the-tagcloud").replaceWith(e),t(".the-tagcloud").css("display",v)):t("#"+a).after(e)})}}(jQuery),function(t){t(document).bind("DOMNodeInserted",function(a){function n(a){"undefined"!=typeof pll_term_languages&&t.each(pll_term_languages,function(n,e){t.each(e,function(e,i){t.each(i,function(i){id="#"+e+"-"+pll_term_languages[n][e][i],a==n?t(id).show():t(id).hide()})})})}function e(a){"undefined"!=typeof pll_page_languages&&t.each(pll_page_languages,function(n,e){t.each(e,function(e){v=t('#post_parent option[value="'+pll_page_languages[n][e]+'"]'),a==n?v.show():v.hide()})})}var i=t(a.target);if("inline-edit"==i.attr("id")){var l=i.prev().attr("id").replace("post-","");if(l>0){var s=i.find(':input[name="inline_lang_choice"]'),o=t("#lang_"+l).html();s.val(o),n(o),e(o),s.change(function(){n(t(this).val()),e(t(this).val())})}}})}(jQuery),function(t){t(document).ajaxSuccess(function(a,n,e){function i(a){var n=new Array;t(".translation_"+a).each(function(){n.push(t(this).parent().parent().attr("id").substring(5))});var e={action:"pll_update_post_rows",post_id:a,translations:n.join(","),post_type:t("input[name='post_type']").val(),screen:t("input[name='screen']").val(),_pll_nonce:t("input[name='_inline_edit']").val()};t.post(ajaxurl,e,function(a){if(a){var n=wpAjax.parseAjaxResponse(a,"ajax-response");t.each(n.responses,function(){"row"==this.what&&t("#post-"+this.supplemental.post_id).replaceWith(this.data)})}})}if("string"==typeof e.data){var l=wpAjax.unserialize(e.data);"undefined"!=typeof l.action&&"inline-save"==l.action&&i(l.post_ID)}})}(jQuery),jQuery(document).ready(function(t){function a(){t(".tr_lang").each(function(){var a=t(this).attr("id").substring(8),n=t(this).parent().parent().siblings(".pll-edit-column");t(this).autocomplete({minLength:0,source:ajaxurl+"?action=pll_posts_not_translated&post_language="+t(".post_lang_choice").val()+"&translation_language="+a+"&post_type="+t("#post_type").val()+"&_pll_nonce="+t("#_pll_nonce").val(),select:function(e,i){t("#htr_lang_"+a).val(i.item.id),n.html(i.item.link)}}),t(this).blur(function(){t(this).val()||(t("#htr_lang_"+a).val(0),n.html(n.siblings(".hidden").children().clone()))})})}var n=new Array;t(".categorydiv").each(function(){var a,e,i=t(this).attr("id");a=i.split("-"),a.shift(),e=a.join("-"),n.push(e),t("#"+e+"-add-submit").before(t("<input />").attr("type","hidden").attr("id",e+"-lang").attr("name","term_lang_choice").attr("value",t(".post_lang_choice").val()))}),t(".post_lang_choice").change(function(){var e=t(this).val(),i=t(this).children('option[value="'+e+'"]').attr("lang"),l=t('.pll-translation-column > span[lang="'+i+'"]').attr("dir"),s={action:"post_lang_choice",lang:e,post_type:t("#post_type").val(),taxonomies:n,post_id:t("#post_ID").val(),_pll_nonce:t("#_pll_nonce").val()};t.post(ajaxurl,s,function(n){var e=wpAjax.parseAjaxResponse(n,"ajax-response");t.each(e.responses,function(){switch(this.what){case"translations":t(".translations").html(this.data),a();break;case"taxonomy":var n=this.data;t("#"+n+"checklist").html(this.supplemental.all),t("#"+n+"checklist-pop").html(this.supplemental.populars),t("#new"+n+"_parent").replaceWith(this.supplemental.dropdown),t("#"+n+"-lang").val(t(".post_lang_choice").val());break;case"pages":t("#parent_id").html(this.data);break;case"flag":t(".pll-select-flag").html(this.data);break;case"permalink":var e=t("#edit-slug-box");"-1"!=this.data&&e.children().length&&e.html(this.data)}}),t(".tagcloud-link").each(function(){var a=t(this).attr("id");tagBox.get(a)}),t("body").removeClass("pll-dir-rtl").removeClass("pll-dir-ltr").addClass("pll-dir-"+l),t("#content_ifr").contents().find("html").attr("lang",i).attr("dir",l),t("#content_ifr").contents().find("body").attr("dir",l)})}),a()});
1
+ !function(n){n.ajaxPrefilter(function(a){"string"==typeof a.data&&-1!==a.data.indexOf("action=ajax-tag-search")&&(lang=n(':input[name="inline_lang_choice"]').val())&&(a.data="lang="+lang+"&"+a.data)})}(jQuery),function(n){n(document).bind("DOMNodeInserted",function(a){function e(a){"undefined"!=typeof pll_term_languages&&n.each(pll_term_languages,function(e,t){n.each(t,function(t,i){n.each(i,function(i){id="#"+t+"-"+pll_term_languages[e][t][i],a==e?n(id).show():n(id).hide()})})})}function t(a){"undefined"!=typeof pll_page_languages&&n.each(pll_page_languages,function(e,t){n.each(t,function(t){v=n('#post_parent option[value="'+pll_page_languages[e][t]+'"]'),a==e?v.show():v.hide()})})}var i=n(a.target);if("inline-edit"==i.attr("id")){var o=i.prev().attr("id").replace("post-","");if(o>0){var l=i.find(':input[name="inline_lang_choice"]'),p=n("#lang_"+o).html();l.val(p),e(p),t(p),l.change(function(){e(n(this).val()),t(n(this).val())})}}})}(jQuery),function(n){n(document).ajaxSuccess(function(a,e,t){function i(a){var e=new Array;n(".translation_"+a).each(function(){e.push(n(this).parent().parent().attr("id").substring(5))});var t={action:"pll_update_post_rows",post_id:a,translations:e.join(","),post_type:n("input[name='post_type']").val(),screen:n("input[name='screen']").val(),_pll_nonce:n("input[name='_inline_edit']").val()};n.post(ajaxurl,t,function(a){if(a){var e=wpAjax.parseAjaxResponse(a,"ajax-response");n.each(e.responses,function(){"row"==this.what&&n("#post-"+this.supplemental.post_id).replaceWith(this.data)})}})}if("string"==typeof t.data){var o=wpAjax.unserialize(t.data);"undefined"!=typeof o.action&&"inline-save"==o.action&&i(o.post_ID)}})}(jQuery);
js/widgets.js ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery( function( $ ) {
2
+ var widgets_container, widgets_selector, flags;
3
+
4
+ if ( 'undefined' !== typeof pll_widgets && pll_widgets.hasOwnProperty( 'flags' ) ) {
5
+ flags = pll_widgets.flags;
6
+ }
7
+
8
+ /**
9
+ * Prepend widget titles with a flag once a language is selected.
10
+ * @param {object} widget The widget element.
11
+ * @return {void} Nothing.
12
+ */
13
+ function add_flag( widget ) {
14
+ if ( ! flags ) {
15
+ return;
16
+ }
17
+ widget = $( widget );
18
+ var title = $( '.widget-top .widget-title h3', widget ),
19
+ locale = $( '.pll-lang-choice option:selected', widget ).val(),
20
+ icon = ( locale && flags.hasOwnProperty( locale ) ) ? flags[ locale ] : null;
21
+
22
+ if ( icon ) {
23
+ icon += ' &nbsp; ';
24
+ var current = $( '.pll-lang', title );
25
+ if ( current.length ) {
26
+ current.html( icon );
27
+ } else {
28
+ flag = '<span class="pll-lang">' + icon + '</span>';
29
+ title.prepend( flag );
30
+ }
31
+ } else {
32
+ $( '.pll-lang', title ).remove();
33
+ }
34
+ }
35
+
36
+ if ( 'undefined' !== typeof wp.customize ) {
37
+
38
+ widgets_container = $( '#customize-controls' );
39
+ widgets_selector = '.customize-control .widget';
40
+
41
+ /**
42
+ * WP Customizer add control listener.
43
+ *
44
+ * @link https://wordpress.stackexchange.com/questions/256536/callback-after-wordpress-customizer-complete-loading
45
+ *
46
+ * @param {object} control The control type.
47
+ * @return {void} Nothing.
48
+ */
49
+ function customize_add_flag( control ) {
50
+ if ( ! control.extended( wp.customize.Widgets.WidgetControl ) ) {
51
+ return;
52
+ }
53
+
54
+ /*
55
+ * Make sure the widget's contents are embedded; normally this is done
56
+ * when the control is expanded, for DOM performance reasons.
57
+ */
58
+ control.embedWidgetContent();
59
+
60
+ // Now we know for sure the widget is fully embedded.
61
+ add_flag( control.container.find( '.widget' ) );
62
+ }
63
+ wp.customize.control.each( customize_add_flag );
64
+ wp.customize.control.bind( 'add', customize_add_flag );
65
+
66
+ } else {
67
+
68
+ widgets_container = $( '#widgets-right' );
69
+ widgets_selector = '.widget';
70
+
71
+ }
72
+
73
+ // Add flags on load.
74
+ $( widgets_selector, widgets_container ).each( function() {
75
+ add_flag( this );
76
+ } );
77
+
78
+ // Update flags.
79
+ widgets_container.on( 'change', '.pll-lang-choice', function() {
80
+ add_flag( $( this ).parents( '.widget' ) );
81
+ } );
82
+
83
+ } );
js/widgets.min.js ADDED
@@ -0,0 +1 @@
 
1
+ jQuery(function(e){function t(t){if(o){t=e(t);var n=e(".widget-top .widget-title h3",t),l=e(".pll-lang-choice option:selected",t).val(),i=l&&o.hasOwnProperty(l)?o[l]:null;if(i){i+=" &nbsp; ";var d=e(".pll-lang",n);d.length?d.html(i):(flag='<span class="pll-lang">'+i+"</span>",n.prepend(flag))}else e(".pll-lang",n).remove()}}function n(e){e.extended(wp.customize.Widgets.WidgetControl)&&(e.embedWidgetContent(),t(e.container.find(".widget")))}var l,i,o;"undefined"!=typeof pll_widgets&&pll_widgets.hasOwnProperty("flags")&&(o=pll_widgets.flags),"undefined"!=typeof wp.customize?(l=e("#customize-controls"),i=".customize-control .widget",wp.customize.control.each(n),wp.customize.control.bind("add",n)):(l=e("#widgets-right"),i=".widget"),e(i,l).each(function(){t(this)}),l.on("change",".pll-lang-choice",function(){t(e(this).parents(".widget"))})});
modules/plugins/cache-compat.php CHANGED
@@ -32,8 +32,8 @@ class PLL_Cache_Compat {
32
  */
33
  public function add_cookie_script() {
34
  $domain = ( 2 == PLL()->options['force_lang'] ) ? parse_url( PLL()->links_model->home, PHP_URL_HOST ) : COOKIE_DOMAIN;
35
- $js = sprintf( '
36
- (function() {
37
  var expirationDate = new Date();
38
  expirationDate.setTime( expirationDate.getTime() + %d * 1000 );
39
  document.cookie = "%s=%s; expires=" + expirationDate.toUTCString() + "; path=%s%s";
32
  */
33
  public function add_cookie_script() {
34
  $domain = ( 2 == PLL()->options['force_lang'] ) ? parse_url( PLL()->links_model->home, PHP_URL_HOST ) : COOKIE_DOMAIN;
35
+ $js = sprintf(
36
+ '(function() {
37
  var expirationDate = new Date();
38
  expirationDate.setTime( expirationDate.getTime() + %d * 1000 );
39
  document.cookie = "%s=%s; expires=" + expirationDate.toUTCString() + "; path=%s%s";
modules/plugins/featured-content.php ADDED
@@ -0,0 +1,130 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Manages the compatibility with the Jetpack Twenty Fourteenn Featured content
5
+ *
6
+ * @since 2.4
7
+ */
8
+ class PLL_Featured_Content {
9
+ /**
10
+ * Constructor
11
+ *
12
+ * @since 2.4
13
+ */
14
+ public function __construct() {
15
+ add_filter( 'transient_featured_content_ids', array( $this, 'featured_content_ids' ) );
16
+ add_filter( 'pll_filter_query_excluded_query_vars', array( $this, 'fix_featured_posts' ) );
17
+ add_filter( 'option_featured-content', array( $this, 'option_featured_content' ) );
18
+ }
19
+
20
+ /**
21
+ * Tell whether the theme supports the featured content
22
+ *
23
+ * @since 2.4
24
+ *
25
+ * @return bool
26
+ */
27
+ protected function is_active() {
28
+ return 'twentyfourteen' === get_template() || ( defined( 'JETPACK__VERSION' ) && get_theme_support( 'featured-content' ) );
29
+ }
30
+
31
+ /**
32
+ * Get the theme featured posts filter name
33
+ *
34
+ * @since 2.4
35
+ *
36
+ * @return string
37
+ */
38
+ protected function get_featured_posts_filter() {
39
+ $theme_support = get_theme_support( 'featured-content' );
40
+
41
+ if ( isset( $theme_support[0]['featured_content_filter'] ) ) {
42
+ $theme_support[0]['filter'] = $theme_support[0]['featured_content_filter'];
43
+ unset( $theme_support[0]['featured_content_filter'] );
44
+ }
45
+
46
+ return $theme_support[0]['filter'];
47
+ }
48
+
49
+ /**
50
+ * Rewrites the function Featured_Content::get_featured_post_ids()
51
+ *
52
+ * @since 1.4
53
+ *
54
+ * @param array $featured_ids Featured posts ids
55
+ * @return array modified featured posts ids ( include all languages )
56
+ */
57
+ public function featured_content_ids( $featured_ids ) {
58
+ if ( ! $this->is_active() || ! did_action( 'pll_init' ) || false !== $featured_ids ) {
59
+ return $featured_ids;
60
+ }
61
+
62
+ $settings = Featured_Content::get_setting();
63
+
64
+ if ( ! $term = wpcom_vip_get_term_by( 'name', $settings['tag-name'], 'post_tag' ) ) {
65
+ return $featured_ids;
66
+ }
67
+
68
+ // Get featured tag translations
69
+ $tags = PLL()->model->term->get_translations( $term->term_id );
70
+ $ids = array();
71
+
72
+ // Query for featured posts in all languages
73
+ // One query per language to get the correct number of posts per language
74
+ foreach ( $tags as $tag ) {
75
+ $_ids = get_posts(
76
+ array(
77
+ 'lang' => 0, // avoid language filters
78
+ 'fields' => 'ids',
79
+ 'numberposts' => Featured_Content::$max_posts,
80
+ 'tax_query' => array(
81
+ array(
82
+ 'taxonomy' => 'post_tag',
83
+ 'terms' => (int) $tag,
84
+ ),
85
+ ),
86
+ )
87
+ );
88
+
89
+ $ids = array_merge( $ids, $_ids );
90
+ }
91
+
92
+ $ids = array_map( 'absint', $ids );
93
+ set_transient( 'featured_content_ids', $ids );
94
+
95
+ return $ids;
96
+ }
97
+
98
+ /**
99
+ * Allow to filter the featured posts query per language
100
+ *
101
+ * @since 2.4
102
+ *
103
+ * @param array $excludes Query vars excluded from the language filter
104
+ * @return array
105
+ */
106
+ public function fix_featured_posts( $excludes ) {
107
+ if ( $this->is_active() && PLL() instanceof PLL_Frontend && doing_filter( $this->get_featured_posts_filter() ) ) {
108
+ $excludes = array_diff( $excludes, array( 'post__in' ) );
109
+ }
110
+ return $excludes;
111
+ }
112
+
113
+ /**
114
+ * Translates the featured tag id in featured content settings
115
+ * Mainly to allow hiding it when requested in featured content options
116
+ * Acts only on frontend
117
+ *
118
+ * @since 1.4
119
+ *
120
+ * @param array $settings featured content settings
121
+ * @return array modified $settings
122
+ */
123
+ public function option_featured_content( $settings ) {
124
+ if ( $this->is_active() && PLL() instanceof PLL_Frontend && $settings['tag-id'] && $tr = pll_get_term( $settings['tag-id'] ) ) {
125
+ $settings['tag-id'] = $tr;
126
+ }
127
+
128
+ return $settings;
129
+ }
130
+ }
modules/plugins/jetpack.php CHANGED
@@ -116,7 +116,7 @@ class PLL_Jetpack {
116
  * @param string $post_id Post ID of the post for which we are retrieving Related Posts.
117
  * @return array
118
  */
119
- function jetpack_relatedposts_filter_filters( $filters, $post_id ) {
120
  $slug = sanitize_title( pll_get_post_language( $post_id, 'slug' ) );
121
  $filters[] = array( 'term' => array( 'taxonomy.language.slug' => $slug ) );
122
  return $filters;
116
  * @param string $post_id Post ID of the post for which we are retrieving Related Posts.
117
  * @return array
118
  */
119
+ public function jetpack_relatedposts_filter_filters( $filters, $post_id ) {
120
  $slug = sanitize_title( pll_get_post_language( $post_id, 'slug' ) );
121
  $filters[] = array( 'term' => array( 'taxonomy.language.slug' => $slug ) );
122
  return $filters;
modules/plugins/plugins-compat.php CHANGED
@@ -31,15 +31,12 @@ class PLL_Plugins_Compat {
31
  // Aqua Resizer
32
  add_filter( 'pll_home_url_black_list', array( $this, 'aq_home_url_black_list' ) );
33
 
34
- // Twenty Fourteen
35
- add_filter( 'transient_featured_content_ids', array( $this, 'twenty_fourteen_featured_content_ids' ) );
36
- add_filter( 'option_featured-content', array( $this, 'twenty_fourteen_option_featured_content' ) );
37
-
38
  // Duplicate post
39
  add_filter( 'option_duplicate_post_taxonomies_blacklist', array( $this, 'duplicate_post_taxonomies_blacklist' ) );
40
 
41
  // Jetpack
42
- $this->jetpack = new PLL_Jetpack(); // Must be loaded before the plugin is active
 
43
 
44
  // WP Sweep
45
  add_filter( 'wp_sweep_excluded_taxonomies', array( $this, 'wp_sweep_excluded_taxonomies' ) );
@@ -51,9 +48,15 @@ class PLL_Plugins_Compat {
51
  add_filter( 'get_terms_args', array( $this, 'no_category_base_get_terms_args' ), 5 ); // Before adding cache domain
52
 
53
  // WordPress MU Domain Mapping
54
- if ( function_exists( 'redirect_to_mapped_domain' ) && ! get_site_option( 'dm_no_primary_domain' ) ) {
55
- remove_action( 'template_redirect', 'redirect_to_mapped_domain' );
56
- add_action( 'template_redirect', array( $this, 'dm_redirect_to_mapped_domain' ) );
 
 
 
 
 
 
57
  }
58
  }
59
 
@@ -64,7 +67,7 @@ class PLL_Plugins_Compat {
64
  *
65
  * @return object
66
  */
67
- static public function instance() {
68
  if ( empty( self::$instance ) ) {
69
  self::$instance = new self();
70
  }
@@ -106,6 +109,11 @@ class PLL_Plugins_Compat {
106
  if ( ( 'Divi' === get_template() || defined( 'ET_BUILDER_PLUGIN_VERSION' ) ) && class_exists( 'PLL_Divi_Builder' ) ) {
107
  $this->divi_builder = new PLL_Divi_Builder();
108
  }
 
 
 
 
 
109
  }
110
 
111
  /**
@@ -127,7 +135,7 @@ class PLL_Plugins_Compat {
127
  *
128
  * @since 1.2
129
  */
130
- function maybe_wordpress_importer() {
131
  if ( defined( 'WP_LOAD_IMPORTERS' ) && class_exists( 'WP_Import' ) ) {
132
  remove_action( 'admin_init', 'wordpress_importer_init' );
133
  add_action( 'admin_init', array( $this, 'wordpress_importer_init' ) );
@@ -140,7 +148,7 @@ class PLL_Plugins_Compat {
140
  *
141
  * @since 1.2
142
  */
143
- function wordpress_importer_init() {
144
  $class = new ReflectionClass( 'WP_Import' );
145
  load_plugin_textdomain( 'wordpress-importer', false, basename( dirname( $class->getFileName() ) ) . '/languages' );
146
 
@@ -158,7 +166,7 @@ class PLL_Plugins_Compat {
158
  * @param array $terms an array of arrays containing terms information form the WXR file
159
  * @return array
160
  */
161
- function wp_import_terms( $terms ) {
162
  include PLL_SETTINGS_INC . '/languages.php';
163
 
164
  foreach ( $terms as $key => $term ) {
@@ -211,73 +219,6 @@ class PLL_Plugins_Compat {
211
  }
212
  }
213
 
214
- /**
215
- * Twenty Fourteen
216
- * Rewrites the function Featured_Content::get_featured_post_ids()
217
- *
218
- * @since 1.4
219
- *
220
- * @param array $featured_ids featured posts ids
221
- * @return array modified featured posts ids ( include all languages )
222
- */
223
- public function twenty_fourteen_featured_content_ids( $featured_ids ) {
224
- if ( 'twentyfourteen' != get_template() || ! did_action( 'pll_init' ) || false !== $featured_ids ) {
225
- return $featured_ids;
226
- }
227
-
228
- $settings = Featured_Content::get_setting();
229
-
230
- if ( ! $term = wpcom_vip_get_term_by( 'name', $settings['tag-name'], 'post_tag' ) ) {
231
- return $featured_ids;
232
- }
233
-
234
- // Get featured tag translations
235
- $tags = PLL()->model->term->get_translations( $term->term_id );
236
- $ids = array();
237
-
238
- // Query for featured posts in all languages
239
- // One query per language to get the correct number of posts per language
240
- foreach ( $tags as $tag ) {
241
- $_ids = get_posts( array(
242
- 'lang' => 0, // avoid language filters
243
- 'fields' => 'ids',
244
- 'numberposts' => Featured_Content::$max_posts,
245
- 'tax_query' => array(
246
- array(
247
- 'taxonomy' => 'post_tag',
248
- 'terms' => (int) $tag,
249
- ),
250
- ),
251
- ) );
252
-
253
- $ids = array_merge( $ids, $_ids );
254
- }
255
-
256
- $ids = array_map( 'absint', $ids );
257
- set_transient( 'featured_content_ids', $ids );
258
-
259
- return $ids;
260
- }
261
-
262
- /**
263
- * Twenty Fourteen
264
- * Translates the featured tag id in featured content settings
265
- * Mainly to allow hiding it when requested in featured content options
266
- * Acts only on frontend
267
- *
268
- * @since 1.4
269
- *
270
- * @param array $settings featured content settings
271
- * @return array modified $settings
272
- */
273
- public function twenty_fourteen_option_featured_content( $settings ) {
274
- if ( 'twentyfourteen' == get_template() && PLL() instanceof PLL_Frontend && $settings['tag-id'] && $tr = pll_get_term( $settings['tag-id'] ) ) {
275
- $settings['tag-id'] = $tr;
276
- }
277
-
278
- return $settings;
279
- }
280
-
281
  /**
282
  * Duplicate Post
283
  * Avoid duplicating the 'post_translations' taxonomy
@@ -287,7 +228,7 @@ class PLL_Plugins_Compat {
287
  * @param array|string $taxonomies
288
  * @return array
289
  */
290
- function duplicate_post_taxonomies_blacklist( $taxonomies ) {
291
  if ( empty( $taxonomies ) ) {
292
  $taxonomies = array(); // As we get an empty string when there is no taxonomy
293
  }
31
  // Aqua Resizer
32
  add_filter( 'pll_home_url_black_list', array( $this, 'aq_home_url_black_list' ) );
33
 
 
 
 
 
34
  // Duplicate post
35
  add_filter( 'option_duplicate_post_taxonomies_blacklist', array( $this, 'duplicate_post_taxonomies_blacklist' ) );
36
 
37
  // Jetpack
38
+ $this->jetpack = new PLL_Jetpack(); // Must be loaded before the plugin is active
39
+ $this->featured_content = new PLL_Featured_Content();
40
 
41
  // WP Sweep
42
  add_filter( 'wp_sweep_excluded_taxonomies', array( $this, 'wp_sweep_excluded_taxonomies' ) );
48
  add_filter( 'get_terms_args', array( $this, 'no_category_base_get_terms_args' ), 5 ); // Before adding cache domain
49
 
50
  // WordPress MU Domain Mapping
51
+ if ( function_exists( 'redirect_to_mapped_domain' ) ) {
52
+ if ( ! defined( 'PLL_CACHE_HOME_URL' ) && ( $options = get_option( 'polylang' ) ) && $options['force_lang'] < 2 ) {
53
+ define( 'PLL_CACHE_HOME_URL', false );
54
+ }
55
+
56
+ if ( ! get_site_option( 'dm_no_primary_domain' ) ) {
57
+ remove_action( 'template_redirect', 'redirect_to_mapped_domain' );
58
+ add_action( 'template_redirect', array( $this, 'dm_redirect_to_mapped_domain' ) );
59
+ }
60
  }
61
  }
62
 
67
  *
68
  * @return object
69
  */
70
+ public static function instance() {
71
  if ( empty( self::$instance ) ) {
72
  self::$instance = new self();
73
  }
109
  if ( ( 'Divi' === get_template() || defined( 'ET_BUILDER_PLUGIN_VERSION' ) ) && class_exists( 'PLL_Divi_Builder' ) ) {
110
  $this->divi_builder = new PLL_Divi_Builder();
111
  }
112
+
113
+ // Admin Columns & Admin Columns Pro
114
+ if ( ( defined( 'AC_FILE' ) || defined( 'ACP_FILE' ) ) && class_exists( 'PLL_CPAC' ) ) {
115
+ add_action( 'admin_init', array( $this->cpac = new PLL_CPAC(), 'init' ) );
116
+ }
117
  }
118
 
119
  /**
135
  *
136
  * @since 1.2
137
  */
138
+ public function maybe_wordpress_importer() {
139
  if ( defined( 'WP_LOAD_IMPORTERS' ) && class_exists( 'WP_Import' ) ) {
140
  remove_action( 'admin_init', 'wordpress_importer_init' );
141
  add_action( 'admin_init', array( $this, 'wordpress_importer_init' ) );
148
  *
149
  * @since 1.2
150
  */
151
+ public function wordpress_importer_init() {
152
  $class = new ReflectionClass( 'WP_Import' );
153
  load_plugin_textdomain( 'wordpress-importer', false, basename( dirname( $class->getFileName() ) ) . '/languages' );
154
 
166
  * @param array $terms an array of arrays containing terms information form the WXR file
167
  * @return array
168
  */
169
+ public function wp_import_terms( $terms ) {
170
  include PLL_SETTINGS_INC . '/languages.php';
171
 
172
  foreach ( $terms as $key => $term ) {
219
  }
220
  }
221
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
222
  /**
223
  * Duplicate Post
224
  * Avoid duplicating the 'post_translations' taxonomy
228
  * @param array|string $taxonomies
229
  * @return array
230
  */
231
+ public function duplicate_post_taxonomies_blacklist( $taxonomies ) {
232
  if ( empty( $taxonomies ) ) {
233
  $taxonomies = array(); // As we get an empty string when there is no taxonomy
234
  }
modules/plugins/wp-import.php CHANGED
@@ -13,7 +13,7 @@ class PLL_WP_Import extends WP_Import {
13
  *
14
  * @since 1.2
15
  */
16
- function process_terms() {
17
  $term_translations = array();
18
 
19
  // Store this for future usage as parent function unsets $this->terms
@@ -50,7 +50,7 @@ class PLL_WP_Import extends WP_Import {
50
  *
51
  * @since 1.2
52
  */
53
- function process_posts() {
54
  $menu_items = $mo_posts = array();
55
 
56
  // Store this for future usage as parent function unset $this->posts
@@ -110,7 +110,7 @@ class PLL_WP_Import extends WP_Import {
110
  *
111
  * @param array $terms array of terms in 'term_translations' taxonomy
112
  */
113
- function remap_terms_relations( &$terms ) {
114
  global $wpdb;
115
 
116
  foreach ( $terms as $term ) {
@@ -131,11 +131,11 @@ class PLL_WP_Import extends WP_Import {
131
  $trs = array_unique( $trs );
132
 
133
  // Make sure we don't attempt to insert already existing term relationships
134
- $existing_trs = $wpdb->get_results( "
135
- SELECT tr.object_id, tr.term_taxonomy_id FROM $wpdb->term_relationships AS tr
136
- INNER JOIN $wpdb->term_taxonomy AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
137
- WHERE tt.taxonomy IN ( 'term_language', 'term_translations' )
138
- " );
139
 
140
  foreach ( $existing_trs as $key => $tr ) {
141
  $existing_trs[ $key ] = $wpdb->prepare( '( %d, %d )', $tr->object_id, $tr->term_taxonomy_id );
@@ -144,7 +144,8 @@ class PLL_WP_Import extends WP_Import {
144
  $trs = array_diff( $trs, $existing_trs );
145
 
146
  if ( ! empty( $trs ) ) {
147
- $wpdb->query( "INSERT INTO $wpdb->term_relationships ( object_id, term_taxonomy_id ) VALUES " . implode( ',', $trs ) );
 
148
  }
149
  }
150
  }
@@ -157,7 +158,7 @@ class PLL_WP_Import extends WP_Import {
157
  * @param array $terms array of terms in 'post_translations' or 'term_translations' taxonomies
158
  * @param array $processed_objects array of posts or terms processed by WordPress Importer
159
  */
160
- function remap_translations( &$terms, &$processed_objects ) {
161
  global $wpdb;
162
 
163
  foreach ( $terms as $term ) {
@@ -177,9 +178,13 @@ class PLL_WP_Import extends WP_Import {
177
  }
178
 
179
  if ( ! empty( $u ) ) {
180
- $wpdb->query( "UPDATE $wpdb->term_taxonomy
 
 
181
  SET description = ( CASE term_id " . implode( ' ', $u['case'] ) . ' END )
182
- WHERE term_id IN ( ' . implode( ',', $u['in'] ) . ' )' );
 
 
183
  }
184
  }
185
  }
13
  *
14
  * @since 1.2
15
  */
16
+ public function process_terms() {
17
  $term_translations = array();
18
 
19
  // Store this for future usage as parent function unsets $this->terms
50
  *
51
  * @since 1.2
52
  */
53
+ public function process_posts() {
54
  $menu_items = $mo_posts = array();
55
 
56
  // Store this for future usage as parent function unset $this->posts
110
  *
111
  * @param array $terms array of terms in 'term_translations' taxonomy
112
  */
113
+ protected function remap_terms_relations( &$terms ) {
114
  global $wpdb;
115
 
116
  foreach ( $terms as $term ) {
131
  $trs = array_unique( $trs );
132
 
133
  // Make sure we don't attempt to insert already existing term relationships
134
+ $existing_trs = $wpdb->get_results(
135
+ "SELECT tr.object_id, tr.term_taxonomy_id FROM {$wpdb->term_relationships} AS tr
136
+ INNER JOIN {$wpdb->term_taxonomy} AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
137
+ WHERE tt.taxonomy IN ( 'term_language', 'term_translations' )"
138
+ );
139
 
140
  foreach ( $existing_trs as $key => $tr ) {
141
  $existing_trs[ $key ] = $wpdb->prepare( '( %d, %d )', $tr->object_id, $tr->term_taxonomy_id );
144
  $trs = array_diff( $trs, $existing_trs );
145
 
146
  if ( ! empty( $trs ) ) {
147
+ // PHPCS:ignore WordPress.DB.PreparedSQL.NotPrepared
148
+ $wpdb->query( "INSERT INTO {$wpdb->term_relationships} ( object_id, term_taxonomy_id ) VALUES " . implode( ',', $trs ) );
149
  }
150
  }
151
  }
158
  * @param array $terms array of terms in 'post_translations' or 'term_translations' taxonomies
159
  * @param array $processed_objects array of posts or terms processed by WordPress Importer
160
  */
161
+ protected function remap_translations( &$terms, &$processed_objects ) {
162
  global $wpdb;
163
 
164
  foreach ( $terms as $term ) {
178
  }
179
 
180
  if ( ! empty( $u ) ) {
181
+ // PHPCS:disable WordPress.DB.PreparedSQL.NotPrepared
182
+ $wpdb->query(
183
+ "UPDATE {$wpdb->term_taxonomy}
184
  SET description = ( CASE term_id " . implode( ' ', $u['case'] ) . ' END )
185
+ WHERE term_id IN ( ' . implode( ',', $u['in'] ) . ' )'
186
+ );
187
+ // PHPCS:enable
188
  }
189
  }
190
  }
modules/plugins/wpseo.php CHANGED
@@ -67,7 +67,7 @@ class PLL_WPSEO {
67
  *
68
  * @since 2.0
69
  */
70
- function wpseo_register_strings() {
71
  $options = get_option( 'wpseo_titles' );
72
  foreach ( get_post_types( array( 'public' => true, '_builtin' => false ) ) as $t ) {
73
  if ( pll_is_translated_post_type( $t ) ) {
@@ -112,7 +112,7 @@ class PLL_WPSEO {
112
  * @param array $options
113
  * @return array
114
  */
115
- function wpseo_translate_titles( $options ) {
116
  if ( PLL() instanceof PLL_Frontend ) {
117
  foreach ( get_post_types( array( 'public' => true, '_builtin' => false ) ) as $t ) {
118
  if ( pll_is_translated_post_type( $t ) ) {
@@ -237,11 +237,13 @@ class PLL_WPSEO {
237
 
238
  foreach ( $languages as $lang ) {
239
  if ( empty( PLL()->options['hide_default'] ) || pll_default_language() !== $lang ) {
240
- $str .= $renderer->sitemap_url( array(
241
- 'loc' => pll_home_url( $lang ),
242
- 'pri' => 1,
243
- 'chf' => apply_filters( 'wpseo_sitemap_homepage_change_freq', 'daily', pll_home_url( $lang ) ),
244
- ) );
 
 
245
  }
246
  }
247
  return $str;
@@ -269,11 +271,20 @@ class PLL_WPSEO {
269
 
270
  // WPSEO already deals with the locale
271
  if ( did_action( 'pll_init' ) && method_exists( $wpseo_og, 'og_tag' ) ) {
 
 
272
  foreach ( PLL()->model->get_languages_list() as $language ) {
273
  if ( PLL()->curlang->slug !== $language->slug && PLL()->links->get_translation_url( $language ) && isset( $language->facebook ) ) {
274
- $wpseo_og->og_tag( 'og:locale:alternate', $language->facebook );
275
  }
276
  }
 
 
 
 
 
 
 
277
  }
278
  }
279
 
67
  *
68
  * @since 2.0
69
  */
70
+ public function wpseo_register_strings() {
71
  $options = get_option( 'wpseo_titles' );
72
  foreach ( get_post_types( array( 'public' => true, '_builtin' => false ) ) as $t ) {
73
  if ( pll_is_translated_post_type( $t ) ) {
112
  * @param array $options
113
  * @return array
114
  */
115
+ public function wpseo_translate_titles( $options ) {
116
  if ( PLL() instanceof PLL_Frontend ) {
117
  foreach ( get_post_types( array( 'public' => true, '_builtin' => false ) ) as $t ) {
118
  if ( pll_is_translated_post_type( $t ) ) {
237
 
238
  foreach ( $languages as $lang ) {
239
  if ( empty( PLL()->options['hide_default'] ) || pll_default_language() !== $lang ) {
240
+ $str .= $renderer->sitemap_url(
241
+ array(
242
+ 'loc' => pll_home_url( $lang ),
243
+ 'pri' => 1,
244
+ 'chf' => apply_filters( 'wpseo_sitemap_homepage_change_freq', 'daily', pll_home_url( $lang ) ),
245
+ )
246
+ );
247
  }
248
  }
249
  return $str;
271
 
272
  // WPSEO already deals with the locale
273
  if ( did_action( 'pll_init' ) && method_exists( $wpseo_og, 'og_tag' ) ) {
274
+ $alternates = array();
275
+
276
  foreach ( PLL()->model->get_languages_list() as $language ) {
277
  if ( PLL()->curlang->slug !== $language->slug && PLL()->links->get_translation_url( $language ) && isset( $language->facebook ) ) {
278
+ $alternates[] = $language->facebook;
279
  }
280
  }
281
+
282
+ // There is a risk that 2 languages have the same Facebook locale. So let's make sure to output each locale only once.
283
+ $alternates = array_unique( $alternates );
284
+
285
+ foreach ( $alternates as $lang ) {
286
+ $wpseo_og->og_tag( 'og:locale:alternate', $lang );
287
+ }
288
  }
289
  }
290
 
modules/share-slug/settings-share-slug.php CHANGED
@@ -15,11 +15,14 @@ class PLL_Settings_Share_Slug extends PLL_Settings_Module {
15
  * @param object $polylang polylang object
16
  */
17
  public function __construct( &$polylang ) {
18
- parent::__construct( $polylang, array(
19
- 'module' => 'share-slugs',
20
- 'title' => __( 'Share slugs', 'polylang' ),
21
- 'description' => __( 'Allows to share the same url slug across languages for posts and terms.', 'polylang' ),
22
- ) );
 
 
 
23
 
24
  if ( class_exists( 'PLL_Share_Post_Slug', true ) && get_option( 'permalink_structure' ) ) {
25
  add_action( 'admin_print_footer_scripts', array( $this, 'print_js' ) );
15
  * @param object $polylang polylang object
16
  */
17
  public function __construct( &$polylang ) {
18
+ parent::__construct(
19
+ $polylang,
20
+ array(
21
+ 'module' => 'share-slugs',
22
+ 'title' => __( 'Share slugs', 'polylang' ),
23
+ 'description' => __( 'Allows to share the same url slug across languages for posts and terms.', 'polylang' ),
24
+ )
25
+ );
26
 
27
  if ( class_exists( 'PLL_Share_Post_Slug', true ) && get_option( 'permalink_structure' ) ) {
28
  add_action( 'admin_print_footer_scripts', array( $this, 'print_js' ) );
modules/sync/admin-sync.php CHANGED
@@ -5,8 +5,7 @@
5
  *
6
  * @since 1.2
7
  */
8
- class PLL_Admin_Sync {
9
- public $taxonomies, $post_metas, $term_meta;
10
 
11
  /**
12
  * Constructor
@@ -16,28 +15,10 @@ class PLL_Admin_Sync {
16
  * @param object $polylang
17
  */
18
  public function __construct( &$polylang ) {
19
- $this->model = &$polylang->model;
20
- $this->options = &$polylang->options;
21
-
22
- $this->taxonomies = new PLL_Sync_Tax( $polylang );
23
- $this->post_metas = new PLL_Sync_Post_Metas( $polylang );
24
- $this->term_metas = new PLL_Sync_Term_Metas( $polylang );
25
 
26
  add_filter( 'wp_insert_post_parent', array( $this, 'wp_insert_post_parent' ), 10, 3 );
27
  add_action( 'add_meta_boxes', array( $this, 'add_meta_boxes' ), 5, 2 ); // Before Types which populates custom fields in same hook with priority 10
28
-
29
- add_action( 'pll_save_post', array( $this, 'pll_save_post' ), 10, 3 );
30
- add_action( 'pll_save_term', array( $this, 'sync_term_parent' ), 10, 3 );
31
-
32
- add_action( 'pll_duplicate_term', array( $this->term_metas, 'copy' ), 10, 3 );
33
-
34
- if ( $this->options['media_support'] ) {
35
- add_action( 'pll_translate_media', array( $this->taxonomies, 'copy' ), 10, 3 );
36
- add_action( 'pll_translate_media', array( $this->post_metas, 'copy' ), 10, 3 );
37
- add_action( 'edit_attachment', array( $this, 'edit_attachment' ) );
38
- }
39
-
40
- add_filter( 'pre_update_option_sticky_posts', array( $this, 'sync_sticky_posts' ), 10, 2 );
41
  }
42
 
43
  /**
@@ -95,72 +76,59 @@ class PLL_Admin_Sync {
95
  }
96
 
97
  /**
98
- * Synchronizes post fields in translations
99
  *
100
- * @since 1.2
101
  *
102
- * @param int $post_id post id
103
- * @param object $post post object
104
- * @param array $translations post translations
105
  */
106
- public function pll_save_post( $post_id, $post, $translations ) {
107
  global $wpdb;
108
 
109
- // Prepare properties to synchronize
110
- foreach ( array( 'comment_status', 'ping_status', 'menu_order' ) as $property ) {
111
- if ( in_array( $property, $this->options['sync'] ) ) {
112
- $postarr[ $property ] = $post->$property;
113
- }
 
 
 
 
 
 
 
 
 
 
 
114
  }
115
 
116
- if ( in_array( 'post_date', $this->options['sync'] ) ) {
117
- // For new drafts, save the date now otherwise it is overriden by WP. Thanks to JoryHogeveen. See #32.
118
- if ( 'post-new.php' === $GLOBALS['pagenow'] && isset( $_GET['from_post'], $_GET['new_lang'] ) ) {
119
- $original = get_post( (int) $_GET['from_post'] );
120
- $wpdb->update(
121
- $wpdb->posts, array(
122
- 'post_date' => $original->post_date,
123
- 'post_date_gmt' => $original->post_date_gmt,
124
- ),
125
- array( 'ID' => $post_id )
126
- );
127
- } else {
128
- $postarr['post_date'] = $post->post_date;
129
- $postarr['post_date_gmt'] = $post->post_date_gmt;
130
- }
131
  }
132
 
133
- foreach ( $translations as $lang => $tr_id ) {
134
- if ( ! $tr_id || $tr_id === $post_id ) {
135
- continue;
136
- }
137
-
138
- // Add comment status, ping status, menu order... to synchronization
139
- $tr_arr = empty( $postarr ) ? array() : $postarr;
140
-
141
- if ( isset( $GLOBALS['post_type'] ) ) {
142
- $post_type = $GLOBALS['post_type'];
143
- } elseif ( isset( $_REQUEST['post_type'] ) ) {
144
- $post_type = $_REQUEST['post_type']; // 2nd case for quick edit
145
- }
146
 
147
- // Add post parent to synchronization
148
- // Make sure not to impact media translations when creating them at the same time as post
149
- // Do not udpate the translation parent if the user set a parent with no translation
150
- if ( in_array( 'post_parent', $this->options['sync'] ) && isset( $post_type ) && $post_type === $post->post_type ) {
151
- $post_parent = ( $parent_id = wp_get_post_parent_id( $post_id ) ) ? $this->model->post->get_translation( $parent_id, $lang ) : 0;
152
- if ( ! ( $parent_id && ! $post_parent ) ) {
153
- $tr_arr['post_parent'] = $post_parent;
154
- }
155
- }
156
 
157
- // Update all the row at once
158
- // Don't use wp_update_post to avoid infinite loop
159
- if ( ! empty( $tr_arr ) ) {
160
- $wpdb->update( $wpdb->posts, $tr_arr, array( 'ID' => $tr_id ) );
161
- clean_post_cache( $tr_id );
162
- }
163
- }
 
 
 
 
164
 
165
  // Sticky posts
166
  if ( in_array( 'sticky_posts', $this->options['sync'] ) ) {
@@ -174,76 +142,6 @@ class PLL_Admin_Sync {
174
  }
175
  }
176
 
177
- /**
178
- * Synchronize term parent in translations
179
- * Calling clean_term_cache *after* this is mandatory otherwise the $taxonomy_children option is not correctly updated
180
- * Before WP 3.9 clean_term_cache could be called ( efficiently ) only one time due to static array which prevented to update the option more than once
181
- * This is the reason to use the edit_term filter and not edited_term
182
- *
183
- * @since 2.3
184
- *
185
- * @param int $term_id Term id
186
- * @param string $taxonomy Taxonomy name
187
- * @param array $translations The list of translations term ids
188
- */
189
- public function sync_term_parent( $term_id, $taxonomy, $translations ) {
190
- global $wpdb;
191
-
192
- if ( is_taxonomy_hierarchical( $taxonomy ) && $this->model->is_translated_taxonomy( $taxonomy ) ) {
193
- $term = get_term( $term_id );
194
-
195
- foreach ( $translations as $lang => $tr_id ) {
196
- if ( ! empty( $tr_id ) && $tr_id !== $term_id && $tr_parent = $this->model->term->get_translation( $term->parent, $lang ) ) {
197
- $wpdb->update(
198
- $wpdb->term_taxonomy,
199
- array( 'parent' => isset( $tr_parent ) ? $tr_parent : 0 ),
200
- array( 'term_taxonomy_id' => get_term( (int) $tr_id, $taxonomy )->term_taxonomy_id )
201
- );
202
-
203
- clean_term_cache( $tr_id, $taxonomy ); // OK since WP 3.9
204
- }
205
- }
206
- }
207
- }
208
-
209
- /**
210
- * Synchronizes terms and metas in translations for media
211
- *
212
- * @since 1.8
213
- *
214
- * @param int $post_id post id
215
- */
216
- public function edit_attachment( $post_id ) {
217
- $this->pll_save_post( $post_id, get_post( $post_id ), $this->model->post->get_translations( $post_id ) );
218
- }
219
-
220
- /**
221
- * Synchronize sticky posts
222
- *
223
- * @since 2.3
224
- *
225
- * @param array $value New option value
226
- * @param array $old_value Old option value
227
- * @return array
228
- */
229
- public function sync_sticky_posts( $value, $old_value ) {
230
- if ( in_array( 'sticky_posts', $this->options['sync'] ) ) {
231
- // Stick post
232
- if ( $sticked = array_diff( $value, $old_value ) ) {
233
- $translations = $this->model->post->get_translations( reset( $sticked ) );
234
- $value = array_unique( array_merge( $value, array_values( $translations ) ) );
235
- }
236
-
237
- // Unstick post
238
- if ( $unsticked = array_diff( $old_value, $value ) ) {
239
- $translations = $this->model->post->get_translations( reset( $unsticked ) );
240
- $value = array_unique( array_diff( $value, array_values( $translations ) ) );
241
- }
242
- }
243
-
244
- return $value;
245
- }
246
-
247
  /**
248
  * Some backward compatibility with Polylang < 2.3
249
  * allows to call PLL()->sync->copy_post_metas() and PLL()->sync->copy_taxonomies()
@@ -263,10 +161,15 @@ class PLL_Admin_Sync {
263
  $debug = debug_backtrace();
264
  $i = 1 + empty( $debug[1]['line'] ); // The file and line are in $debug[2] if the function was called using call_user_func
265
 
266
- trigger_error( sprintf(
267
- '%1$s was called incorrectly in %3$s on line %4$s: the call to PLL()->sync->%1$s() has been deprecated in Polylang 2.3, use PLL()->sync->%2$s->copy() instead.' . "\nError handler",
268
- $func, $obj, $debug[ $i ]['file'], $debug[ $i ]['line']
269
- ) );
 
 
 
 
 
270
  }
271
  return call_user_func_array( array( $this->$obj, 'copy' ), $args );
272
  }
5
  *
6
  * @since 1.2
7
  */
8
+ class PLL_Admin_Sync extends PLL_Sync {
 
9
 
10
  /**
11
  * Constructor
15
  * @param object $polylang
16
  */
17
  public function __construct( &$polylang ) {
18
+ parent::__construct( $polylang );
 
 
 
 
 
19
 
20
  add_filter( 'wp_insert_post_parent', array( $this, 'wp_insert_post_parent' ), 10, 3 );
21
  add_action( 'add_meta_boxes', array( $this, 'add_meta_boxes' ), 5, 2 ); // Before Types which populates custom fields in same hook with priority 10
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  }
23
 
24
  /**
76
  }
77
 
78
  /**
79
+ * Get post fields to synchornize
80
  *
81
+ * @since 2.4
82
  *
83
+ * @param object $post Post object
84
+ * @return array
 
85
  */
86
+ protected function get_fields_to_sync( $post ) {
87
  global $wpdb;
88
 
89
+ $postarr = parent::get_fields_to_sync( $post );
90
+
91
+ // For new drafts, save the date now otherwise it is overriden by WP. Thanks to JoryHogeveen. See #32.
92
+ if ( in_array( 'post_date', $this->options['sync'] ) && 'post-new.php' === $GLOBALS['pagenow'] && isset( $_GET['from_post'], $_GET['new_lang'] ) ) {
93
+ unset( $postarr['post_date'] );
94
+ unset( $postarr['post_date_gmt'] );
95
+
96
+ $original = get_post( (int) $_GET['from_post'] );
97
+ $wpdb->update(
98
+ $wpdb->posts,
99
+ array(
100
+ 'post_date' => $original->post_date,
101
+ 'post_date_gmt' => $original->post_date_gmt,
102
+ ),
103
+ array( 'ID' => $post->ID )
104
+ );
105
  }
106
 
107
+ if ( isset( $GLOBALS['post_type'] ) ) {
108
+ $post_type = $GLOBALS['post_type'];
109
+ } elseif ( isset( $_REQUEST['post_type'] ) ) {
110
+ $post_type = $_REQUEST['post_type']; // 2nd case for quick edit
 
 
 
 
 
 
 
 
 
 
 
111
  }
112
 
113
+ // Make sure not to impact media translations when creating them at the same time as post
114
+ if ( in_array( 'post_parent', $this->options['sync'] ) && ( ! isset( $post_type ) || $post_type !== $post->post_type ) ) {
115
+ unset( $postarr['post_parent'] );
116
+ }
 
 
 
 
 
 
 
 
 
117
 
118
+ return $postarr;
119
+ }
 
 
 
 
 
 
 
120
 
121
+ /**
122
+ * Synchronizes post fields in translations
123
+ *
124
+ * @since 1.2
125
+ *
126
+ * @param int $post_id post id
127
+ * @param object $post post object
128
+ * @param array $translations post translations
129
+ */
130
+ public function pll_save_post( $post_id, $post, $translations ) {
131
+ parent::pll_save_post( $post_id, $post, $translations );
132
 
133
  // Sticky posts
134
  if ( in_array( 'sticky_posts', $this->options['sync'] ) ) {
142
  }
143
  }
144
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145
  /**
146
  * Some backward compatibility with Polylang < 2.3
147
  * allows to call PLL()->sync->copy_post_metas() and PLL()->sync->copy_taxonomies()
161
  $debug = debug_backtrace();
162
  $i = 1 + empty( $debug[1]['line'] ); // The file and line are in $debug[2] if the function was called using call_user_func
163
 
164
+ trigger_error(
165
+ sprintf(
166
+ '%1$s was called incorrectly in %3$s on line %4$s: the call to PLL()->sync->%1$s() has been deprecated in Polylang 2.3, use PLL()->sync->%2$s->copy() instead.' . "\nError handler",
167
+ $func,
168
+ $obj,
169
+ $debug[ $i ]['file'],
170
+ $debug[ $i ]['line']
171
+ )
172
+ );
173
  }
174
  return call_user_func_array( array( $this->$obj, 'copy' ), $args );
175
  }
modules/sync/settings-sync.php CHANGED
@@ -15,11 +15,14 @@ class PLL_Settings_Sync extends PLL_Settings_Module {
15
  * @param object $polylang polylang object
16
  */
17
  public function __construct( &$polylang ) {
18
- parent::__construct( $polylang, array(
19
- 'module' => 'sync',
20
- 'title' => __( 'Synchronization', 'polylang' ),
21
- 'description' => __( 'The synchronization options allow to maintain exact same values (or translations in the case of taxonomies and page parent) of meta content between the translations of a post or page.', 'polylang' ),
22
- ) );
 
 
 
23
  }
24
 
25
  /**
@@ -84,7 +87,7 @@ class PLL_Settings_Sync extends PLL_Settings_Module {
84
  *
85
  * @return array
86
  */
87
- static public function list_metas_to_sync() {
88
  return array(
89
  'taxonomies' => __( 'Taxonomies', 'polylang' ),
90
  'post_meta' => __( 'Custom fields', 'polylang' ),
15
  * @param object $polylang polylang object
16
  */
17
  public function __construct( &$polylang ) {
18
+ parent::__construct(
19
+ $polylang,
20
+ array(
21
+ 'module' => 'sync',
22
+ 'title' => __( 'Synchronization', 'polylang' ),
23
+ 'description' => __( 'The synchronization options allow to maintain exact same values (or translations in the case of taxonomies and page parent) of meta content between the translations of a post or page.', 'polylang' ),
24
+ )
25
+ );
26
  }
27
 
28
  /**
87
  *
88
  * @return array
89
  */
90
+ public static function list_metas_to_sync() {
91
  return array(
92
  'taxonomies' => __( 'Taxonomies', 'polylang' ),
93
  'post_meta' => __( 'Custom fields', 'polylang' ),
modules/sync/sync-metas.php CHANGED
@@ -144,7 +144,7 @@ abstract class PLL_Sync_Metas {
144
  $tr_ids = $this->model->{$this->meta_type}->get_translations( $id );
145
 
146
  foreach ( $tr_ids as $lang => $tr_id ) {
147
- if ( $tr_id !== $id ) {
148
  $to_copy = $this->get_metas_to_copy( $id, $tr_id, $lang, true );
149
  if ( in_array( $meta_key, $to_copy ) ) {
150
  $meta_value = $this->maybe_translate_value( $meta_value, $meta_key, $id, $tr_id, $lang );
@@ -252,7 +252,7 @@ abstract class PLL_Sync_Metas {
252
  $tr_ids = $this->model->{$this->meta_type}->get_translations( $id );
253
 
254
  foreach ( $tr_ids as $lang => $tr_id ) {
255
- if ( $tr_id !== $id ) {
256
  if ( in_array( $key, $this->to_copy[ $id ][ $tr_id ] ) ) {
257
  if ( '' !== $value && null !== $value && false !== $value ) { // Same test as WP
258
  $value = $this->maybe_translate_value( $value, $key, $id, $tr_id, $lang );
@@ -332,7 +332,7 @@ abstract class PLL_Sync_Metas {
332
  $src_lang = array_search( $object_id, $translations );
333
 
334
  foreach ( $translations as $tr_lang => $tr_id ) {
335
- if ( $tr_id !== $object_id ) {
336
  $this->copy( $object_id, $tr_id, $tr_lang, true );
337
  }
338
  }
144
  $tr_ids = $this->model->{$this->meta_type}->get_translations( $id );
145
 
146
  foreach ( $tr_ids as $lang => $tr_id ) {
147
+ if ( $tr_id != $id ) {
148
  $to_copy = $this->get_metas_to_copy( $id, $tr_id, $lang, true );
149
  if ( in_array( $meta_key, $to_copy ) ) {
150
  $meta_value = $this->maybe_translate_value( $meta_value, $meta_key, $id, $tr_id, $lang );
252
  $tr_ids = $this->model->{$this->meta_type}->get_translations( $id );
253
 
254
  foreach ( $tr_ids as $lang => $tr_id ) {
255
+ if ( $tr_id != $id ) {
256
  if ( in_array( $key, $this->to_copy[ $id ][ $tr_id ] ) ) {
257
  if ( '' !== $value && null !== $value && false !== $value ) { // Same test as WP
258
  $value = $this->maybe_translate_value( $value, $key, $id, $tr_id, $lang );
332
  $src_lang = array_search( $object_id, $translations );
333
 
334
  foreach ( $translations as $tr_lang => $tr_id ) {
335
+ if ( $tr_id != $object_id ) {
336
  $this->copy( $object_id, $tr_id, $tr_lang, true );
337
  }
338
  }
modules/sync/sync-tax.php CHANGED
@@ -194,21 +194,23 @@ class PLL_Sync_Tax {
194
  public function create_term( $term_id, $taxonomy, $translations ) {
195
  if ( doing_action( 'create_term' ) && in_array( $taxonomy, $this->get_taxonomies_to_copy( true ) ) ) {
196
  // Get all posts associated to the translated terms
197
- $tr_posts = get_posts( array(
198
- 'numberposts' => -1,
199
- 'nopaging' => true,
200
- 'post_type' => 'any',
201
- 'post_status' => 'any',
202
- 'fields' => 'ids',
203
- 'tax_query' => array(
204
- array(
205
- 'taxonomy' => $taxonomy,
206
- 'field' => 'id',
207
- 'terms' => array_merge( array( $term_id ), array_values( $translations ) ),
208
- 'include_children' => false,
 
 
209
  ),
210
- ),
211
- ) );
212
 
213
  $lang = $this->model->term->get_language( $term_id ); // Language of the created term
214
  $posts = array();
194
  public function create_term( $term_id, $taxonomy, $translations ) {
195
  if ( doing_action( 'create_term' ) && in_array( $taxonomy, $this->get_taxonomies_to_copy( true ) ) ) {
196
  // Get all posts associated to the translated terms
197
+ $tr_posts = get_posts(
198
+ array(
199
+ 'numberposts' => -1,
200
+ 'nopaging' => true,
201
+ 'post_type' => 'any',
202
+ 'post_status' => 'any',
203
+ 'fields' => 'ids',
204
+ 'tax_query' => array(
205
+ array(
206
+ 'taxonomy' => $taxonomy,
207
+ 'field' => 'id',
208
+ 'terms' => array_merge( array( $term_id ), array_values( $translations ) ),
209
+ 'include_children' => false,
210
+ ),
211
  ),
212
+ )
213
+ );
214
 
215
  $lang = $this->model->term->get_language( $term_id ); // Language of the created term
216
  $posts = array();
modules/sync/sync.php ADDED
@@ -0,0 +1,177 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Manages copy and synchronization of terms and post metas on front
5
+ *
6
+ * @since 2.4
7
+ */
8
+ class PLL_Sync {
9
+ public $taxonomies, $post_metas, $term_meta;
10
+
11
+ /**
12
+ * Constructor
13
+ *
14
+ * @since 1.2
15
+ *
16
+ * @param object $polylang
17
+ */
18
+ public function __construct( &$polylang ) {
19
+ $this->model = &$polylang->model;
20
+ $this->options = &$polylang->options;
21
+
22
+ $this->taxonomies = new PLL_Sync_Tax( $polylang );
23
+ $this->post_metas = new PLL_Sync_Post_Metas( $polylang );
24
+ $this->term_metas = new PLL_Sync_Term_Metas( $polylang );
25
+
26
+ add_action( 'pll_save_post', array( $this, 'pll_save_post' ), 10, 3 );
27
+ add_action( 'pll_save_term', array( $this, 'sync_term_parent' ), 10, 3 );
28
+
29
+ add_action( 'pll_duplicate_term', array( $this->term_metas, 'copy' ), 10, 3 );
30
+
31
+ if ( $this->options['media_support'] ) {
32
+ add_action( 'pll_translate_media', array( $this->taxonomies, 'copy' ), 10, 3 );
33
+ add_action( 'pll_translate_media', array( $this->post_metas, 'copy' ), 10, 3 );
34
+ add_action( 'edit_attachment', array( $this, 'edit_attachment' ) );
35
+ }
36
+
37
+ add_filter( 'pre_update_option_sticky_posts', array( $this, 'sync_sticky_posts' ), 10, 2 );
38
+ }
39
+
40
+ /**
41
+ * Get post fields to synchornize
42
+ *
43
+ * @since 2.4
44
+ *
45
+ * @param object $post Post object
46
+ * @return array
47
+ */
48
+ protected function get_fields_to_sync( $post ) {
49
+ $postarr = array();
50
+
51
+ foreach ( array( 'comment_status', 'ping_status', 'menu_order' ) as $property ) {
52
+ if ( in_array( $property, $this->options['sync'] ) ) {
53
+ $postarr[ $property ] = $post->$property;
54
+ }
55
+ }
56
+
57
+ if ( in_array( 'post_date', $this->options['sync'] ) ) {
58
+ $postarr['post_date'] = $post->post_date;
59
+ $postarr['post_date_gmt'] = $post->post_date_gmt;
60
+ }
61
+
62
+ if ( in_array( 'post_parent', $this->options['sync'] ) ) {
63
+ $postarr['post_parent'] = wp_get_post_parent_id( $post->ID );
64
+ }
65
+
66
+ return $postarr;
67
+ }
68
+
69
+ /**
70
+ * Synchronizes post fields in translations
71
+ *
72
+ * @since 2.4
73
+ *
74
+ * @param int $post_id post id
75
+ * @param object $post post object
76
+ * @param array $translations post translations
77
+ */
78
+ public function pll_save_post( $post_id, $post, $translations ) {
79
+ global $wpdb;
80
+
81
+ $postarr = $this->get_fields_to_sync( $post );
82
+
83
+ if ( ! empty( $postarr ) ) {
84
+ foreach ( $translations as $lang => $tr_id ) {
85
+ if ( ! $tr_id || $tr_id === $post_id ) {
86
+ continue;
87
+ }
88
+
89
+ $tr_arr = $postarr;
90
+ unset( $tr_arr['post_parent'] );
91
+
92
+ // Do not udpate the translation parent if the user set a parent with no translation
93
+ if ( isset( $postarr['post_parent'] ) ) {
94
+ $post_parent = $postarr['post_parent'] ? $this->model->post->get_translation( $postarr['post_parent'], $lang ) : 0;
95
+ if ( ! ( $postarr['post_parent'] && ! $post_parent ) ) {
96
+ $tr_arr['post_parent'] = $post_parent;
97
+ }
98
+ }
99
+
100
+ // Update all the row at once
101
+ // Don't use wp_update_post to avoid infinite loop
102
+ $wpdb->update( $wpdb->posts, $tr_arr, array( 'ID' => $tr_id ) );
103
+ clean_post_cache( $tr_id );
104
+ }
105
+ }
106
+ }
107
+
108
+ /**
109
+ * Synchronize term parent in translations
110
+ * Calling clean_term_cache *after* this is mandatory otherwise the $taxonomy_children option is not correctly updated
111
+ * Before WP 3.9 clean_term_cache could be called ( efficiently ) only one time due to static array which prevented to update the option more than once
112
+ * This is the reason to use the edit_term filter and not edited_term
113
+ *
114
+ * @since 2.3
115
+ *
116
+ * @param int $term_id Term id
117
+ * @param string $taxonomy Taxonomy name
118
+ * @param array $translations The list of translations term ids
119
+ */
120
+ public function sync_term_parent( $term_id, $taxonomy, $translations ) {
121
+ global $wpdb;
122
+
123
+ if ( is_taxonomy_hierarchical( $taxonomy ) && $this->model->is_translated_taxonomy( $taxonomy ) ) {
124
+ $term = get_term( $term_id );
125
+
126
+ foreach ( $translations as $lang => $tr_id ) {
127
+ if ( ! empty( $tr_id ) && $tr_id !== $term_id && $tr_parent = $this->model->term->get_translation( $term->parent, $lang ) ) {
128
+ $wpdb->update(
129
+ $wpdb->term_taxonomy,
130
+ array( 'parent' => isset( $tr_parent ) ? $tr_parent : 0 ),
131
+ array( 'term_taxonomy_id' => get_term( (int) $tr_id, $taxonomy )->term_taxonomy_id )
132
+ );
133
+
134
+ clean_term_cache( $tr_id, $taxonomy ); // OK since WP 3.9
135
+ }
136
+ }
137
+ }
138
+ }
139
+
140
+ /**
141
+ * Synchronizes terms and metas in translations for media
142
+ *
143
+ * @since 1.8
144
+ *
145
+ * @param int $post_id post id
146
+ */
147
+ public function edit_attachment( $post_id ) {
148
+ $this->pll_save_post( $post_id, get_post( $post_id ), $this->model->post->get_translations( $post_id ) );
149
+ }
150
+
151
+ /**
152
+ * Synchronize sticky posts
153
+ *
154
+ * @since 2.3
155
+ *
156
+ * @param array $value New option value
157
+ * @param array $old_value Old option value
158
+ * @return array
159
+ */
160
+ public function sync_sticky_posts( $value, $old_value ) {
161
+ if ( in_array( 'sticky_posts', $this->options['sync'] ) ) {
162
+ // Stick post
163
+ if ( $sticked = array_diff( $value, $old_value ) ) {
164
+ $translations = $this->model->post->get_translations( reset( $sticked ) );
165
+ $value = array_unique( array_merge( $value, array_values( $translations ) ) );
166
+ }
167
+
168
+ // Unstick post
169
+ if ( $unsticked = array_diff( $old_value, $value ) ) {
170
+ $translations = $this->model->post->get_translations( reset( $unsticked ) );
171
+ $value = array_unique( array_diff( $value, array_values( $translations ) ) );
172
+ }
173
+ }
174
+
175
+ return $value;
176
+ }
177
+ }
modules/translate-slugs/settings-translate-slugs.php CHANGED
@@ -14,11 +14,14 @@ class PLL_Settings_Translate_Slugs extends PLL_Settings_Module {
14
  * @param object $polylang polylang object
15
  */
16
  public function __construct( &$polylang ) {
17
- parent::__construct( $polylang, array(
18
- 'module' => 'translate-slugs',
19
- 'title' => __( 'Translate slugs', 'polylang' ),
20
- 'description' => __( 'Allows to translate custom post types and taxonomies slugs in urls.', 'polylang' ),
21
- ) );
 
 
 
22
  }
23
 
24
  /**
14
  * @param object $polylang polylang object
15
  */
16
  public function __construct( &$polylang ) {
17
+ parent::__construct(
18
+ $polylang,
19
+ array(
20
+ 'module' => 'translate-slugs',
21
+ 'title' => __( 'Translate slugs', 'polylang' ),
22
+ 'description' => __( 'Allows to translate custom post types and taxonomies slugs in urls.', 'polylang' ),
23
+ )
24
+ );
25
  }
26
 
27
  /**
modules/wpml/settings-wpml.php CHANGED
@@ -15,11 +15,14 @@ class PLL_Settings_WPML extends PLL_Settings_Module {
15
  * @param object $polylang polylang object
16
  */
17
  public function __construct( &$polylang ) {
18
- parent::__construct( $polylang, array(
19
- 'module' => 'wpml',
20
- 'title' => __( 'WPML Compatibility', 'polylang' ),
21
- 'description' => __( 'WPML compatibility mode of Polylang', 'polylang' ),
22
- ) );
 
 
 
23
  }
24
 
25
  /**
15
  * @param object $polylang polylang object
16
  */
17
  public function __construct( &$polylang ) {
18
+ parent::__construct(
19
+ $polylang,
20
+ array(
21
+ 'module' => 'wpml',
22
+ 'title' => __( 'WPML Compatibility', 'polylang' ),
23
+ 'description' => __( 'WPML compatibility mode of Polylang', 'polylang' ),
24
+ )
25
+ );
26
  }
27
 
28
  /**
modules/wpml/wpml-compat.php CHANGED
@@ -8,8 +8,8 @@
8
  * @since 1.0.2
9
  */
10
  class PLL_WPML_Compat {
11
- static protected $instance; // For singleton
12
- static protected $strings; // Used for cache
13
  public $api;
14
 
15
  /**
@@ -36,7 +36,7 @@ class PLL_WPML_Compat {
36
  *
37
  * @return object
38
  */
39
- static public function instance() {
40
  if ( empty( self::$instance ) ) {
41
  self::$instance = new self();
42
  }
8
  * @since 1.0.2
9
  */
10
  class PLL_WPML_Compat {
11
+ protected static $instance; // For singleton
12
+ protected static $strings; // Used for cache
13
  public $api;
14
 
15
  /**
36
  *
37
  * @return object
38
  */
39
+ public static function instance() {
40
  if ( empty( self::$instance ) ) {
41
  self::$instance = new self();
42
  }
modules/wpml/wpml-config.php CHANGED
@@ -8,7 +8,7 @@
8
  * @since 1.0
9
  */
10
  class PLL_WPML_Config {
11
- static protected $instance; // For singleton
12
  protected $xmls, $options;
13
 
14
  /**
@@ -29,7 +29,7 @@ class PLL_WPML_Config {
29
  *
30
  * @return object
31
  */
32
- static public function instance() {
33
  if ( empty( self::$instance ) ) {
34
  self::$instance = new self();
35
  }
8
  * @since 1.0
9
  */
10
  class PLL_WPML_Config {
11
+ protected static $instance; // For singleton
12
  protected $xmls, $options;
13
 
14
  /**
29
  *
30
  * @return object
31
  */
32
+ public static function instance() {
33
  if ( empty( self::$instance ) ) {
34
  self::$instance = new self();
35
  }
polylang.php CHANGED
@@ -3,7 +3,7 @@
3
  /**
4
  Plugin Name: Polylang
5
  Plugin URI: https://polylang.pro
6
- Version: 2.3.11
7
  Author: Frédéric Demarle
8
  Author uri: https://polylang.pro
9
  Description: Adds multilingual capability to WordPress
@@ -44,7 +44,7 @@ if ( defined( 'POLYLANG_BASENAME' ) ) {
44
  require_once ABSPATH . 'wp-includes/pluggable.php';
45
  deactivate_plugins( plugin_basename( __FILE__ ) ); // Deactivate this plugin
46
  // WP does not allow us to send a custom meaningful message, so just tell the plugin has been deactivated
47
- wp_redirect( add_query_arg( 'deactivate', 'true', remove_query_arg( 'activate' ) ) );
48
  exit;
49
  }
50
  } else {
@@ -53,12 +53,13 @@ if ( defined( 'POLYLANG_BASENAME' ) ) {
53
  }
54
  } else {
55
  // Go on loading the plugin
56
- define( 'POLYLANG_VERSION', '2.3.11' );
57
- define( 'PLL_MIN_WP_VERSION', '4.4' );
58
 
59
  define( 'POLYLANG_FILE', __FILE__ ); // this file
60
  define( 'POLYLANG_BASENAME', plugin_basename( POLYLANG_FILE ) ); // plugin name as known by WP
61
  define( 'POLYLANG_DIR', dirname( POLYLANG_FILE ) ); // our directory
 
62
 
63
  define( 'PLL_ADMIN_INC', POLYLANG_DIR . '/admin' );
64
  define( 'PLL_FRONT_INC', POLYLANG_DIR . '/frontend' );
3
  /**
4
  Plugin Name: Polylang
5
  Plugin URI: https://polylang.pro
6
+ Version: 2.4
7
  Author: Frédéric Demarle
8
  Author uri: https://polylang.pro
9
  Description: Adds multilingual capability to WordPress
44
  require_once ABSPATH . 'wp-includes/pluggable.php';
45
  deactivate_plugins( plugin_basename( __FILE__ ) ); // Deactivate this plugin
46
  // WP does not allow us to send a custom meaningful message, so just tell the plugin has been deactivated
47
+ wp_safe_redirect( add_query_arg( 'deactivate', 'true', remove_query_arg( 'activate' ) ) );
48
  exit;
49
  }
50
  } else {
53
  }
54
  } else {
55
  // Go on loading the plugin
56
+ define( 'POLYLANG_VERSION', '2.4' );
57
+ define( 'PLL_MIN_WP_VERSION', '4.7' );
58
 
59
  define( 'POLYLANG_FILE', __FILE__ ); // this file
60
  define( 'POLYLANG_BASENAME', plugin_basename( POLYLANG_FILE ) ); // plugin name as known by WP
61
  define( 'POLYLANG_DIR', dirname( POLYLANG_FILE ) ); // our directory
62
+ define( 'POLYLANG', ucwords( str_replace( '-', ' ', dirname( POLYLANG_BASENAME ) ) ) );
63
 
64
  define( 'PLL_ADMIN_INC', POLYLANG_DIR . '/admin' );
65
  define( 'PLL_FRONT_INC', POLYLANG_DIR . '/frontend' );
readme.txt CHANGED
@@ -2,9 +2,9 @@
2
  Contributors: Chouby
3
  Donate link: https://polylang.pro
4
  Tags: multilingual, bilingual, translate, translation, language, multilanguage, international, localization
5
- Requires at least: 4.4
6
  Tested up to: 4.9
7
- Stable tag: 2.3.11
8
  License: GPLv2 or later
9
 
10
  Making WordPress multilingual
@@ -41,7 +41,7 @@ Don't hesitate to [give your feedback](http://wordpress.org/support/view/plugin-
41
 
42
  == Installation ==
43
 
44
- 1. Make sure you are using WordPress 4.4 or later and that your server is running PHP 5.2.4 or later (same requirement as WordPress itself)
45
  1. If you tried other multilingual plugins, deactivate them before activating Polylang, otherwise, you may get unexpected results!
46
  1. Install and activate the plugin as usual from the 'Plugins' menu in WordPress.
47
  1. Go to the languages settings page and create the languages you need
@@ -76,6 +76,29 @@ Don't hesitate to [give your feedback](http://wordpress.org/support/view/plugin-
76
 
77
  == Changelog ==
78
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  = 2.3.11 (2018-10-03) =
80
 
81
  * Pro: Add action 'pll_created_sync_post'
2
  Contributors: Chouby
3
  Donate link: https://polylang.pro
4
  Tags: multilingual, bilingual, translate, translation, language, multilanguage, international, localization
5
+ Requires at least: 4.7
6
  Tested up to: 4.9
7
+ Stable tag: 2.4
8
  License: GPLv2 or later
9
 
10
  Making WordPress multilingual
41
 
42
  == Installation ==
43
 
44
+ 1. Make sure you are using WordPress 4.7 or later and that your server is running PHP 5.2.4 or later (same requirement as WordPress itself)
45
  1. If you tried other multilingual plugins, deactivate them before activating Polylang, otherwise, you may get unexpected results!
46
  1. Install and activate the plugin as usual from the 'Plugins' menu in WordPress.
47
  1. Go to the languages settings page and create the languages you need
76
 
77
  == Changelog ==
78
 
79
+ = 2.4 (2018-11-12) =
80
+
81
+ * Minimum WordPress version is now 4.7
82
+ * Pro: Add the possibility to bulk duplicate or bulk synchronize posts.
83
+ * Pro: Add compatibility with Admin Columns
84
+ * Pro: Add synchronized posts to the REST API
85
+ * Pro: Fix variations messed when changing WooCommerce attributes slugs
86
+ * Pro: Fix incorrect language for ajax requests made on front by The Events Calendar
87
+ * Pro: Fix term not duplicated correctly when the language is set from the content
88
+ * Refactor the core to activate on front and for the REST api actions that were previously available only in the backend (language checks, synchronizations...).
89
+ * Add flags to widgets displayed in only one language (Props Jory Hogeveen) #257
90
+ * Honor 'pll_the_language_args' for all options in menus #237
91
+ * Add better filters for default flags and custom flags
92
+ * Custom flags can now be stored in the polylang directory in the theme
93
+ * Custom flags can now use SVG
94
+ * Add compatibility with Jetpack featured content module
95
+ * Fix Twenty Fourteen featured posts possibly not filtered per language
96
+ * Fix home url not working with WordPress MU Domain mapping
97
+ * Fix Assigning a parent category breaking the hierarchy of translated category
98
+ * Fix: Accept 0,1 and 1.0 as q factors in browser preferred language detection (Props Dominic Rubas)
99
+ * Fix performance issue when using hundreds of widgets
100
+ * Fix translations possibly wrong if the post language is changed without saving the post after
101
+
102
  = 2.3.11 (2018-10-03) =
103
 
104
  * Pro: Add action 'pll_created_sync_post'
settings/flags.php CHANGED
@@ -12,255 +12,255 @@ if ( ! defined( 'ABSPATH' ) ) {
12
  * the value is the Country name
13
  */
14
  $flags = array(
15
- 'ad' => __( 'Andorra', 'polylang' ),
16
- 'ae' => __( 'United Arab Emirates', 'polylang' ),
17
- 'af' => __( 'Afghanistan', 'polylang' ),
18
- 'ag' => __( 'Antigua and Barbuda', 'polylang' ),
19
- 'ai' => __( 'Anguilla', 'polylang' ),
20
- 'al' => __( 'Albania', 'polylang' ),
21
- 'am' => __( 'Armenia', 'polylang' ),
22
- 'an' => __( 'Netherlands Antilles', 'polylang' ),
23
- 'ao' => __( 'Angola', 'polylang' ),
24
- 'ar' => __( 'Argentina', 'polylang' ),
25
- 'arab' => __( 'Arab league', 'polylang' ),
26
- 'as' => __( 'American Samoa', 'polylang' ),
27
- 'at' => __( 'Austria', 'polylang' ),
28
- 'au' => __( 'Australia', 'polylang' ),
29
- 'aw' => __( 'Aruba', 'polylang' ),
30
- 'ax' => __( 'Åland Islands', 'polylang' ),
31
- 'az' => __( 'Azerbaijan', 'polylang' ),
32
- 'ba' => __( 'Bosnia and Herzegovina', 'polylang' ),
33
- 'basque' => __( 'Basque Country', 'polylang' ),
34
- 'bb' => __( 'Barbados', 'polylang' ),
35
- 'bd' => __( 'Bangladesh', 'polylang' ),
36
- 'be' => __( 'Belgium', 'polylang' ),
37
- 'bf' => __( 'Burkina Faso', 'polylang' ),
38
- 'bg' => __( 'Bulgaria', 'polylang' ),
39
- 'bh' => __( 'Bahrain', 'polylang' ),
40
- 'bi' => __( 'Burundi', 'polylang' ),
41
- 'bj' => __( 'Benin', 'polylang' ),
42
- 'bm' => __( 'Bermuda', 'polylang' ),
43
- 'bn' => __( 'Brunei', 'polylang' ),
44
- 'bo' => __( 'Bolivia', 'polylang' ),
45
- 'br' => __( 'Brazil', 'polylang' ),
46
- 'bs' => __( 'Bahamas', 'polylang' ),
47
- 'bt' => __( 'Bhutan', 'polylang' ),
48
- 'bw' => __( 'Botswana', 'polylang' ),
49
- 'by' => __( 'Belarus', 'polylang' ),
50
- 'bz' => __( 'Belize', 'polylang' ),
51
- 'ca' => __( 'Canada', 'polylang' ),
52
  'catalonia' => __( 'Catalonia', 'polylang' ),
53
- 'cc' => __( 'Cocos', 'polylang' ),
54
- 'cd' => __( 'Democratic Republic of the Congo', 'polylang' ),
55
- 'cf' => __( 'Central African Republic', 'polylang' ),
56
- 'cg' => __( 'Congo', 'polylang' ),
57
- 'ch' => __( 'Switzerland', 'polylang' ),
58
- 'ci' => __( 'Ivory Coast', 'polylang' ),
59
- 'ck' => __( 'Cook Islands', 'polylang' ),
60
- 'cl' => __( 'Chile', 'polylang' ),
61
- 'cm' => __( 'Cameroon', 'polylang' ),
62
- 'cn' => __( 'China', 'polylang' ),
63
- 'co' => __( 'Colombia', 'polylang' ),
64
- 'cr' => __( 'Costa Rica', 'polylang' ),
65
- 'cu' => __( 'Cuba', 'polylang' ),
66
- 'cv' => __( 'Cape Verde', 'polylang' ),
67
- 'cx' => __( 'Christmas Island', 'polylang' ),
68
- 'cy' => __( 'Cyprus', 'polylang' ),
69
- 'cz' => __( 'Czech Republic', 'polylang' ),
70
- 'de' => __( 'Germany', 'polylang' ),
71
- 'dj' => __( 'Djibouti', 'polylang' ),
72
- 'dk' => __( 'Denmark', 'polylang' ),
73
- 'dm' => __( 'Dominica', 'polylang' ),
74
- 'do' => __( 'Dominican Republic', 'polylang' ),
75
- 'dz' => __( 'Algeria', 'polylang' ),
76
- 'ec' => __( 'Ecuador', 'polylang' ),
77
- 'ee' => __( 'Estonia', 'polylang' ),
78
- 'eg' => __( 'Egypt', 'polylang' ),
79
- 'eh' => __( 'Western Sahara', 'polylang' ),
80
- 'england' => __( 'England', 'polylang' ),
81
- 'er' => __( 'Eritrea', 'polylang' ),
82
- 'es' => __( 'Spain', 'polylang' ),
83
  'esperanto' => __( 'Esperanto', 'polylang' ),
84
- 'et' => __( 'Ethiopia', 'polylang' ),
85
- 'fi' => __( 'Finland', 'polylang' ),
86
- 'fj' => __( 'Fiji', 'polylang' ),
87
- 'fk' => __( 'Falkland Islands', 'polylang' ),
88
- 'fm' => __( 'Micronesia', 'polylang' ),
89
- 'fo' => __( 'Faroe Islands', 'polylang' ),
90
- 'fr' => __( 'France', 'polylang' ),
91
- 'ga' => __( 'Gabon', 'polylang' ),
92
- 'galicia' => __( 'Galicia', 'polylang' ),
93
- 'gb' => __( 'United Kingdom', 'polylang' ),
94
- 'gd' => __( 'Grenada', 'polylang' ),
95
- 'ge' => __( 'Georgia', 'polylang' ),
96
- 'gh' => __( 'Ghana', 'polylang' ),
97
- 'gi' => __( 'Gibraltar', 'polylang' ),
98
- 'gl' => __( 'Greenland', 'polylang' ),
99
- 'gm' => __( 'Gambia', 'polylang' ),
100
- 'gn' => __( 'Guinea', 'polylang' ),
101
- 'gp' => __( 'Guadeloupe', 'polylang' ),
102
- 'gq' => __( 'Equatorial Guinea', 'polylang' ),
103
- 'gr' => __( 'Greece', 'polylang' ),
104
- 'gs' => __( 'South Georgia and the South Sandwich Islands', 'polylang' ),
105
- 'gt' => __( 'Guatemala', 'polylang' ),
106
- 'gu' => __( 'Guam', 'polylang' ),
107
- 'gw' => __( 'Guinea-Bissau', 'polylang' ),
108
- 'gy' => __( 'Guyana', 'polylang' ),
109
- 'hk' => __( 'Hong Kong', 'polylang' ),
110
- 'hm' => __( 'Heard Island and McDonald Islands', 'polylang' ),
111
- 'hn' => __( 'Honduras', 'polylang' ),
112
- 'hr' => __( 'Croatia', 'polylang' ),
113
- 'ht' => __( 'Haiti', 'polylang' ),
114
- 'hu' => __( 'Hungary', 'polylang' ),
115
- 'id' => __( 'Indonesia', 'polylang' ),
116
- 'ie' => __( 'Republic of Ireland', 'polylang' ),
117
- 'il' => __( 'Israel', 'polylang' ),
118
- 'in' => __( 'India', 'polylang' ),
119
- 'io' => __( 'British Indian Ocean Territory', 'polylang' ),
120
- 'iq' => __( 'Iraq', 'polylang' ),
121
- 'ir' => __( 'Iran', 'polylang' ),
122
- 'is' => __( 'Iceland', 'polylang' ),
123
- 'it' => __( 'Italy', 'polylang' ),
124
- 'jm' => __( 'Jamaica', 'polylang' ),
125
- 'jo' => __( 'Jordan', 'polylang' ),
126
- 'jp' => __( 'Japan', 'polylang' ),
127
- 'ke' => __( 'Kenya', 'polylang' ),
128
- 'kg' => __( 'Kyrgyzstan', 'polylang' ),
129
- 'kh' => __( 'Cambodia', 'polylang' ),
130
- 'ki' => __( 'Kiribati', 'polylang' ),
131
- 'km' => __( 'Comoros', 'polylang' ),
132
- 'kn' => __( 'Saint Kitts and Nevis', 'polylang' ),
133
- 'kp' => __( 'North Korea', 'polylang' ),
134
- 'kr' => __( 'South Korea', 'polylang' ),
135
  'kurdistan' => __( 'Kurdistan', 'polylang' ),
136
- 'kw' => __( 'Kuwait', 'polylang' ),
137
- 'ky' => __( 'Cayman Islands', 'polylang' ),
138
- 'kz' => __( 'Kazakhstan', 'polylang' ),
139
- 'la' => __( 'Laos', 'polylang' ),
140
- 'lb' => __( 'Lebanon', 'polylang' ),
141
- 'lc' => __( 'Saint Lucia', 'polylang' ),
142
- 'li' => __( 'Liechtenstein', 'polylang' ),
143
- 'lk' => __( 'Sri Lanka', 'polylang' ),
144
- 'lr' => __( 'Liberia', 'polylang' ),
145
- 'ls' => __( 'Lesotho', 'polylang' ),
146
- 'lt' => __( 'Lithuania', 'polylang' ),
147
- 'lu' => __( 'Luxembourg', 'polylang' ),
148
- 'lv' => __( 'Latvia', 'polylang' ),
149
- 'ly' => __( 'Libya', 'polylang' ),
150
- 'ma' => __( 'Morocco', 'polylang' ),
151
- 'mc' => __( 'Monaco', 'polylang' ),
152
- 'md' => __( 'Moldova', 'polylang' ),
153
- 'me' => __( 'Montenegro', 'polylang' ),
154
- 'mg' => __( 'Madagascar', 'polylang' ),
155
- 'mh' => __( 'Marshall Islands', 'polylang' ),
156
- 'mk' => __( 'Macedonia', 'polylang' ),
157
- 'ml' => __( 'Mali', 'polylang' ),
158
- 'mm' => __( 'Myanmar', 'polylang' ),
159
- 'mn' => __( 'Mongolia', 'polylang' ),
160
- 'mo' => __( 'Macao', 'polylang' ),
161
- 'mp' => __( 'Northern Mariana Islands', 'polylang' ),
162
- 'mq' => __( 'Martinique', 'polylang' ),
163
- 'mr' => __( 'Mauritania', 'polylang' ),
164
- 'ms' => __( 'Montserrat', 'polylang' ),
165
- 'mt' => __( 'Malta', 'polylang' ),
166
- 'mu' => __( 'Mauritius', 'polylang' ),
167
- 'mv' => __( 'Maldives', 'polylang' ),
168
- 'mw' => __( 'Malawi', 'polylang' ),
169
- 'mx' => __( 'Mexico', 'polylang' ),
170
- 'my' => __( 'Malaysia', 'polylang' ),
171
- 'mz' => __( 'Mozambique', 'polylang' ),
172
- 'na' => __( 'Namibia', 'polylang' ),
173
- 'nc' => __( 'New Caledonia', 'polylang' ),
174
- 'ne' => __( 'Niger', 'polylang' ),
175
- 'nf' => __( 'Norfolk Island', 'polylang' ),
176
- 'ng' => __( 'Nigeria', 'polylang' ),
177
- 'ni' => __( 'Nicaragua', 'polylang' ),
178
- 'nl' => __( 'Netherlands', 'polylang' ),
179
- 'no' => __( 'Norway', 'polylang' ),
180
- 'np' => __( 'Nepal', 'polylang' ),
181
- 'nr' => __( 'Nauru', 'polylang' ),
182
- 'nu' => __( 'Niue', 'polylang' ),
183
- 'nz' => __( 'New Zealand', 'polylang' ),
184
  'occitania' => __( 'Occitania', 'polylang' ),
185
- 'om' => __( 'Oman', 'polylang' ),
186
- 'pa' => __( 'Panama', 'polylang' ),
187
- 'pe' => __( 'Peru', 'polylang' ),
188
- 'pf' => __( 'French Polynesia', 'polylang' ),
189
- 'pg' => __( 'Papua New Guinea', 'polylang' ),
190
- 'ph' => __( 'Philippines', 'polylang' ),
191
- 'pk' => __( 'Pakistan', 'polylang' ),
192
- 'pl' => __( 'Poland', 'polylang' ),
193
- 'pm' => __( 'Saint Pierre and Miquelon', 'polylang' ),
194
- 'pn' => __( 'Pitcairn', 'polylang' ),
195
- 'pr' => __( 'Puerto Rico', 'polylang' ),
196
- 'ps' => __( 'Palestinian Territory', 'polylang' ),
197
- 'pt' => __( 'Portugal', 'polylang' ),
198
- 'pw' => __( 'Belau', 'polylang' ),
199
- 'py' => __( 'Paraguay', 'polylang' ),
200
- 'qa' => __( 'Qatar', 'polylang' ),
201
- 'quebec' => __( 'Quebec', 'polylang' ),
202
- 'ro' => __( 'Romania', 'polylang' ),
203
- 'rs' => __( 'Serbia', 'polylang' ),
204
- 'ru' => __( 'Russia', 'polylang' ),
205
- 'rw' => __( 'Rwanda', 'polylang' ),
206
- 'sa' => __( 'Saudi Arabia', 'polylang' ),
207
- 'sb' => __( 'Solomon Islands', 'polylang' ),
208
- 'sc' => __( 'Seychelles', 'polylang' ),
209
- 'scotland' => __( 'Scotland', 'polylang' ),
210
- 'sd' => __( 'Sudan', 'polylang' ),
211
- 'se' => __( 'Sweden', 'polylang' ),
212
- 'sg' => __( 'Singapore', 'polylang' ),
213
- 'sh' => __( 'Saint Helena', 'polylang' ),
214
- 'si' => __( 'Slovenia', 'polylang' ),
215
- 'sk' => __( 'Slovakia', 'polylang' ),
216
- 'sl' => __( 'Sierra Leone', 'polylang' ),
217
- 'sm' => __( 'San Marino', 'polylang' ),
218
- 'sn' => __( 'Senegal', 'polylang' ),
219
- 'so' => __( 'Somalia', 'polylang' ),
220
- 'sr' => __( 'Suriname', 'polylang' ),
221
- 'ss' => __( 'South Sudan', 'polylang' ),
222
- 'st' => __( 'São Tomé and Príncipe', 'polylang' ),
223
- 'sv' => __( 'El Salvador', 'polylang' ),
224
- 'sy' => __( 'Syria', 'polylang' ),
225
- 'sz' => __( 'Swaziland', 'polylang' ),
226
- 'tc' => __( 'Turks and Caicos Islands', 'polylang' ),
227
- 'td' => __( 'Chad', 'polylang' ),
228
- 'tf' => __( 'French Southern Territories', 'polylang' ),
229
- 'tg' => __( 'Togo', 'polylang' ),
230
- 'th' => __( 'Thailand', 'polylang' ),
231
- 'tibet' => __( 'Tibet', 'polylang' ),
232
- 'tj' => __( 'Tajikistan', 'polylang' ),
233
- 'tk' => __( 'Tokelau', 'polylang' ),
234
- 'tl' => __( 'Timor-Leste', 'polylang' ),
235
- 'tm' => __( 'Turkmenistan', 'polylang' ),
236
- 'tn' => __( 'Tunisia', 'polylang' ),
237
- 'to' => __( 'Tonga', 'polylang' ),
238
- 'tr' => __( 'Turkey', 'polylang' ),
239
- 'tt' => __( 'Trinidad and Tobago', 'polylang' ),
240
- 'tv' => __( 'Tuvalu', 'polylang' ),
241
- 'tw' => __( 'Taiwan', 'polylang' ),
242
- 'tz' => __( 'Tanzania', 'polylang' ),
243
- 'ua' => __( 'Ukraine', 'polylang' ),
244
- 'ug' => __( 'Uganda', 'polylang' ),
245
- 'us' => __( 'United States', 'polylang' ),
246
- 'uy' => __( 'Uruguay', 'polylang' ),
247
- 'uz' => __( 'Uzbekistan', 'polylang' ),
248
- 'va' => __( 'Vatican', 'polylang' ),
249
- 'vc' => __( 'Saint Vincent and the Grenadines', 'polylang' ),
250
- 've' => __( 'Venezuela', 'polylang' ),
251
- 'veneto' => __( 'Veneto', 'polylang' ),
252
- 'vg' => __( 'British Virgin Islands', 'polylang' ),
253
- 'vi' => __( 'United States Virgin Islands', 'polylang' ),
254
- 'vn' => __( 'Vietnam', 'polylang' ),
255
- 'vu' => __( 'Vanuatu', 'polylang' ),
256
- 'wales' => __( 'Wales', 'polylang' ),
257
- 'wf' => __( 'Wallis and Futuna', 'polylang' ),
258
- 'ws' => __( 'Western Samoa', 'polylang' ),
259
- 'ye' => __( 'Yemen', 'polylang' ),
260
- 'yt' => __( 'Mayotte', 'polylang' ),
261
- 'za' => __( 'South Africa', 'polylang' ),
262
- 'zm' => __( 'Zambia', 'polylang' ),
263
- 'zw' => __( 'Zimbabwe', 'polylang' ),
264
  );
265
 
266
  /**
12
  * the value is the Country name
13
  */
14
  $flags = array(
15
+ 'ad' => __( 'Andorra', 'polylang' ),
16
+ 'ae' => __( 'United Arab Emirates', 'polylang' ),
17
+ 'af' => __( 'Afghanistan', 'polylang' ),
18
+ 'ag' => __( 'Antigua and Barbuda', 'polylang' ),
19
+ 'ai' => __( 'Anguilla', 'polylang' ),
20
+ 'al' => __( 'Albania', 'polylang' ),
21
+ 'am' => __( 'Armenia', 'polylang' ),
22
+ 'an' => __( 'Netherlands Antilles', 'polylang' ),
23
+ 'ao' => __( 'Angola', 'polylang' ),
24
+ 'ar' => __( 'Argentina', 'polylang' ),
25
+ 'arab' => __( 'Arab league', 'polylang' ),
26
+ 'as' => __( 'American Samoa', 'polylang' ),
27
+ 'at' => __( 'Austria', 'polylang' ),
28
+ 'au' => __( 'Australia', 'polylang' ),
29
+ 'aw' => __( 'Aruba', 'polylang' ),
30
+ 'ax' => __( 'Åland Islands', 'polylang' ),
31
+ 'az' => __( 'Azerbaijan', 'polylang' ),
32
+ 'ba' => __( 'Bosnia and Herzegovina', 'polylang' ),
33
+ 'basque' => __( 'Basque Country', 'polylang' ),
34
+ 'bb' => __( 'Barbados', 'polylang' ),
35
+ 'bd' => __( 'Bangladesh', 'polylang' ),
36
+ 'be' => __( 'Belgium', 'polylang' ),
37
+ 'bf' => __( 'Burkina Faso', 'polylang' ),
38
+ 'bg' => __( 'Bulgaria', 'polylang' ),
39
+ 'bh' => __( 'Bahrain', 'polylang' ),
40
+ 'bi' => __( 'Burundi', 'polylang' ),
41
+ 'bj' => __( 'Benin', 'polylang' ),
42
+ 'bm' => __( 'Bermuda', 'polylang' ),
43
+ 'bn' => __( 'Brunei', 'polylang' ),
44
+ 'bo' => __( 'Bolivia', 'polylang' ),
45
+ 'br' => __( 'Brazil', 'polylang' ),
46
+ 'bs' => __( 'Bahamas', 'polylang' ),
47
+ 'bt' => __( 'Bhutan', 'polylang' ),
48
+ 'bw' => __( 'Botswana', 'polylang' ),
49
+ 'by' => __( 'Belarus', 'polylang' ),
50
+ 'bz' => __( 'Belize', 'polylang' ),
51
+ 'ca' => __( 'Canada', 'polylang' ),
52
  'catalonia' => __( 'Catalonia', 'polylang' ),
53
+ 'cc' => __( 'Cocos', 'polylang' ),
54
+ 'cd' => __( 'Democratic Republic of the Congo', 'polylang' ),
55
+ 'cf' => __( 'Central African Republic', 'polylang' ),
56
+ 'cg' => __( 'Congo', 'polylang' ),
57
+ 'ch' => __( 'Switzerland', 'polylang' ),
58
+ 'ci' => __( 'Ivory Coast', 'polylang' ),
59
+ 'ck' => __( 'Cook Islands', 'polylang' ),
60
+ 'cl' => __( 'Chile', 'polylang' ),
61
+ 'cm' => __( 'Cameroon', 'polylang' ),
62
+ 'cn' => __( 'China', 'polylang' ),
63
+ 'co' => __( 'Colombia', 'polylang' ),
64
+ 'cr' => __( 'Costa Rica', 'polylang' ),
65
+ 'cu' => __( 'Cuba', 'polylang' ),
66
+ 'cv' => __( 'Cape Verde', 'polylang' ),
67
+ 'cx' => __( 'Christmas Island', 'polylang' ),
68
+ 'cy' => __( 'Cyprus', 'polylang' ),
69
+ 'cz' => __( 'Czech Republic', 'polylang' ),
70
+ 'de' => __( 'Germany', 'polylang' ),
71
+ 'dj' => __( 'Djibouti', 'polylang' ),
72
+ 'dk' => __( 'Denmark', 'polylang' ),
73
+ 'dm' => __( 'Dominica', 'polylang' ),
74
+ 'do' => __( 'Dominican Republic', 'polylang' ),
75
+ 'dz' => __( 'Algeria', 'polylang' ),
76
+ 'ec' => __( 'Ecuador', 'polylang' ),
77
+ 'ee' => __( 'Estonia', 'polylang' ),
78
+ 'eg' => __( 'Egypt', 'polylang' ),
79
+ 'eh' => __( 'Western Sahara', 'polylang' ),
80
+ 'england' => __( 'England', 'polylang' ),
81
+ 'er' => __( 'Eritrea', 'polylang' ),
82
+ 'es' => __( 'Spain', 'polylang' ),
83
  'esperanto' => __( 'Esperanto', 'polylang' ),
84
+ 'et' => __( 'Ethiopia', 'polylang' ),
85
+ 'fi' => __( 'Finland', 'polylang' ),
86
+ 'fj' => __( 'Fiji', 'polylang' ),
87
+ 'fk' => __( 'Falkland Islands', 'polylang' ),
88
+ 'fm' => __( 'Micronesia', 'polylang' ),
89
+ 'fo' => __( 'Faroe Islands', 'polylang' ),
90
+ 'fr' => __( 'France', 'polylang' ),
91
+ 'ga' => __( 'Gabon', 'polylang' ),
92
+ 'galicia' => __( 'Galicia', 'polylang' ),
93
+ 'gb' => __( 'United Kingdom', 'polylang' ),
94
+ 'gd' => __( 'Grenada', 'polylang' ),
95
+ 'ge' => __( 'Georgia', 'polylang' ),
96
+ 'gh' => __( 'Ghana', 'polylang' ),
97
+ 'gi' => __( 'Gibraltar', 'polylang' ),
98
+ 'gl' => __( 'Greenland', 'polylang' ),
99
+ 'gm' => __( 'Gambia', 'polylang' ),
100
+ 'gn' => __( 'Guinea', 'polylang' ),
101
+ 'gp' => __( 'Guadeloupe', 'polylang' ),
102
+ 'gq' => __( 'Equatorial Guinea', 'polylang' ),
103
+ 'gr' => __( 'Greece', 'polylang' ),
104
+ 'gs' => __( 'South Georgia and the South Sandwich Islands', 'polylang' ),
105
+ 'gt' => __( 'Guatemala', 'polylang' ),
106
+ 'gu' => __( 'Guam', 'polylang' ),
107
+ 'gw' => __( 'Guinea-Bissau', 'polylang' ),
108
+ 'gy' => __( 'Guyana', 'polylang' ),
109
+ 'hk' => __( 'Hong Kong', 'polylang' ),
110
+ 'hm' => __( 'Heard Island and McDonald Islands', 'polylang' ),
111
+ 'hn' => __( 'Honduras', 'polylang' ),
112
+ 'hr' => __( 'Croatia', 'polylang' ),
113
+ 'ht' => __( 'Haiti', 'polylang' ),
114
+ 'hu' => __( 'Hungary', 'polylang' ),
115
+ 'id' => __( 'Indonesia', 'polylang' ),
116
+ 'ie' => __( 'Republic of Ireland', 'polylang' ),
117
+ 'il' => __( 'Israel', 'polylang' ),
118
+ 'in' => __( 'India', 'polylang' ),
119
+ 'io' => __( 'British Indian Ocean Territory', 'polylang' ),
120
+ 'iq' => __( 'Iraq', 'polylang' ),
121
+ 'ir' => __( 'Iran', 'polylang' ),
122
+ 'is' => __( 'Iceland', 'polylang' ),
123
+ 'it' => __( 'Italy', 'polylang' ),
124
+ 'jm' => __( 'Jamaica', 'polylang' ),
125
+ 'jo' => __( 'Jordan', 'polylang' ),
126
+ 'jp' => __( 'Japan', 'polylang' ),
127
+ 'ke' => __( 'Kenya', 'polylang' ),
128
+ 'kg' => __( 'Kyrgyzstan', 'polylang' ),
129
+ 'kh' => __( 'Cambodia', 'polylang' ),
130
+ 'ki' => __( 'Kiribati', 'polylang' ),
131
+ 'km' => __( 'Comoros', 'polylang' ),
132
+ 'kn' => __( 'Saint Kitts and Nevis', 'polylang' ),
133
+ 'kp' => __( 'North Korea', 'polylang' ),
134
+ 'kr' => __( 'South Korea', 'polylang' ),
135
  'kurdistan' => __( 'Kurdistan', 'polylang' ),
136
+ 'kw' => __( 'Kuwait', 'polylang' ),
137
+ 'ky' => __( 'Cayman Islands', 'polylang' ),
138
+ 'kz' => __( 'Kazakhstan', 'polylang' ),
139
+ 'la' => __( 'Laos', 'polylang' ),
140
+ 'lb' => __( 'Lebanon', 'polylang' ),
141
+ 'lc' => __( 'Saint Lucia', 'polylang' ),
142
+ 'li' => __( 'Liechtenstein', 'polylang' ),
143
+ 'lk' => __( 'Sri Lanka', 'polylang' ),
144
+ 'lr' => __( 'Liberia', 'polylang' ),
145
+ 'ls' => __( 'Lesotho', 'polylang' ),
146
+ 'lt' => __( 'Lithuania', 'polylang' ),
147
+ 'lu' => __( 'Luxembourg', 'polylang' ),
148
+ 'lv' => __( 'Latvia', 'polylang' ),
149
+ 'ly' => __( 'Libya', 'polylang' ),
150
+ 'ma' => __( 'Morocco', 'polylang' ),
151
+ 'mc' => __( 'Monaco', 'polylang' ),
152
+ 'md' => __( 'Moldova', 'polylang' ),
153
+ 'me' => __( 'Montenegro', 'polylang' ),
154
+ 'mg' => __( 'Madagascar', 'polylang' ),
155
+ 'mh' => __( 'Marshall Islands', 'polylang' ),
156
+ 'mk' => __( 'Macedonia', 'polylang' ),
157
+ 'ml' => __( 'Mali', 'polylang' ),
158
+ 'mm' => __( 'Myanmar', 'polylang' ),
159
+ 'mn' => __( 'Mongolia', 'polylang' ),
160
+ 'mo' => __( 'Macao', 'polylang' ),
161
+ 'mp' => __( 'Northern Mariana Islands', 'polylang' ),
162
+ 'mq' => __( 'Martinique', 'polylang' ),
163
+ 'mr' => __( 'Mauritania', 'polylang' ),
164
+ 'ms' => __( 'Montserrat', 'polylang' ),
165
+ 'mt' => __( 'Malta', 'polylang' ),
166
+ 'mu' => __( 'Mauritius', 'polylang' ),
167
+ 'mv' => __( 'Maldives', 'polylang' ),
168
+ 'mw' => __( 'Malawi', 'polylang' ),
169
+ 'mx' => __( 'Mexico', 'polylang' ),
170
+ 'my' => __( 'Malaysia', 'polylang' ),
171
+ 'mz' => __( 'Mozambique', 'polylang' ),
172
+ 'na' => __( 'Namibia', 'polylang' ),
173
+ 'nc' => __( 'New Caledonia', 'polylang' ),
174
+ 'ne' => __( 'Niger', 'polylang' ),
175
+ 'nf' => __( 'Norfolk Island', 'polylang' ),
176
+ 'ng' => __( 'Nigeria', 'polylang' ),
177
+ 'ni' => __( 'Nicaragua', 'polylang' ),
178
+ 'nl' => __( 'Netherlands', 'polylang' ),
179
+ 'no' => __( 'Norway', 'polylang' ),
180
+ 'np' => __( 'Nepal', 'polylang' ),
181
+ 'nr' => __( 'Nauru', 'polylang' ),
182
+ 'nu' => __( 'Niue', 'polylang' ),
183
+ 'nz' => __( 'New Zealand', 'polylang' ),
184
  'occitania' => __( 'Occitania', 'polylang' ),
185
+ 'om' => __( 'Oman', 'polylang' ),
186
+ 'pa' => __( 'Panama', 'polylang' ),
187
+ 'pe' => __( 'Peru', 'polylang' ),
188
+ 'pf' => __( 'French Polynesia', 'polylang' ),
189
+ 'pg' => __( 'Papua New Guinea', 'polylang' ),
190
+ 'ph' => __( 'Philippines', 'polylang' ),
191
+ 'pk' => __( 'Pakistan', 'polylang' ),
192
+ 'pl' => __( 'Poland', 'polylang' ),
193
+ 'pm' => __( 'Saint Pierre and Miquelon', 'polylang' ),
194
+ 'pn' => __( 'Pitcairn', 'polylang' ),
195
+ 'pr' => __( 'Puerto Rico', 'polylang' ),
196
+ 'ps' => __( 'Palestinian Territory', 'polylang' ),
197
+ 'pt' => __( 'Portugal', 'polylang' ),
198
+ 'pw' => __( 'Belau', 'polylang' ),
199
+ 'py' => __( 'Paraguay', 'polylang' ),
200
+ 'qa' => __( 'Qatar', 'polylang' ),
201
+ 'quebec' => __( 'Quebec', 'polylang' ),
202
+ 'ro' => __( 'Romania', 'polylang' ),
203
+ 'rs' => __( 'Serbia', 'polylang' ),
204
+ 'ru' => __( 'Russia', 'polylang' ),
205
+ 'rw' => __( 'Rwanda', 'polylang' ),
206
+ 'sa' => __( 'Saudi Arabia', 'polylang' ),
207
+ 'sb' => __( 'Solomon Islands', 'polylang' ),
208
+ 'sc' => __( 'Seychelles', 'polylang' ),
209
+ 'scotland' => __( 'Scotland', 'polylang' ),
210
+ 'sd' => __( 'Sudan', 'polylang' ),
211
+ 'se' => __( 'Sweden', 'polylang' ),
212
+ 'sg' => __( 'Singapore', 'polylang' ),
213
+ 'sh' => __( 'Saint Helena', 'polylang' ),
214
+ 'si' => __( 'Slovenia', 'polylang' ),
215
+ 'sk' => __( 'Slovakia', 'polylang' ),
216
+ 'sl' => __( 'Sierra Leone', 'polylang' ),
217
+ 'sm' => __( 'San Marino', 'polylang' ),
218
+ 'sn' => __( 'Senegal', 'polylang' ),
219
+ 'so' => __( 'Somalia', 'polylang' ),
220
+ 'sr' => __( 'Suriname', 'polylang' ),
221
+ 'ss' => __( 'South Sudan', 'polylang' ),
222
+ 'st' => __( 'São Tomé and Príncipe', 'polylang' ),
223
+ 'sv' => __( 'El Salvador', 'polylang' ),
224
+ 'sy' => __( 'Syria', 'polylang' ),
225
+ 'sz' => __( 'Swaziland', 'polylang' ),
226
+ 'tc' => __( 'Turks and Caicos Islands', 'polylang' ),
227
+ 'td' => __( 'Chad', 'polylang' ),
228
+ 'tf' => __( 'French Southern Territories', 'polylang' ),
229
+ 'tg' => __( 'Togo', 'polylang' ),
230
+ 'th' => __( 'Thailand', 'polylang' ),
231
+ 'tibet' => __( 'Tibet', 'polylang' ),
232
+ 'tj' => __( 'Tajikistan', 'polylang' ),
233
+ 'tk' => __( 'Tokelau', 'polylang' ),
234
+ 'tl' => __( 'Timor-Leste', 'polylang' ),
235
+ 'tm' => __( 'Turkmenistan', 'polylang' ),
236
+ 'tn' => __( 'Tunisia', 'polylang' ),
237
+ 'to' => __( 'Tonga', 'polylang' ),
238
+ 'tr' => __( 'Turkey', 'polylang' ),
239
+ 'tt' => __( 'Trinidad and Tobago', 'polylang' ),
240
+ 'tv' => __( 'Tuvalu', 'polylang' ),
241
+ 'tw' => __( 'Taiwan', 'polylang' ),
242
+ 'tz' => __( 'Tanzania', 'polylang' ),
243
+ 'ua' => __( 'Ukraine', 'polylang' ),
244
+ 'ug' => __( 'Uganda', 'polylang' ),
245
+ 'us' => __( 'United States', 'polylang' ),
246
+ 'uy' => __( 'Uruguay', 'polylang' ),
247
+ 'uz' => __( 'Uzbekistan', 'polylang' ),
248
+ 'va' => __( 'Vatican', 'polylang' ),
249
+ 'vc' => __( 'Saint Vincent and the Grenadines', 'polylang' ),
250
+ 've' => __( 'Venezuela', 'polylang' ),
251
+ 'veneto' => __( 'Veneto', 'polylang' ),
252
+ 'vg' => __( 'British Virgin Islands', 'polylang' ),
253
+ 'vi' => __( 'United States Virgin Islands', 'polylang' ),
254
+ 'vn' => __( 'Vietnam', 'polylang' ),
255
+ 'vu' => __( 'Vanuatu', 'polylang' ),
256
+ 'wales' => __( 'Wales', 'polylang' ),
257
+ 'wf' => __( 'Wallis and Futuna', 'polylang' ),
258
+ 'ws' => __( 'Western Samoa', 'polylang' ),
259
+ 'ye' => __( 'Yemen', 'polylang' ),
260
+ 'yt' => __( 'Mayotte', 'polylang' ),
261
+ 'za' => __( 'South Africa', 'polylang' ),
262
+ 'zm' => __( 'Zambia', 'polylang' ),
263
+ 'zw' => __( 'Zimbabwe', 'polylang' ),
264
  );
265
 
266
  /**
settings/settings-browser.php CHANGED
@@ -15,12 +15,15 @@ class PLL_Settings_Browser extends PLL_Settings_Module {
15
  * @param object $polylang polylang object
16
  */
17
  public function __construct( &$polylang ) {
18
- parent::__construct( $polylang, array(
19
- 'module' => 'browser',
20
- 'title' => __( 'Detect browser language', 'polylang' ),
21
- 'description' => __( 'When the front page is visited, set the language according to the browser preference', 'polylang' ),
22
- 'active_option' => $this->is_available() ? 'browser' : false,
23
- ) );
 
 
 
24
 
25
  if ( ! class_exists( 'PLL_Xdata_Domain', true ) ) {
26
  add_action( 'admin_print_footer_scripts', array( $this, 'print_js' ) );
15
  * @param object $polylang polylang object
16
  */
17
  public function __construct( &$polylang ) {
18
+ parent::__construct(
19
+ $polylang,
20
+ array(
21
+ 'module' => 'browser',
22
+ 'title' => __( 'Detect browser language', 'polylang' ),
23
+ 'description' => __( 'When the front page is visited, set the language according to the browser preference', 'polylang' ),
24
+ 'active_option' => $this->is_available() ? 'browser' : false,
25
+ )
26
+ );
27
 
28
  if ( ! class_exists( 'PLL_Xdata_Domain', true ) ) {
29
  add_action( 'admin_print_footer_scripts', array( $this, 'print_js' ) );
settings/settings-cpt.php CHANGED
@@ -16,11 +16,14 @@ class PLL_Settings_CPT extends PLL_Settings_Module {
16
  * @param object $polylang polylang object
17
  */
18
  public function __construct( &$polylang ) {
19
- parent::__construct( $polylang, array(
20
- 'module' => 'cpt',
21
- 'title' => __( 'Custom post types and Taxonomies', 'polylang' ),
22
- 'description' => __( 'Activate the languages and translations management for the custom post types and taxonomies.', 'polylang' ),
23
- ) );
 
 
 
24
 
25
  $public_post_types = get_post_types( array( 'public' => true, '_builtin' => false ) );
26
  /** This filter is documented in include/model.php */
16
  * @param object $polylang polylang object
17
  */
18
  public function __construct( &$polylang ) {
19
+ parent::__construct(
20
+ $polylang,
21
+ array(
22
+ 'module' => 'cpt',
23
+ 'title' => __( 'Custom post types and Taxonomies', 'polylang' ),
24
+ 'description' => __( 'Activate the languages and translations management for the custom post types and taxonomies.', 'polylang' ),
25
+ )
26
+ );
27
 
28
  $public_post_types = get_post_types( array( 'public' => true, '_builtin' => false ) );
29
  /** This filter is documented in include/model.php */
settings/settings-licenses.php CHANGED
@@ -16,11 +16,14 @@ class PLL_Settings_Licenses extends PLL_Settings_Module {
16
  * @param object $polylang polylang object
17
  */
18
  public function __construct( &$polylang ) {
19
- parent::__construct( $polylang, array(
20
- 'module' => 'licenses',
21
- 'title' => __( 'License keys', 'polylang' ),
22
- 'description' => __( 'Manage licenses for Polylang Pro or addons.', 'polylang' ),
23
- ) );
 
 
 
24
 
25
  $this->buttons['cancel'] = sprintf( '<button type="button" class="button button-secondary cancel">%s</button>', __( 'Close' ) );
26
 
@@ -76,7 +79,9 @@ class PLL_Settings_Licenses extends PLL_Settings_Module {
76
  $out = sprintf(
77
  '<td><label for="pll-licenses[%1$s]">%2$s</label></td>' .
78
  '<td><input name="licenses[%1$s]" id="pll-licenses[%1$s]" type="text" value="%3$s" class="regular-text code" />',
79
- esc_attr( $item->id ), esc_attr( $item->name ), esc_html( $item->license_key )
 
 
80
  );
81
 
82
  if ( ! empty( $license ) && is_object( $license ) ) {
@@ -211,9 +216,11 @@ class PLL_Settings_Licenses extends PLL_Settings_Module {
211
  }
212
 
213
  $id = sanitize_text_field( substr( $_POST['id'], 11 ) );
214
- wp_send_json( array(
215
- 'id' => $id,
216
- 'html' => $this->get_row( $this->items[ $id ]->deactivate_license() ),
217
- ) );
 
 
218
  }
219
  }
16
  * @param object $polylang polylang object
17
  */
18
  public function __construct( &$polylang ) {
19
+ parent::__construct(
20
+ $polylang,
21
+ array(
22
+ 'module' => 'licenses',
23
+ 'title' => __( 'License keys', 'polylang' ),
24
+ 'description' => __( 'Manage licenses for Polylang Pro or addons.', 'polylang' ),
25
+ )
26
+ );
27
 
28
  $this->buttons['cancel'] = sprintf( '<button type="button" class="button button-secondary cancel">%s</button>', __( 'Close' ) );
29
 
79
  $out = sprintf(
80
  '<td><label for="pll-licenses[%1$s]">%2$s</label></td>' .
81
  '<td><input name="licenses[%1$s]" id="pll-licenses[%1$s]" type="text" value="%3$s" class="regular-text code" />',
82
+ esc_attr( $item->id ),
83
+ esc_attr( $item->name ),
84
+ esc_html( $item->license_key )
85
  );
86
 
87
  if ( ! empty( $license ) && is_object( $license ) ) {
216
  }
217
 
218
  $id = sanitize_text_field( substr( $_POST['id'], 11 ) );
219
+ wp_send_json(
220
+ array(
221
+ 'id' => $id,
222
+ 'html' => $this->get_row( $this->items[ $id ]->deactivate_license() ),
223
+ )
224
+ );
225
  }
226
  }
settings/settings-media.php CHANGED
@@ -15,11 +15,14 @@ class PLL_Settings_Media extends PLL_Settings_Module {
15
  * @param object $polylang polylang object
16
  */
17
  public function __construct( &$polylang ) {
18
- parent::__construct( $polylang, array(
19
- 'module' => 'media',
20
- 'title' => __( 'Media' ),
21
- 'description' => __( 'Activate languages and translations for media', 'polylang' ),
22
- 'active_option' => 'media_support',
23
- ) );
 
 
 
24
  }
25
  }
15
  * @param object $polylang polylang object
16
  */
17
  public function __construct( &$polylang ) {
18
+ parent::__construct(
19
+ $polylang,
20
+ array(
21
+ 'module' => 'media',
22
+ 'title' => __( 'Media' ),
23
+ 'description' => __( 'Activate languages and translations for media', 'polylang' ),
24
+ 'active_option' => 'media_support',
25
+ )
26
+ );
27
  }
28
  }
settings/settings-module.php CHANGED
@@ -24,11 +24,14 @@ class PLL_Settings_Module {
24
  $this->model = &$polylang->model;
25
  $this->links_model = &$polylang->links_model;
26
 
27
- $args = wp_parse_args( $args, array(
28
- 'title' => '',
29
- 'description' => '',
30
- 'active_option' => false,
31
- ) );
 
 
 
32
 
33
  foreach ( $args as $prop => $value ) {
34
  $this->$prop = $value;
@@ -36,29 +39,25 @@ class PLL_Settings_Module {
36
 
37
  // All possible action links, even if not always a link ;-)
38
  $this->action_links = array(
39
- 'configure' => sprintf(
40
  '<a title="%s" href="%s">%s</a>',
41
  esc_attr__( 'Configure this module', 'polylang' ),
42
  '#',
43
  esc_html__( 'Settings', 'polylang' )
44
  ),
45
-
46
- 'deactivate' => sprintf(
47
  '<a title="%s" href="%s">%s</a>',
48
  esc_attr__( 'Deactivate this module', 'polylang' ),
49
  wp_nonce_url( '?page=mlang&amp;tab=modules&amp;pll_action=deactivate&amp;noheader=true&amp;module=' . $this->module, 'pll_deactivate' ),
50
  esc_html__( 'Deactivate', 'polylang' )
51
  ),
52
-
53
- 'activate' => sprintf(
54
  '<a title="%s" href="%s">%s</a>',
55
  esc_attr__( 'Activate this module', 'polylang' ),
56
  wp_nonce_url( '?page=mlang&amp;tab=modules&amp;pll_action=activate&amp;noheader=true&amp;module=' . $this->module, 'pll_activate' ),
57
  esc_html__( 'Activate', 'polylang' )
58
  ),
59
-
60
- 'activated' => esc_html__( 'Activated', 'polylang' ),
61
-
62
  'deactivated' => esc_html__( 'Deactivated', 'polylang' ),
63
  );
64
 
24
  $this->model = &$polylang->model;
25
  $this->links_model = &$polylang->links_model;
26
 
27
+ $args = wp_parse_args(
28
+ $args,
29
+ array(
30
+ 'title' => '',
31
+ 'description' => '',
32
+ 'active_option' => false,
33
+ )
34
+ );
35
 
36
  foreach ( $args as $prop => $value ) {
37
  $this->$prop = $value;
39
 
40
  // All possible action links, even if not always a link ;-)
41
  $this->action_links = array(
42
+ 'configure' => sprintf(
43
  '<a title="%s" href="%s">%s</a>',
44
  esc_attr__( 'Configure this module', 'polylang' ),
45
  '#',
46
  esc_html__( 'Settings', 'polylang' )
47
  ),
48
+ 'deactivate' => sprintf(
 
49
  '<a title="%s" href="%s">%s</a>',
50
  esc_attr__( 'Deactivate this module', 'polylang' ),
51
  wp_nonce_url( '?page=mlang&amp;tab=modules&amp;pll_action=deactivate&amp;noheader=true&amp;module=' . $this->module, 'pll_deactivate' ),
52
  esc_html__( 'Deactivate', 'polylang' )
53
  ),
54
+ 'activate' => sprintf(
 
55
  '<a title="%s" href="%s">%s</a>',
56
  esc_attr__( 'Activate this module', 'polylang' ),
57
  wp_nonce_url( '?page=mlang&amp;tab=modules&amp;pll_action=activate&amp;noheader=true&amp;module=' . $this->module, 'pll_activate' ),
58
  esc_html__( 'Activate', 'polylang' )
59
  ),
60
+ 'activated' => esc_html__( 'Activated', 'polylang' ),
 
 
61
  'deactivated' => esc_html__( 'Deactivated', 'polylang' ),
62
  );
63
 
settings/settings-tools.php CHANGED
@@ -15,11 +15,14 @@ class PLL_Settings_Tools extends PLL_Settings_Module {
15
  * @param object $polylang polylang object
16
  */
17
  public function __construct( &$polylang ) {
18
- parent::__construct( $polylang, array(
19
- 'module' => 'tools',
20
- 'title' => __( 'Tools', 'polylang' ),
21
- 'description' => __( 'Decide whether to remove all data when deleting Polylang.', 'polylang' ),
22
- ) );
 
 
 
23
  }
24
 
25
  /**
15
  * @param object $polylang polylang object
16
  */
17
  public function __construct( &$polylang ) {
18
+ parent::__construct(
19
+ $polylang,
20
+ array(
21
+ 'module' => 'tools',
22
+ 'title' => __( 'Tools', 'polylang' ),
23
+ 'description' => __( 'Decide whether to remove all data when deleting Polylang.', 'polylang' ),
24
+ )
25
+ );
26
  }
27
 
28
  /**
settings/settings-url.php CHANGED
@@ -15,12 +15,15 @@ class PLL_Settings_Url extends PLL_Settings_Module {
15
  * @param object $polylang
16
  */
17
  public function __construct( &$polylang ) {
18
- parent::__construct( $polylang, array(
19
- 'module' => 'url',
20
- 'title' => __( 'URL modifications', 'polylang' ),
21
- 'description' => __( 'Decide how your URLs will look like.', 'polylang' ),
22
- 'configure' => true,
23
- ) );
 
 
 
24
 
25
  $this->links_model = &$polylang->links_model;
26
  $this->page_on_front = &$polylang->static_pages->page_on_front;
@@ -227,10 +230,17 @@ class PLL_Settings_Url extends PLL_Settings_Module {
227
  foreach ( $options['domains'] as $key => $domain ) {
228
  if ( empty( $domain ) ) {
229
  $lang = $this->model->get_language( $key );
230
- add_settings_error( 'general', 'pll_invalid_domain', esc_html( sprintf(
231
- /* translators: %s is a native language name */
232
- __( 'Please enter a valid URL for %s.', 'polylang' ), $lang->name
233
- ) ) );
 
 
 
 
 
 
 
234
  }
235
  else {
236
  $newoptions['domains'][ $key ] = esc_url_raw( trim( $domain ) );
@@ -275,10 +285,17 @@ class PLL_Settings_Url extends PLL_Settings_Module {
275
  $response_code = wp_remote_retrieve_response_code( $response );
276
 
277
  if ( 200 != $response_code ) {
278
- add_settings_error( 'general', 'pll_invalid_domain', esc_html( sprintf(
279
- /* translators: %s is an url */
280
- __( 'Polylang was unable to access the URL %s. Please check that the URL is valid.', 'polylang' ), $url
281
- ) ) );
 
 
 
 
 
 
 
282
  }
283
  }
284
  }
15
  * @param object $polylang
16
  */
17
  public function __construct( &$polylang ) {
18
+ parent::__construct(
19
+ $polylang,
20
+ array(
21
+ 'module' => 'url',
22
+ 'title' => __( 'URL modifications', 'polylang' ),
23
+ 'description' => __( 'Decide how your URLs will look like.', 'polylang' ),
24
+ 'configure' => true,
25
+ )
26
+ );
27
 
28
  $this->links_model = &$polylang->links_model;
29
  $this->page_on_front = &$polylang->static_pages->page_on_front;
230
  foreach ( $options['domains'] as $key => $domain ) {
231
  if ( empty( $domain ) ) {
232
  $lang = $this->model->get_language( $key );
233
+ add_settings_error(
234
+ 'general',
235
+ 'pll_invalid_domain',
236
+ esc_html(
237
+ sprintf(
238
+ /* translators: %s is a native language name */
239
+ __( 'Please enter a valid URL for %s.', 'polylang' ),
240
+ $lang->name
241
+ )
242
+ )
243
+ );
244
  }
245
  else {
246
  $newoptions['domains'][ $key ] = esc_url_raw( trim( $domain ) );
285
  $response_code = wp_remote_retrieve_response_code( $response );
286
 
287
  if ( 200 != $response_code ) {
288
+ add_settings_error(
289
+ 'general',
290
+ 'pll_invalid_domain',
291
+ esc_html(
292
+ sprintf(
293
+ /* translators: %s is an url */
294
+ __( 'Polylang was unable to access the URL %s. Please check that the URL is valid.', 'polylang' ),
295
+ $url
296
+ )
297
+ )
298
+ );
299
  }
300
  }
301
  }
settings/settings.php CHANGED
@@ -58,16 +58,19 @@ class PLL_Settings extends PLL_Admin_Base {
58
  );
59
 
60
  if ( $this->model->get_languages_list() ) {
61
- $modules = array_merge( array(
62
- 'PLL_Settings_Url',
63
- 'PLL_Settings_Browser',
64
- 'PLL_Settings_Media',
65
- 'PLL_Settings_CPT',
66
- 'PLL_Settings_Sync',
67
- 'PLL_Settings_WPML',
68
- 'PLL_Settings_Share_Slug',
69
- 'PLL_Settings_Translate_Slugs',
70
- ), $modules );
 
 
 
71
  }
72
 
73
  /**
@@ -110,11 +113,14 @@ class PLL_Settings extends PLL_Admin_Base {
110
  );
111
  }
112
 
113
- add_screen_option( 'per_page', array(
114
- 'label' => __( 'Languages', 'polylang' ),
115
- 'default' => 10,
116
- 'option' => 'pll_lang_per_page',
117
- ) );
 
 
 
118
 
119
  add_action( 'admin_notices', array( $this, 'notice_objects_with_no_lang' ) );
120
  }
@@ -125,11 +131,14 @@ class PLL_Settings extends PLL_Admin_Base {
125
  * @since 2.1
126
  */
127
  public function load_page_strings() {
128
- add_screen_option( 'per_page', array(
129
- 'label' => __( 'Strings translations', 'polylang' ),
130
- 'default' => 10,
131
- 'option' => 'pll_strings_per_page',
132
- ) );
 
 
 
133
  }
134
 
135
  /**
@@ -307,7 +316,7 @@ class PLL_Settings extends PLL_Admin_Base {
307
  *
308
  * @param array $args query arguments to add to the url
309
  */
310
- static public function redirect( $args = array() ) {
311
  if ( $errors = get_settings_errors() ) {
312
  set_transient( 'settings_errors', $errors, 30 );
313
  $args['settings-updated'] = 1;
@@ -323,7 +332,7 @@ class PLL_Settings extends PLL_Admin_Base {
323
  * @since 2.3
324
  */
325
  public function get_predefined_languages() {
326
- require_once( ABSPATH . 'wp-admin/includes/translation-install.php' );
327
  include PLL_SETTINGS_INC . '/languages.php';
328
 
329
  $translations = wp_get_available_translations();
58
  );
59
 
60
  if ( $this->model->get_languages_list() ) {
61
+ $modules = array_merge(
62
+ array(
63
+ 'PLL_Settings_Url',
64
+ 'PLL_Settings_Browser',
65
+ 'PLL_Settings_Media',
66
+ 'PLL_Settings_CPT',
67
+ 'PLL_Settings_Sync',
68
+ 'PLL_Settings_WPML',
69
+ 'PLL_Settings_Share_Slug',
70
+ 'PLL_Settings_Translate_Slugs',
71
+ ),
72
+ $modules
73
+ );
74
  }
75
 
76
  /**
113
  );
114
  }
115
 
116
+ add_screen_option(
117
+ 'per_page',
118
+ array(
119
+ 'label' => __( 'Languages', 'polylang' ),
120
+ 'default' => 10,
121
+ 'option' => 'pll_lang_per_page',
122
+ )
123
+ );
124
 
125
  add_action( 'admin_notices', array( $this, 'notice_objects_with_no_lang' ) );
126
  }
131
  * @since 2.1
132
  */
133
  public function load_page_strings() {
134
+ add_screen_option(
135
+ 'per_page',
136
+ array(
137
+ 'label' => __( 'Strings translations', 'polylang' ),
138
+ 'default' => 10,
139
+ 'option' => 'pll_strings_per_page',
140
+ )
141
+ );
142
  }
143
 
144
  /**
316
  *
317
  * @param array $args query arguments to add to the url
318
  */
319
+ public static function redirect( $args = array() ) {
320
  if ( $errors = get_settings_errors() ) {
321
  set_transient( 'settings_errors', $errors, 30 );
322
  $args['settings-updated'] = 1;
332
  * @since 2.3
333
  */
334
  public function get_predefined_languages() {
335
+ require_once ABSPATH . 'wp-admin/includes/translation-install.php';
336
  include PLL_SETTINGS_INC . '/languages.php';
337
 
338
  $translations = wp_get_available_translations();
settings/table-languages.php CHANGED
@@ -17,11 +17,13 @@ class PLL_Table_Languages extends WP_List_Table {
17
  *
18
  * @since 0.1
19
  */
20
- function __construct() {
21
- parent::__construct( array(
22
- 'plural' => 'Languages', // Do not translate ( used for css class )
23
- 'ajax' => false,
24
- ) );
 
 
25
  }
26
 
27
  /**
@@ -55,7 +57,7 @@ class PLL_Table_Languages extends WP_List_Table {
55
  * @param string $column_name
56
  * @return string
57
  */
58
- function column_default( $item, $column_name ) {
59
  switch ( $column_name ) {
60
  case 'locale':
61
  case 'slug':
@@ -79,7 +81,7 @@ class PLL_Table_Languages extends WP_List_Table {
79
  * @param object $item
80
  * @return string
81
  */
82
- function column_name( $item ) {
83
  return sprintf(
84
  '<a title="%s" href="%s">%s</a>',
85
  esc_attr__( 'Edit this language', 'polylang' ),
@@ -97,12 +99,12 @@ class PLL_Table_Languages extends WP_List_Table {
97
  * @param object $item
98
  * @return string
99
  */
100
- function column_default_lang( $item ) {
101
  $options = get_option( 'polylang' );
102
 
103
  if ( $options['default_lang'] != $item->slug ) {
104
- $s = sprintf('
105
- <div class="row-actions"><span class="default-lang">
106
  <a class="icon-default-lang" title="%1$s" href="%2$s"><span class="screen-reader-text">%3$s</span></a>
107
  </span></div>',
108
  esc_attr__( 'Select as default language', 'polylang' ),
@@ -139,7 +141,7 @@ class PLL_Table_Languages extends WP_List_Table {
139
  *
140
  * @return array the list of column titles
141
  */
142
- function get_columns() {
143
  return array(
144
  'name' => esc_html__( 'Full name', 'polylang' ),
145
  'locale' => esc_html__( 'Locale', 'polylang' ),
@@ -158,7 +160,7 @@ class PLL_Table_Languages extends WP_List_Table {
158
  *
159
  * @return array
160
  */
161
- function get_sortable_columns() {
162
  return array(
163
  'name' => array( 'name', true ), // sorted by name by default
164
  'locale' => array( 'locale', false ),
@@ -251,7 +253,7 @@ class PLL_Table_Languages extends WP_List_Table {
251
  *
252
  * @param array $data
253
  */
254
- function prepare_items( $data = array() ) {
255
  $per_page = $this->get_items_per_page( 'pll_lang_per_page' );
256
  $this->_column_headers = array( $this->get_columns(), array(), $this->get_sortable_columns() );
257
 
@@ -260,10 +262,12 @@ class PLL_Table_Languages extends WP_List_Table {
260
  $total_items = count( $data );
261
  $this->items = array_slice( $data, ( $this->get_pagenum() - 1 ) * $per_page, $per_page );
262
 
263
- $this->set_pagination_args( array(
264
- 'total_items' => $total_items,
265
- 'per_page' => $per_page,
266
- 'total_pages' => ceil( $total_items / $per_page ),
267
- ) );
 
 
268
  }
269
  }
17
  *
18
  * @since 0.1
19
  */
20
+ public function __construct() {
21
+ parent::__construct(
22
+ array(
23
+ 'plural' => 'Languages', // Do not translate ( used for css class )
24
+ 'ajax' => false,
25
+ )
26
+ );
27
  }
28
 
29
  /**
57
  * @param string $column_name
58
  * @return string
59
  */
60
+ public function column_default( $item, $column_name ) {
61
  switch ( $column_name ) {
62
  case 'locale':
63
  case 'slug':
81
  * @param object $item
82
  * @return string
83
  */
84
+ public function column_name( $item ) {
85
  return sprintf(
86
  '<a title="%s" href="%s">%s</a>',
87
  esc_attr__( 'Edit this language', 'polylang' ),
99
  * @param object $item
100
  * @return string
101
  */
102
+ public function column_default_lang( $item ) {
103
  $options = get_option( 'polylang' );
104
 
105
  if ( $options['default_lang'] != $item->slug ) {
106
+ $s = sprintf(
107
+ '<div class="row-actions"><span class="default-lang">
108
  <a class="icon-default-lang" title="%1$s" href="%2$s"><span class="screen-reader-text">%3$s</span></a>
109
  </span></div>',
110
  esc_attr__( 'Select as default language', 'polylang' ),
141
  *
142
  * @return array the list of column titles
143
  */
144
+ public function get_columns() {
145
  return array(
146
  'name' => esc_html__( 'Full name', 'polylang' ),
147
  'locale' => esc_html__( 'Locale', 'polylang' ),
160
  *
161
  * @return array
162
  */
163
+ public function get_sortable_columns() {
164
  return array(
165
  'name' => array( 'name', true ), // sorted by name by default
166
  'locale' => array( 'locale', false ),
253
  *
254
  * @param array $data
255
  */
256
+ public function prepare_items( $data = array() ) {
257
  $per_page = $this->get_items_per_page( 'pll_lang_per_page' );
258
  $this->_column_headers = array( $this->get_columns(), array(), $this->get_sortable_columns() );
259
 
262
  $total_items = count( $data );
263
  $this->items = array_slice( $data, ( $this->get_pagenum() - 1 ) * $per_page, $per_page );
264
 
265
+ $this->set_pagination_args(
266
+ array(
267
+ 'total_items' => $total_items,
268
+ 'per_page' => $per_page,
269
+ 'total_pages' => ceil( $total_items / $per_page ),
270
+ )
271
+ );
272
  }
273
  }
settings/table-settings.php CHANGED
@@ -16,11 +16,13 @@ class PLL_Table_Settings extends WP_List_Table {
16
  *
17
  * @since 1.8
18
  */
19
- function __construct() {
20
- parent::__construct( array(
21
- 'plural' => 'Settings', // Do not translate ( used for css class )
22
- 'ajax' => false,
23
- ) );
 
 
24
  }
25
 
26
  /**
@@ -53,24 +55,19 @@ class PLL_Table_Settings extends WP_List_Table {
53
 
54
  // Display an upgrade message if there is any, reusing css from the plugins updates
55
  if ( $message = $item->get_upgrade_message() ) {
56
- printf( '
57
- <tr class="plugin-update-tr">
58
  <td colspan="3" class="plugin-update colspanchange">%s</td>
59
  </tr>',
60
- sprintf(
61
- version_compare( $GLOBALS['wp_version'], '4.6', '<' ) ?
62
- '<div class="update-message">%s</div>' : // backward compatibility with WP < 4.6
63
- '<div class="update-message notice inline notice-warning notice-alt"><p>%s</p></div>',
64
- $message
65
- )
66
  );
67
  }
68
 
69
  // The settings if there are
70
  // "inactive" class to reuse css from the plugins list table
71
  if ( $form = $item->get_form() ) {
72
- printf( '
73
- <tr id="pll-configure-%s" class="pll-configure inactive inline-edit-row" style="display: none;">
74
  <td colspan="3">
75
  <legend>%s</legend>
76
  %s
@@ -79,7 +76,10 @@ class PLL_Table_Settings extends WP_List_Table {
79
  </p>
80
  </td>
81
  </tr>',
82
- esc_attr( $item->module ), esc_html( $item->title ), $form, implode( $item->get_buttons() )
 
 
 
83
  );
84
  }
85
  }
16
  *
17
  * @since 1.8
18
  */
19
+ public function __construct() {
20
+ parent::__construct(
21
+ array(
22
+ 'plural' => 'Settings', // Do not translate ( used for css class )
23
+ 'ajax' => false,
24
+ )
25
+ );
26
  }
27
 
28
  /**
55
 
56
  // Display an upgrade message if there is any, reusing css from the plugins updates
57
  if ( $message = $item->get_upgrade_message() ) {
58
+ printf(
59
+ '<tr class="plugin-update-tr">
60
  <td colspan="3" class="plugin-update colspanchange">%s</td>
61
  </tr>',
62
+ sprintf( '<div class="update-message notice inline notice-warning notice-alt"><p>%s</p></div>', $message )
 
 
 
 
 
63
  );
64
  }
65
 
66
  // The settings if there are
67
  // "inactive" class to reuse css from the plugins list table
68
  if ( $form = $item->get_form() ) {
69
+ printf(
70
+ '<tr id="pll-configure-%s" class="pll-configure inactive inline-edit-row" style="display: none;">
71
  <td colspan="3">
72
  <legend>%s</legend>
73
  %s
76
  </p>
77
  </td>
78
  </tr>',
79
+ esc_attr( $item->module ),
80
+ esc_html( $item->title ),
81
+ $form,
82
+ implode( $item->get_buttons() )
83
  );
84
  }
85
  }
settings/table-string.php CHANGED
@@ -20,11 +20,13 @@ class PLL_Table_String extends WP_List_Table {
20
  *
21
  * @param array $languages list of languages
22
  */
23
- function __construct( $languages ) {
24
- parent::__construct( array(
25
- 'plural' => 'Strings translations', // Do not translate ( used for css class )
26
- 'ajax' => false,
27
- ) );
 
 
28
 
29
  $this->languages = $languages;
30
  $this->strings = PLL_Admin_Strings::get_strings();
@@ -43,7 +45,7 @@ class PLL_Table_String extends WP_List_Table {
43
  * @param string $column_name
44
  * @return string
45
  */
46
- function column_default( $item, $column_name ) {
47
  return $item[ $column_name ];
48
  }
49
 
@@ -55,7 +57,7 @@ class PLL_Table_String extends WP_List_Table {
55
  * @param array $item
56
  * @return string
57
  */
58
- function column_cb( $item ) {
59
  return sprintf(
60
  '<label class="screen-reader-text" for="cb-select-%1$s">%2$s</label><input id="cb-select-%1$s" type="checkbox" name="strings[]" value="%1$s" %3$s />',
61
  esc_attr( $item['row'] ),
@@ -73,7 +75,7 @@ class PLL_Table_String extends WP_List_Table {
73
  * @param array $item
74
  * @return string
75
  */
76
- function column_string( $item ) {
77
  return format_to_edit( $item['string'] ); // Don't interpret special chars for the string column
78
  }
79
 
@@ -85,7 +87,7 @@ class PLL_Table_String extends WP_List_Table {
85
  * @param array $item
86
  * @return string
87
  */
88
- function column_translations( $item ) {
89
  $languages = array_combine( wp_list_pluck( $this->languages, 'slug' ), wp_list_pluck( $this->languages, 'name' ) );
90
  $out = '';
91
 
@@ -93,11 +95,13 @@ class PLL_Table_String extends WP_List_Table {
93
  $input_type = $item['multiline'] ?
94
  '<textarea name="translation[%1$s][%2$s]" id="%1$s-%2$s">%4$s</textarea>' :
95
  '<input type="text" name="translation[%1$s][%2$s]" id="%1$s-%2$s" value="%4$s" />';
96
- $out .= sprintf( '<div class="translation"><label for="%1$s-%2$s">%3$s</label>' . $input_type . '</div>' . "\n",
 
97
  esc_attr( $key ),
98
  esc_attr( $item['row'] ),
99
  esc_html( $languages[ $key ] ),
100
- format_to_edit( $translation ) ); // Don't interpret special chars
 
101
  }
102
 
103
  return $out;
@@ -110,7 +114,7 @@ class PLL_Table_String extends WP_List_Table {
110
  *
111
  * @return array the list of column titles
112
  */
113
- function get_columns() {
114
  return array(
115
  'cb' => '<input type="checkbox" />', // Checkbox
116
  'string' => esc_html__( 'String', 'polylang' ),
@@ -127,7 +131,7 @@ class PLL_Table_String extends WP_List_Table {
127
  *
128
  * @return array
129
  */
130
- function get_sortable_columns() {
131
  return array(
132
  'string' => array( 'string', false ),
133
  'name' => array( 'name', false ),
@@ -165,7 +169,7 @@ class PLL_Table_String extends WP_List_Table {
165
  *
166
  * @since 0.6
167
  */
168
- function prepare_items() {
169
  $data = $this->strings;
170
 
171
  // Filter for search string
@@ -201,11 +205,13 @@ class PLL_Table_String extends WP_List_Table {
201
  $total_items = count( $data );
202
  $this->items = array_slice( $data, ( $this->get_pagenum() - 1 ) * $per_page, $per_page );
203
 
204
- $this->set_pagination_args( array(
205
- 'total_items' => $total_items,
206
- 'per_page' => $per_page,
207
- 'total_pages' => ceil( $total_items / $per_page ),
208
- ) );
 
 
209
  }
210
 
211
  /**
@@ -215,7 +221,7 @@ class PLL_Table_String extends WP_List_Table {
215
  *
216
  * @return array
217
  */
218
- function get_bulk_actions() {
219
  return array( 'delete' => __( 'Delete', 'polylang' ) );
220
  }
221
 
@@ -238,7 +244,7 @@ class PLL_Table_String extends WP_List_Table {
238
  *
239
  * @param string $which only 'top' is supported
240
  */
241
- function extra_tablenav( $which ) {
242
  if ( 'top' !== $which ) {
243
  return;
244
  }
20
  *
21
  * @param array $languages list of languages
22
  */
23
+ public function __construct( $languages ) {
24
+ parent::__construct(
25
+ array(
26
+ 'plural' => 'Strings translations', // Do not translate ( used for css class )
27
+ 'ajax' => false,
28
+ )
29
+ );
30
 
31
  $this->languages = $languages;
32
  $this->strings = PLL_Admin_Strings::get_strings();
45
  * @param string $column_name
46
  * @return string
47
  */
48
+ public function column_default( $item, $column_name ) {
49
  return $item[ $column_name ];
50
  }
51
 
57
  * @param array $item
58
  * @return string
59
  */
60
+ public function column_cb( $item ) {
61
  return sprintf(
62
  '<label class="screen-reader-text" for="cb-select-%1$s">%2$s</label><input id="cb-select-%1$s" type="checkbox" name="strings[]" value="%1$s" %3$s />',
63
  esc_attr( $item['row'] ),
75
  * @param array $item
76
  * @return string
77
  */
78
+ public function column_string( $item ) {
79
  return format_to_edit( $item['string'] ); // Don't interpret special chars for the string column
80
  }
81
 
87
  * @param array $item
88
  * @return string
89
  */
90
+ public function column_translations( $item ) {
91
  $languages = array_combine( wp_list_pluck( $this->languages, 'slug' ), wp_list_pluck( $this->languages, 'name' ) );
92
  $out = '';
93
 
95
  $input_type = $item['multiline'] ?
96
  '<textarea name="translation[%1$s][%2$s]" id="%1$s-%2$s">%4$s</textarea>' :
97
  '<input type="text" name="translation[%1$s][%2$s]" id="%1$s-%2$s" value="%4$s" />';
98
+ $out .= sprintf(
99
+ '<div class="translation"><label for="%1$s-%2$s">%3$s</label>' . $input_type . '</div>' . "\n",
100
  esc_attr( $key ),
101
  esc_attr( $item['row'] ),
102
  esc_html( $languages[ $key ] ),
103
+ format_to_edit( $translation ) // Don't interpret special chars
104
+ );
105
  }
106
 
107
  return $out;
114
  *
115
  * @return array the list of column titles
116
  */
117
+ public function get_columns() {
118
  return array(
119
  'cb' => '<input type="checkbox" />', // Checkbox
120
  'string' => esc_html__( 'String', 'polylang' ),
131
  *
132
  * @return array
133
  */
134
+ public function get_sortable_columns() {
135
  return array(
136
  'string' => array( 'string', false ),
137
  'name' => array( 'name', false ),
169
  *
170
  * @since 0.6
171
  */
172
+ public function prepare_items() {
173
  $data = $this->strings;
174
 
175
  // Filter for search string
205
  $total_items = count( $data );
206
  $this->items = array_slice( $data, ( $this->get_pagenum() - 1 ) * $per_page, $per_page );
207
 
208
+ $this->set_pagination_args(
209
+ array(
210
+ 'total_items' => $total_items,
211
+ 'per_page' => $per_page,
212
+ 'total_pages' => ceil( $total_items / $per_page ),
213
+ )
214
+ );
215
  }
216
 
217
  /**
221
  *
222
  * @return array
223
  */
224
+ public function get_bulk_actions() {
225
  return array( 'delete' => __( 'Delete', 'polylang' ) );
226
  }
227
 
244
  *
245
  * @param string $which only 'top' is supported
246
  */
247
+ public function extra_tablenav( $which ) {
248
  if ( 'top' !== $which ) {
249
  return;
250
  }
settings/view-tab-lang.php CHANGED
@@ -125,9 +125,15 @@ if ( ! defined( 'ABSPATH' ) ) {
125
  <?php
126
  include PLL_SETTINGS_INC . '/flags.php';
127
  foreach ( $flags as $code => $label ) {
 
 
 
128
  printf(
129
- '<option value="%1$s"%2$s>%3$s</option>' . "\n",
130
  esc_attr( $code ),
 
 
 
131
  isset( $edit_lang->flag_code ) && $edit_lang->flag_code == $code ? ' selected="selected"' : '',
132
  esc_html( $label )
133
  );
125
  <?php
126
  include PLL_SETTINGS_INC . '/flags.php';
127
  foreach ( $flags as $code => $label ) {
128
+ /** This filter is documented in include/language.php */
129
+ $flag = apply_filters( 'pll_flag', array( 'url' => plugins_url( "/flags/{$code}.png", POLYLANG_FILE ) ), $code );
130
+
131
  printf(
132
+ '<option value="%s" data-url="%s"%s%s%s>%s</option>' . "\n",
133
  esc_attr( $code ),
134
+ esc_url( $flag['url'] ),
135
+ empty( $flag['width'] ) ? '' : sprintf( ' data-width="%s"', (int) $flag['width'] ),
136
+ empty( $flag['height'] ) ? '' : sprintf( ' data-height="%s"', (int) $flag['height'] ),
137
  isset( $edit_lang->flag_code ) && $edit_lang->flag_code == $code ? ' selected="selected"' : '',
138
  esc_html( $label )
139
  );
uninstall.php CHANGED
@@ -17,7 +17,7 @@ class PLL_Uninstall {
17
  *
18
  * @since 0.5
19
  */
20
- function __construct() {
21
  global $wpdb;
22
 
23
  // Check if it is a multisite uninstall - if so, run the uninstall function for each blog id
@@ -39,7 +39,7 @@ class PLL_Uninstall {
39
  *
40
  * @since 0.5
41
  */
42
- function uninstall() {
43
  $options = get_option( 'polylang' );
44
 
45
  if ( empty( $options['uninstall'] ) ) {
@@ -77,13 +77,15 @@ class PLL_Uninstall {
77
  }
78
 
79
  // Delete menu language switchers
80
- $ids = get_posts( array(
81
- 'post_type' => 'nav_menu_item',
82
- 'numberposts' => -1,
83
- 'nopaging' => true,
84
- 'fields' => 'ids',
85
- 'meta_key' => '_pll_menu_item',
86
- ) );
 
 
87
 
88
  foreach ( $ids as $id ) {
89
  wp_delete_post( $id, true );
@@ -97,13 +99,15 @@ class PLL_Uninstall {
97
 
98
  // Delete the strings translations 1.2+
99
  register_post_type( 'polylang_mo', array( 'rewrite' => false, 'query_var' => false ) );
100
- $ids = get_posts( array(
101
- 'post_type' => 'polylang_mo',
102
- 'post_status' => 'any',
103
- 'numberposts' => -1,
104
- 'nopaging' => true,
105
- 'fields' => 'ids',
106
- ) );
 
 
107
  foreach ( $ids as $id ) {
108
  wp_delete_post( $id, true );
109
  }
@@ -116,13 +120,13 @@ class PLL_Uninstall {
116
 
117
  if ( ! empty( $term_ids ) ) {
118
  $term_ids = array_unique( $term_ids );
119
- $wpdb->query( "DELETE FROM $wpdb->terms WHERE term_id IN ( " . implode( ',', $term_ids ) . ' )' );
120
- $wpdb->query( "DELETE FROM $wpdb->term_taxonomy WHERE term_id IN ( " . implode( ',', $term_ids ) . ' )' );
121
  }
122
 
123
  if ( ! empty( $tt_ids ) ) {
124
  $tt_ids = array_unique( $tt_ids );
125
- $wpdb->query( "DELETE FROM $wpdb->term_relationships WHERE term_taxonomy_id IN ( " . implode( ',', $tt_ids ) . ' )' );
126
  }
127
 
128
  // Delete options
17
  *
18
  * @since 0.5
19
  */
20
+ public function __construct() {
21
  global $wpdb;
22
 
23
  // Check if it is a multisite uninstall - if so, run the uninstall function for each blog id
39
  *
40
  * @since 0.5
41
  */
42
+ public function uninstall() {
43
  $options = get_option( 'polylang' );
44
 
45
  if ( empty( $options['uninstall'] ) ) {
77
  }
78
 
79
  // Delete menu language switchers
80
+ $ids = get_posts(
81
+ array(
82
+ 'post_type' => 'nav_menu_item',
83
+ 'numberposts' => -1,
84
+ 'nopaging' => true,
85
+ 'fields' => 'ids',
86
+ 'meta_key' => '_pll_menu_item',
87
+ )
88
+ );
89
 
90
  foreach ( $ids as $id ) {
91
  wp_delete_post( $id, true );
99
 
100
  // Delete the strings translations 1.2+
101
  register_post_type( 'polylang_mo', array( 'rewrite' => false, 'query_var' => false ) );
102
+ $ids = get_posts(
103
+ array(
104
+ 'post_type' => 'polylang_mo',
105
+ 'post_status' => 'any',
106
+ 'numberposts' => -1,
107
+ 'nopaging' => true,
108
+ 'fields' => 'ids',
109
+ )
110
+ );
111
  foreach ( $ids as $id ) {
112
  wp_delete_post( $id, true );
113
  }
120
 
121
  if ( ! empty( $term_ids ) ) {
122
  $term_ids = array_unique( $term_ids );
123
+ $wpdb->query( "DELETE FROM {$wpdb->terms} WHERE term_id IN ( " . implode( ',', $term_ids ) . ' )' ); // PHPCS:ignore WordPress.DB.PreparedSQL.NotPrepared
124
+ $wpdb->query( "DELETE FROM {$wpdb->term_taxonomy} WHERE term_id IN ( " . implode( ',', $term_ids ) . ' )' ); // PHPCS:ignore WordPress.DB.PreparedSQL.NotPrepared
125
  }
126
 
127
  if ( ! empty( $tt_ids ) ) {
128
  $tt_ids = array_unique( $tt_ids );
129
+ $wpdb->query( "DELETE FROM {$wpdb->term_relationships} WHERE term_taxonomy_id IN ( " . implode( ',', $tt_ids ) . ' )' ); // PHPCS:ignore WordPress.DB.PreparedSQL.NotPrepared
130
  }
131
 
132
  // Delete options