Polylang - Version 2.0.8

Version Description

(2016-11-14) =

  • Disable admin language feature in WP 4.7+
  • Pro: fix case where a media could lose its parent post when translated on the fly by the content duplication
  • Pro: fix on the fly media created at content duplication attached to parent page instead of child page
  • Fix translations input fields not populated in languages metabox when creating a new translation in WP 4.7
  • Fix possibility to delete the translations of the default category in WP 4.7
  • Fix tag search not filtered per language in Quick edit in WP 4.7
  • Fix dropdown language switcher not working for untranslated pages
Download this release

Release Info

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

Code changes from version 2.0.7 to 2.0.8

admin/admin-base.php CHANGED
@@ -204,7 +204,10 @@ class PLL_Admin_Base extends PLL_Base {
204
  */
205
  public function init_user() {
206
  // Backend locale
207
- add_filter( 'locale', array( $this, 'get_locale' ) );
 
 
 
208
 
209
  // Language for admin language filter: may be empty
210
  // $_GET['lang'] is numeric when editing a language, not when selecting a new language in the filter
@@ -232,11 +235,14 @@ class PLL_Admin_Base extends PLL_Base {
232
  // Inform that the admin language has been set
233
  // Only if the admin language is one of the Polylang defined language
234
  if ( $curlang = $this->model->get_language( get_locale() ) ) {
235
- $GLOBALS['text_direction'] = $curlang->is_rtl ? 'rtl' : 'ltr'; // force text direction according to language setting
 
 
 
 
236
  /** This action is documented in frontend/choose-lang.php */
237
  do_action( 'pll_language_defined', $curlang->slug, $curlang );
238
- }
239
- else {
240
  /** This action is documented in include/class-polylang.php */
241
  do_action( 'pll_no_language_defined' ); // to load overriden textdomains
242
  }
@@ -262,6 +268,7 @@ class PLL_Admin_Base extends PLL_Base {
262
 
263
  /**
264
  * Get the locale based on user preference
 
265
  *
266
  * @since 0.4
267
  *
@@ -269,7 +276,7 @@ class PLL_Admin_Base extends PLL_Base {
269
  * @return string modified locale
270
  */
271
  public function get_locale( $locale ) {
272
- return ( $loc = get_user_meta( get_current_user_id(), 'user_lang', 'true' ) ) ? $loc : $locale;
273
  }
274
 
275
  /**
204
  */
205
  public function init_user() {
206
  // Backend locale
207
+ // FIXME: Backward compatibility with WP < 4.7
208
+ if ( version_compare( $GLOBALS['wp_version'], '4.7alpha', '<' ) ) {
209
+ add_filter( 'locale', array( $this, 'get_locale' ) );
210
+ }
211
 
212
  // Language for admin language filter: may be empty
213
  // $_GET['lang'] is numeric when editing a language, not when selecting a new language in the filter
235
  // Inform that the admin language has been set
236
  // Only if the admin language is one of the Polylang defined language
237
  if ( $curlang = $this->model->get_language( get_locale() ) ) {
238
+ // FIXME: Backward compatibility with WP < 4.7
239
+ if ( version_compare( $GLOBALS['wp_version'], '4.7alpha', '<' ) ) {
240
+ $GLOBALS['text_direction'] = $curlang->is_rtl ? 'rtl' : 'ltr'; // force text direction according to language setting
241
+ }
242
+
243
  /** This action is documented in frontend/choose-lang.php */
244
  do_action( 'pll_language_defined', $curlang->slug, $curlang );
245
+ } else {
 
246
  /** This action is documented in include/class-polylang.php */
247
  do_action( 'pll_no_language_defined' ); // to load overriden textdomains
248
  }
268
 
269
  /**
270
  * Get the locale based on user preference
271
+ * FIXME: Backward compatibility with WP < 4.7
272
  *
273
  * @since 0.4
274
  *
276
  * @return string modified locale
277
  */
278
  public function get_locale( $locale ) {
279
+ return ( $loc = get_user_meta( get_current_user_id(), 'locale', 'true' ) ) ? $loc : $locale;
280
  }
281
 
282
  /**
admin/admin-filters-term.php CHANGED
@@ -566,7 +566,8 @@ class PLL_Admin_Filters_Term {
566
  */
567
  protected function get_queried_language( $taxonomies, $args ) {
568
  // Does nothing except on taxonomies which are filterable
569
- if ( ! $this->model->is_translated_taxonomy( $taxonomies ) ) {
 
570
  return false;
571
  }
572
 
@@ -631,23 +632,26 @@ class PLL_Admin_Filters_Term {
631
  * @return int
632
  */
633
  public function option_default_category( $value ) {
634
- $traces = debug_backtrace();
635
- $n = version_compare( PHP_VERSION, '7', '>=' ) ? 3 : 4; // PHP 7 does not include call_user_func_array
 
 
636
 
637
- if ( isset( $traces[ $n ] ) ) {
638
- // FIXME 'column_name' for backward compatibility with WP < 4.3
639
- 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 ) ) ) {
640
- return $traces[ $n ]['args'][0]->term_id;
641
- }
642
 
643
- if ( 'wp_delete_term' == $traces[ $n ]['function'] ) {
644
- return $this->model->term->get( $value, $this->model->term->get_language( $traces[ $n ]['args'][0] ) );
645
- }
646
- }
 
647
 
648
- // Filters the default category in note below the category list table and in settings->writing dropdown
649
- elseif ( isset( $traces[ $n - 1 ]['file'] ) && ( false !== stripos( $traces[ $n - 1 ]['file'], 'edit-tags.php' ) || false !== stripos( $traces[ $n - 1 ]['file'], 'options-writing.php' ) ) ) {
650
- return $this->model->term->get( $value, $this->pref_lang );
 
651
  }
652
 
653
  return $value;
566
  */
567
  protected function get_queried_language( $taxonomies, $args ) {
568
  // Does nothing except on taxonomies which are filterable
569
+ // Since WP 4.7, make sure not to filter wp_get_object_terms()
570
+ if ( ! $this->model->is_translated_taxonomy( $taxonomies ) || ! empty( $args['object_ids'] ) ) {
571
  return false;
572
  }
573
 
632
  * @return int
633
  */
634
  public function option_default_category( $value ) {
635
+ // Filters the default category in note below the category list table and in settings->writing dropdown
636
+ if ( isset( $this->pref_lang) && $tr = $this->model->term->get( $value, $this->pref_lang ) ) {
637
+ $value = $tr;
638
+ }
639
 
640
+ // FIXME backward compatibility with WP < 4.7
641
+ if ( version_compare( $GLOBALS['wp_version'], '4.7alpha', '<' ) ) {
642
+ $traces = debug_backtrace();
643
+ $n = version_compare( PHP_VERSION, '7', '>=' ) ? 3 : 4; // PHP 7 does not include call_user_func_array
 
644
 
645
+ if ( isset( $traces[ $n ] ) ) {
646
+ // FIXME 'column_name' for backward compatibility with WP < 4.3
647
+ 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 ) ) ) {
648
+ return $traces[ $n ]['args'][0]->term_id;
649
+ }
650
 
651
+ if ( 'wp_delete_term' == $traces[ $n ]['function'] ) {
652
+ return $this->model->term->get( $value, $this->model->term->get_language( $traces[ $n ]['args'][0] ) );
653
+ }
654
+ }
655
  }
656
 
657
  return $value;
admin/admin-filters.php CHANGED
@@ -1,14 +1,14 @@
1
  <?php
2
 
3
  /**
4
- * setup miscellaneous admin filters as well as filters common to admin and frontend
5
  *
6
  * @since 1.2
7
  */
8
  class PLL_Admin_Filters extends PLL_Filters {
9
 
10
  /**
11
- * constructor: setups filters and actions
12
  *
13
  * @since 1.2
14
  *
@@ -17,20 +17,20 @@ class PLL_Admin_Filters extends PLL_Filters {
17
  public function __construct( &$polylang ) {
18
  parent::__construct( $polylang );
19
 
20
- // widgets languages filter
21
  add_action( 'in_widget_form', array( $this, 'in_widget_form' ), 10, 3 );
22
  add_filter( 'widget_update_callback', array( $this, 'widget_update_callback' ), 10, 4 );
23
 
24
- // language management for users
25
  add_action( 'personal_options_update', array( $this, 'personal_options_update' ) );
26
  add_action( 'edit_user_profile_update', array( $this, 'personal_options_update' ) );
27
  add_action( 'personal_options', array( $this, 'personal_options' ) );
28
 
29
- // ugrades languages files after a core upgrade ( timing is important )
30
- // backward compatibility WP < 4.0 *AND* Polylang < 1.6
31
  add_action( '_core_updated_successfully', array( $this, 'upgrade_languages' ), 1 ); // since WP 3.3
32
 
33
- // upgrades plugins and themes translations files
34
  add_filter( 'themes_update_check_locales', array( $this, 'update_check_locales' ) );
35
  add_filter( 'plugins_update_check_locales', array( $this, 'update_check_locales' ) );
36
 
@@ -43,7 +43,7 @@ class PLL_Admin_Filters extends PLL_Filters {
43
  }
44
 
45
  /**
46
- * modifies the widgets forms to add our language dropdwown list
47
  *
48
  * @since 0.3
49
  *
@@ -69,22 +69,21 @@ class PLL_Admin_Filters extends PLL_Filters {
69
  }
70
 
71
  /**
72
- * called when widget options are saved
73
  * saves the language associated to the widget
74
  *
75
  * @since 0.3
76
  *
77
- * @param array $instance widget options
78
- * @param array $new_instance not used
79
- * @param array $old_instance not used
80
- * @param object $widget WP_Widget object
81
- * @return array widget options
82
  */
83
  public function widget_update_callback( $instance, $new_instance, $old_instance, $widget ) {
84
  if ( ! empty( $_POST[ $key = $widget->id.'_lang_choice' ] ) && in_array( $_POST[ $key ], $this->model->get_languages_list( array( 'fields' => 'slug' ) ) ) ) {
85
  $instance['pll_lang'] = $_POST[ $key ];
86
- }
87
- else {
88
  unset( $instance['pll_lang'] );
89
  }
90
 
@@ -92,62 +91,68 @@ class PLL_Admin_Filters extends PLL_Filters {
92
  }
93
 
94
  /**
95
- * updates language user preference set in user profile
96
  *
97
  * @since 0.4
98
  *
99
  * @param int $user_id
100
  */
101
  public function personal_options_update( $user_id ) {
102
- // admin language
103
- $user_lang = in_array( $_POST['user_lang'], $this->model->get_languages_list( array( 'fields' => 'locale' ) ) ) ? $_POST['user_lang'] : 0;
104
- update_user_meta( $user_id, 'user_lang', $user_lang );
 
 
 
105
 
106
- // biography translations
107
  foreach ( $this->model->get_languages_list() as $lang ) {
108
  $meta = $lang->slug == $this->options['default_lang'] ? 'description' : 'description_' . $lang->slug;
109
  $description = empty( $_POST[ 'description_' . $lang->slug ] ) ? '' : trim( $_POST[ 'description_' . $lang->slug ] );
110
 
111
  /** This filter is documented in wp-includes/user.php */
112
- $description = apply_filters( 'pre_user_description', $description ); // applies WP default filter wp_filter_kses
113
  update_user_meta( $user_id, $meta, $description );
114
  }
115
  }
116
 
117
  /**
118
- * form for language user preference in user profile
119
  *
120
  * @since 0.4
121
  *
122
  * @param object $profileuser
123
  */
124
  public function personal_options( $profileuser ) {
125
- $dropdown = new PLL_Walker_Dropdown();
126
- printf( '
127
- <tr>
128
- <th><label for="user_lang">%s</label></th>
129
- <td>%s</td>
130
- </tr>',
131
- esc_html__( 'Admin language', 'polylang' ),
132
- $dropdown->walk(
133
- array_merge(
134
- array( (object) array( 'locale' => 0, 'name' => __( 'WordPress default', 'polylang' ) ) ),
135
- $this->model->get_languages_list()
136
- ),
137
- array(
138
- 'name' => 'user_lang',
139
- 'value' => 'locale',
140
- 'selected' => get_user_meta( $profileuser->ID, 'user_lang', true ),
 
 
 
141
  )
142
- )
143
- );
144
 
145
- // hidden informations to modify the biography form with js
146
  foreach ( $this->model->get_languages_list() as $lang ) {
147
  $meta = $lang->slug == $this->options['default_lang'] ? 'description' : 'description_' . $lang->slug;
148
 
149
  /** This filter is documented in wp-includes/user.php */
150
- $description = apply_filters( 'user_description', get_user_meta( $profileuser->ID, $meta, true ) ); // applies WP default filter wp_kses_data
151
 
152
  printf( '<input type="hidden" class="biography" name="%s___%s" value="%s" />',
153
  esc_attr( $lang->slug ),
@@ -158,7 +163,7 @@ class PLL_Admin_Filters extends PLL_Filters {
158
  }
159
 
160
  /**
161
- * ugprades languages files after a core upgrade
162
  * only for backward compatibility WP < 4.0 *AND* Polylang < 1.6
163
  *
164
  * @since 0.6
@@ -176,7 +181,7 @@ class PLL_Admin_Filters extends PLL_Filters {
176
  }
177
 
178
  /**
179
- * allows to update translations files for plugins and themes
180
  *
181
  * @since 1.6
182
  *
1
  <?php
2
 
3
  /**
4
+ * Setup miscellaneous admin filters as well as filters common to admin and frontend
5
  *
6
  * @since 1.2
7
  */
8
  class PLL_Admin_Filters extends PLL_Filters {
9
 
10
  /**
11
+ * Constructor: setups filters and actions
12
  *
13
  * @since 1.2
14
  *
17
  public function __construct( &$polylang ) {
18
  parent::__construct( $polylang );
19
 
20
+ // Widgets languages filter
21
  add_action( 'in_widget_form', array( $this, 'in_widget_form' ), 10, 3 );
22
  add_filter( 'widget_update_callback', array( $this, 'widget_update_callback' ), 10, 4 );
23
 
24
+ // Language management for users
25
  add_action( 'personal_options_update', array( $this, 'personal_options_update' ) );
26
  add_action( 'edit_user_profile_update', array( $this, 'personal_options_update' ) );
27
  add_action( 'personal_options', array( $this, 'personal_options' ) );
28
 
29
+ // Ugrades languages files after a core upgrade ( timing is important )
30
+ // Backward compatibility WP < 4.0 *AND* Polylang < 1.6
31
  add_action( '_core_updated_successfully', array( $this, 'upgrade_languages' ), 1 ); // since WP 3.3
32
 
33
+ // Upgrades plugins and themes translations files
34
  add_filter( 'themes_update_check_locales', array( $this, 'update_check_locales' ) );
35
  add_filter( 'plugins_update_check_locales', array( $this, 'update_check_locales' ) );
36
 
43
  }
44
 
45
  /**
46
+ * Modifies the widgets forms to add our language dropdwown list
47
  *
48
  * @since 0.3
49
  *
69
  }
70
 
71
  /**
72
+ * Called when widget options are saved
73
  * saves the language associated to the widget
74
  *
75
  * @since 0.3
76
  *
77
+ * @param array $instance Widget options
78
+ * @param array $new_instance Not used
79
+ * @param array $old_instance Not used
80
+ * @param object $widget WP_Widget object
81
+ * @return array Widget options
82
  */
83
  public function widget_update_callback( $instance, $new_instance, $old_instance, $widget ) {
84
  if ( ! empty( $_POST[ $key = $widget->id.'_lang_choice' ] ) && in_array( $_POST[ $key ], $this->model->get_languages_list( array( 'fields' => 'slug' ) ) ) ) {
85
  $instance['pll_lang'] = $_POST[ $key ];
86
+ } else {
 
87
  unset( $instance['pll_lang'] );
88
  }
89
 
91
  }
92
 
93
  /**
94
+ * Updates language user preference set in user profile
95
  *
96
  * @since 0.4
97
  *
98
  * @param int $user_id
99
  */
100
  public function personal_options_update( $user_id ) {
101
+ // Admin language
102
+ // FIXME Backward compatibility with WP < 4.7
103
+ if ( version_compare( $GLOBALS['wp_version'], '4.7alpha', '<' ) ) {
104
+ $user_lang = in_array( $_POST['user_lang'], $this->model->get_languages_list( array( 'fields' => 'locale' ) ) ) ? $_POST['user_lang'] : 0;
105
+ update_user_meta( $user_id, 'locale', $user_lang );
106
+ }
107
 
108
+ // Biography translations
109
  foreach ( $this->model->get_languages_list() as $lang ) {
110
  $meta = $lang->slug == $this->options['default_lang'] ? 'description' : 'description_' . $lang->slug;
111
  $description = empty( $_POST[ 'description_' . $lang->slug ] ) ? '' : trim( $_POST[ 'description_' . $lang->slug ] );
112
 
113
  /** This filter is documented in wp-includes/user.php */
114
+ $description = apply_filters( 'pre_user_description', $description ); // Applies WP default filter wp_filter_kses
115
  update_user_meta( $user_id, $meta, $description );
116
  }
117
  }
118
 
119
  /**
120
+ * Form for language user preference in user profile
121
  *
122
  * @since 0.4
123
  *
124
  * @param object $profileuser
125
  */
126
  public function personal_options( $profileuser ) {
127
+ // FIXME: Backward compatibility with WP < 4.7
128
+ if ( version_compare( $GLOBALS['wp_version'], '4.7alpha', '<' ) ) {
129
+ $dropdown = new PLL_Walker_Dropdown();
130
+ printf( '
131
+ <tr>
132
+ <th><label for="user_lang">%s</label></th>
133
+ <td>%s</td>
134
+ </tr>',
135
+ esc_html__( 'Admin language', 'polylang' ),
136
+ $dropdown->walk(
137
+ array_merge(
138
+ array( (object) array( 'locale' => 0, 'name' => __( 'WordPress default', 'polylang' ) ) ),
139
+ $this->model->get_languages_list()
140
+ ),
141
+ array(
142
+ 'name' => 'user_lang',
143
+ 'value' => 'locale',
144
+ 'selected' => get_user_meta( $profileuser->ID, 'locale', true ),
145
+ )
146
  )
147
+ );
148
+ }
149
 
150
+ // Hidden informations to modify the biography form with js
151
  foreach ( $this->model->get_languages_list() as $lang ) {
152
  $meta = $lang->slug == $this->options['default_lang'] ? 'description' : 'description_' . $lang->slug;
153
 
154
  /** This filter is documented in wp-includes/user.php */
155
+ $description = apply_filters( 'user_description', get_user_meta( $profileuser->ID, $meta, true ) ); // Applies WP default filter wp_kses_data
156
 
157
  printf( '<input type="hidden" class="biography" name="%s___%s" value="%s" />',
158
  esc_attr( $lang->slug ),
163
  }
164
 
165
  /**
166
+ * Ugprades languages files after a core upgrade
167
  * only for backward compatibility WP < 4.0 *AND* Polylang < 1.6
168
  *
169
  * @since 0.6
181
  }
182
 
183
  /**
184
+ * Allows to update translations files for plugins and themes
185
  *
186
  * @since 1.6
187
  *
admin/admin-model.php CHANGED
@@ -89,6 +89,10 @@ class PLL_Admin_Model extends PLL_Model {
89
  public function delete_language( $lang_id ) {
90
  $lang = $this->get_language( (int) $lang_id );
91
 
 
 
 
 
92
  // Oops ! we are deleting the default language...
93
  // Need to do this before loosing the information for default category translations
94
  if ( $this->options['default_lang'] == $lang->slug ) {
@@ -131,7 +135,6 @@ class PLL_Admin_Model extends PLL_Model {
131
 
132
  // Delete users options
133
  foreach ( get_users( array( 'fields' => 'ID' ) ) as $user_id ) {
134
- delete_user_meta( $user_id, 'user_lang', $lang->locale );
135
  delete_user_meta( $user_id, 'pll_filter_content', $lang->slug );
136
  delete_user_meta( $user_id, 'description_'.$lang->slug );
137
  }
89
  public function delete_language( $lang_id ) {
90
  $lang = $this->get_language( (int) $lang_id );
91
 
92
+ if ( empty( $lang ) ) {
93
+ return;
94
+ }
95
+
96
  // Oops ! we are deleting the default language...
97
  // Need to do this before loosing the information for default category translations
98
  if ( $this->options['default_lang'] == $lang->slug ) {
135
 
136
  // Delete users options
137
  foreach ( get_users( array( 'fields' => 'ID' ) ) as $user_id ) {
 
138
  delete_user_meta( $user_id, 'pll_filter_content', $lang->slug );
139
  delete_user_meta( $user_id, 'description_'.$lang->slug );
140
  }
frontend/frontend-filters.php CHANGED
@@ -126,7 +126,8 @@ class PLL_Frontend_Filters extends PLL_Filters{
126
  */
127
  public function terms_clauses( $clauses, $taxonomies, $args ) {
128
  // Does nothing except on taxonomies which are filterable
129
- if ( ! $this->model->is_translated_taxonomy( $taxonomies ) ) {
 
130
  return $clauses;
131
  }
132
 
126
  */
127
  public function terms_clauses( $clauses, $taxonomies, $args ) {
128
  // Does nothing except on taxonomies which are filterable
129
+ // Since WP 4.7, make sure not to filter wp_get_object_terms()
130
+ if ( ! $this->model->is_translated_taxonomy( $taxonomies ) || ! empty( $args['object_ids'] ) ) {
131
  return $clauses;
132
  }
133
 
include/filters.php CHANGED
@@ -30,6 +30,9 @@ class PLL_Filters {
30
 
31
  // Converts the locale to a valid W3C locale
32
  add_filter( 'language_attributes', array( $this, 'language_attributes' ) );
 
 
 
33
  }
34
 
35
  /**
@@ -177,4 +180,24 @@ class PLL_Filters {
177
  }
178
  return $output;
179
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
180
  }
30
 
31
  // Converts the locale to a valid W3C locale
32
  add_filter( 'language_attributes', array( $this, 'language_attributes' ) );
33
+
34
+ // Prevents deleting all the translations of the default category
35
+ add_filter( 'map_meta_cap', array( $this, 'fix_delete_default_category' ), 10, 4 );
36
  }
37
 
38
  /**
180
  }
181
  return $output;
182
  }
183
+
184
+
185
+ /**
186
+ * Prevents deleting all the translations of the default category
187
+ *
188
+ * @since 2.1
189
+ *
190
+ * @param array $caps The user's actual capabilities.
191
+ * @param string $cap Capability name.
192
+ * @param int $user_id The user ID.
193
+ * @param array $args Adds the context to the cap. The category id.
194
+ * @return array
195
+ */
196
+ public function fix_delete_default_category( $caps, $cap, $user_id, $args ) {
197
+ if ( 'delete_term' === $cap && array_intersect( $args, $this->model->term->get_translations( get_option( 'default_category' ) ) ) ) {
198
+ $caps[] = 'do_not_allow';
199
+ }
200
+
201
+ return $caps;
202
+ }
203
  }
include/switcher.php CHANGED
@@ -188,7 +188,8 @@ class PLL_Switcher {
188
  // Javascript to switch the language when using a dropdown list
189
  if ( $args['dropdown'] ) {
190
  foreach ( $links->model->get_languages_list() as $language ) {
191
- $urls[ $language->slug ] = $args['force_home'] || ( $url = $links->get_translation_url( $language ) ) === null ? $links->get_home_url( $language ) : $url;
 
192
  }
193
 
194
  // Accept only few valid characters for the urls_x variable name ( as the widget id includes '-' which is invalid )
188
  // Javascript to switch the language when using a dropdown list
189
  if ( $args['dropdown'] ) {
190
  foreach ( $links->model->get_languages_list() as $language ) {
191
+ $url = $links->get_translation_url( $language );
192
+ $urls[ $language->slug ] = $args['force_home'] || empty( $url ) ? $links->get_home_url( $language ) : $url;
193
  }
194
 
195
  // Accept only few valid characters for the urls_x variable name ( as the widget id includes '-' which is invalid )
install/upgrade.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
 
3
  /**
4
- * manages Polylang upgrades
5
  *
6
  * @since 1.2
7
  */
@@ -9,7 +9,7 @@ class PLL_Upgrade {
9
  public $options;
10
 
11
  /**
12
- * constructor
13
  *
14
  * @since 1.2
15
  */
@@ -18,7 +18,7 @@ class PLL_Upgrade {
18
  }
19
 
20
  /**
21
- * check if upgrade is possible otherwise die to avoid activation
22
  *
23
  * @since 1.2
24
  */
@@ -31,7 +31,7 @@ class PLL_Upgrade {
31
  }
32
 
33
  /**
34
- * upgrades if possible otherwise returns false to stop Polylang loading
35
  *
36
  * @since 1.2
37
  *
@@ -49,8 +49,8 @@ class PLL_Upgrade {
49
 
50
 
51
  /**
52
- * check if we the previous version is not too old
53
- * upgrades if OK
54
  * /!\ never start any upgrade before admin_init as it is likely to conflict with some other plugins
55
  *
56
  * @since 1.2
@@ -58,12 +58,12 @@ class PLL_Upgrade {
58
  * @return bool true if upgrade is possible, false otherwise
59
  */
60
  public function can_upgrade() {
61
- // don't manage upgrade from version < 0.8
62
  return version_compare( $this->options['version'], '0.8', '>=' );
63
  }
64
 
65
  /**
66
- * displays a notice when ugrading from a too old version
67
  *
68
  * @since 1.0
69
  */
@@ -82,12 +82,12 @@ class PLL_Upgrade {
82
  }
83
 
84
  /**
85
- * upgrades the plugin depending on the previous version
86
  *
87
  * @since 1.2
88
  */
89
  public function _upgrade() {
90
- foreach ( array( '0.9', '1.0', '1.1', '1.2', '1.2.1', '1.2.3', '1.3', '1.4', '1.4.1', '1.4.4', '1.5', '1.6', '1.7.4', '1.8' ) as $version ) {
91
  if ( version_compare( $this->options['version'], $version, '<' ) ) {
92
  call_user_func( array( $this, 'upgrade_' . str_replace( '.', '_', $version ) ) );
93
  }
@@ -98,47 +98,47 @@ class PLL_Upgrade {
98
  $this->delete_pre_1_2_data();
99
  }
100
 
101
- $this->options['previous_version'] = $this->options['version']; // remember the previous version of Polylang since v1.7.7
102
  $this->options['version'] = POLYLANG_VERSION;
103
  update_option( 'polylang', $this->options );
104
  }
105
 
106
  /**
107
- * upgrades if the previous version is < 0.9
108
  *
109
  * @since 1.2
110
  */
111
  protected function upgrade_0_9() {
112
- $this->options['sync'] = defined( 'PLL_SYNC' ) && ! PLL_SYNC ? 0 : 1; // the option replaces PLL_SYNC in 0.9
113
  }
114
 
115
  /**
116
- * upgrades if the previous version is < 1.0
117
  *
118
  * @since 1.2
119
  */
120
  protected function upgrade_1_0() {
121
- // the option replaces PLL_MEDIA_SUPPORT in 1.0
122
  $this->options['media_support'] = defined( 'PLL_MEDIA_SUPPORT' ) && ! PLL_MEDIA_SUPPORT ? 0 : 1;
123
 
124
- // split the synchronization options in 1.0
125
  $this->options['sync'] = empty( $this->options['sync'] ) ? array() : array_keys( PLL_Settings_Sync::list_metas_to_sync() );
126
 
127
- // set default values for post types and taxonomies to translate
128
  $this->options['post_types'] = array_values( get_post_types( array( '_builtin' => false, 'show_ui' => true ) ) );
129
  $this->options['taxonomies'] = array_values( get_taxonomies( array( '_builtin' => false, 'show_ui' => true ) ) );
130
  update_option( 'polylang', $this->options );
131
 
132
- flush_rewrite_rules(); // rewrite rules have been modified in 1.0
133
  }
134
 
135
  /**
136
- * upgrades if the previous version is < 1.1
137
  *
138
  * @since 1.2
139
  */
140
  protected function upgrade_1_1() {
141
- // update strings register with icl_register_string
142
  $strings = get_option( 'polylang_wpml_strings' );
143
  if ( $strings ) {
144
  foreach ( $strings as $key => $string ) {
@@ -147,7 +147,7 @@ class PLL_Upgrade {
147
  update_option( 'polylang_wpml_strings', $strings );
148
  }
149
 
150
- // move polylang_widgets options
151
  if ( $widgets = get_option( 'polylang_widgets' ) ) {
152
  $this->options['widgets'] = $widgets;
153
  delete_option( 'polylang_widgets' );
@@ -155,42 +155,42 @@ class PLL_Upgrade {
155
  }
156
 
157
  /**
158
- * upgrades if the previous version is < 1.2
159
  *
160
  * @since 1.2
161
  */
162
  protected function upgrade_1_2() {
163
- $this->options['domains'] = array(); // option added in 1.2
164
 
165
- // need to register the taxonomies
166
  foreach ( array( 'language', 'term_language', 'post_translations', 'term_translations' ) as $taxonomy ) {
167
  register_taxonomy( $taxonomy, null , array( 'label' => false, 'public' => false, 'query_var' => false, 'rewrite' => false ) );
168
  }
169
 
170
- // abort if the db upgrade has already been done previously
171
  if ( get_terms( 'term_language', array( 'hide_empty' => 0 ) ) ) {
172
  return;
173
  }
174
 
175
- set_time_limit( 0 ); // in case we upgrade a huge site
176
 
177
- // upgrade old model based on metas to new model based on taxonomies
178
  global $wpdb;
179
- $wpdb->termmeta = $wpdb->prefix . 'termmeta'; // registers the termmeta table in wpdb
180
- $languages = get_terms( 'language', array( 'hide_empty' => 0 ) ); // don't use get_languages_list which can't work with the old model
181
 
182
  foreach ( $languages as $lang ) {
183
- // first update language with new storage for locale and text direction
184
  $text_direction = get_metadata( 'term', $lang->term_id, '_rtl', true );
185
  $desc = serialize( array( 'locale' => $lang->description, 'rtl' => $text_direction ) );
186
  wp_update_term( (int) $lang->term_id, 'language', array( 'description' => $desc ) );
187
 
188
- // add language to new 'term_language' taxonomy
189
  $term_lang = wp_insert_term( $lang->name, 'term_language', array( 'slug' => 'pll_' . $lang->slug ) );
190
- $lang_tt_ids[ $lang->term_id ] = $term_lang['term_taxonomy_id']; // keep the term taxonomy id for future
191
  }
192
 
193
- // get all terms with a language defined
194
  $terms = $wpdb->get_results( "SELECT term_id, meta_value FROM $wpdb->termmeta WHERE meta_key = '_language'" );
195
  foreach ( $terms as $key => $term ) {
196
  $terms[ $key ] = $wpdb->prepare( '( %d, %d )', $term->term_id, $lang_tt_ids[ $term->meta_value ] );
@@ -198,17 +198,17 @@ class PLL_Upgrade {
198
 
199
  $terms = array_unique( $terms );
200
 
201
- // assign language to each term
202
  if ( ! empty( $terms ) ) {
203
  $wpdb->query( "INSERT INTO $wpdb->term_relationships ( object_id, term_taxonomy_id ) VALUES " . implode( ',', $terms ) );
204
  }
205
 
206
- // translations
207
  foreach ( array( 'post', 'term' ) as $type ) {
208
  $table = $type . 'meta';
209
  $terms = $slugs = $tts = $trs = array();
210
 
211
- // get all translated objects
212
  $objects = $wpdb->get_col( "SELECT DISTINCT meta_value FROM {$wpdb->$table} WHERE meta_key = '_translations'" );
213
 
214
  if ( empty( $objects ) ) {
@@ -216,7 +216,7 @@ class PLL_Upgrade {
216
  }
217
 
218
  foreach ( $objects as $obj ) {
219
- $term = uniqid( 'pll_' ); // the term name
220
  $terms[] = $wpdb->prepare( '( "%1$s", "%1$s" )', $term );
221
  $slugs[] = $wpdb->prepare( '"%s"', $term );
222
  $translations = maybe_unserialize( maybe_unserialize( $obj ) ); // 2 unserialize due to an old storage bug
@@ -225,30 +225,30 @@ class PLL_Upgrade {
225
 
226
  $terms = array_unique( $terms );
227
 
228
- // insert terms
229
  if ( ! empty( $terms ) ) {
230
  $wpdb->query( "INSERT INTO $wpdb->terms ( slug, name ) VALUES " . implode( ',', $terms ) );
231
  }
232
 
233
- // get all terms with their term_id
234
  $terms = $wpdb->get_results( "SELECT term_id, slug FROM $wpdb->terms WHERE slug IN ( " . implode( ',', $slugs ) . " )" );
235
 
236
- // prepare terms taxonomy relationship
237
  foreach ( $terms as $term ) {
238
  $tts[] = $wpdb->prepare( '( %d, "%s", "%s" )', $term->term_id, $type . '_translations', $description[ $term->slug ] );
239
  }
240
 
241
  $tts = array_unique( $tts );
242
 
243
- // insert term_taxonomy
244
  if ( ! empty( $tts ) ) {
245
  $wpdb->query( "INSERT INTO $wpdb->term_taxonomy ( term_id, taxonomy, description ) VALUES " . implode( ',', $tts ) );
246
  }
247
 
248
- // get all terms with term_taxonomy_id
249
  $terms = get_terms( $type . '_translations', array( 'hide_empty' => false ) );
250
 
251
- // prepare objects relationships
252
  foreach ( $terms as $term ) {
253
  $translations = unserialize( $term->description );
254
  foreach ( $translations as $object_id ) {
@@ -260,23 +260,23 @@ class PLL_Upgrade {
260
 
261
  $trs = array_unique( $trs );
262
 
263
- // insert term_relationships
264
  if ( ! empty( $trs ) ) {
265
  $wpdb->query( "INSERT INTO $wpdb->term_relationships ( object_id, term_taxonomy_id ) VALUES " . implode( ',', $trs ) );
266
  }
267
  }
268
 
269
- // upgrade of string translations is now in upgrade_1_2_1
270
- // upgrade of nav menus is now in upgrade_1_2_3
271
  }
272
 
273
  /**
274
- * upgrades if the previous version is < 1.2.1
275
  *
276
  * @since 1.2.1
277
  */
278
  protected function upgrade_1_2_1() {
279
- // strings translations
280
  foreach ( get_terms( 'language', array( 'hide_empty' => 0 ) ) as $lang ) {
281
  if ( $strings = get_option( 'polylang_mo' . $lang->term_id ) ) {
282
  $mo = new PLL_MO();
@@ -289,14 +289,14 @@ class PLL_Upgrade {
289
  }
290
 
291
  /**
292
- * upgrades if the previous version is < 1.2.3
293
- * uprades multilingual menus depending on the old version due to multiple changes in menus management
294
  *
295
  * @since 1.2.3
296
  */
297
  public function upgrade_1_2_3() {
298
- // old version < 1.1
299
- // multilingal locations and switcher item were stored in a dedicated option
300
  if ( version_compare( $this->options['version'], '1.1', '<' ) ) {
301
  if ( $menu_lang = get_option( 'polylang_nav_menus' ) ) {
302
  foreach ( $menu_lang as $location => $arr ) {
@@ -309,12 +309,12 @@ class PLL_Upgrade {
309
  $has_switcher = array_shift( $switch_options );
310
 
311
  foreach ( get_terms( 'language', array( 'hide_empty' => 0 ) ) as $lang ) {
312
- // move nav menus locations
313
  if ( ! empty( $translations[ $lang->slug ] ) ) {
314
  $locations[ $location ][ $lang->slug ] = $translations[ $lang->slug ];
315
  }
316
 
317
- // create the menu items for the language switcher
318
  if ( ! empty( $has_switcher ) ) {
319
  $menu_item_db_id = wp_update_nav_menu_item( $translations[ $lang->slug ], 0, array(
320
  'menu-item-title' => __( 'Language switcher', 'polylang' ),
@@ -339,8 +339,8 @@ class PLL_Upgrade {
339
  $menus = get_theme_mod( 'nav_menu_locations' );
340
 
341
  if ( is_array( $menus ) ) {
342
- // if old version < 1.2
343
- // clean the WP option as it was a bad idea to pollute it
344
  if ( version_compare( $this->options['version'], '1.2', '<' ) ) {
345
  foreach ( $menus as $loc => $menu ) {
346
  if ( $pos = strpos( $loc, '#' ) ) {
@@ -351,7 +351,7 @@ class PLL_Upgrade {
351
  set_theme_mod( 'nav_menu_locations', $menus );
352
  }
353
 
354
- // get the multilingual locations
355
  foreach ( $menus as $loc => $menu ) {
356
  foreach ( get_terms( 'language', array( 'hide_empty' => 0 ) ) as $lang ) {
357
  $arr[ $loc ][ $lang->slug ] = pll_get_term( $menu, $lang );
@@ -366,8 +366,8 @@ class PLL_Upgrade {
366
  }
367
 
368
  /**
369
- * upgrades if the previous version is < 1.3
370
- * moves the user biographies in default language to the 'description' user meta
371
  *
372
  * @since 1.3
373
  */
@@ -385,9 +385,9 @@ class PLL_Upgrade {
385
  }
386
 
387
  /**
388
- * upgrades if the previous version is < 1.4
389
- * sets a transient to delete old model data
390
- * deletes language cache (due to bug correction in home urls in 1.3.1 and added mo_id in 1.4)
391
  *
392
  * @since 1.4
393
  */
@@ -397,17 +397,17 @@ class PLL_Upgrade {
397
  }
398
 
399
  /**
400
- * old data were not deleted in 1.2, just in case...
401
- * delete them at first upgrade at least 60 days after upgrade to 1.4
402
  *
403
  * @since 1.4
404
  */
405
  protected function delete_pre_1_2_data() {
406
- // suppress data of the old model < 1.2
407
  global $wpdb;
408
  $wpdb->termmeta = $wpdb->prefix . 'termmeta'; // registers the termmeta table in wpdb in case WP < 4.4
409
 
410
- // do nothing if the termmeta table does not exists
411
  if ( count( $wpdb->get_results( "SHOW TABLES LIKE '$wpdb->termmeta'" ) ) ) {
412
  $wpdb->query( "DELETE FROM $wpdb->postmeta WHERE meta_key = '_translations'" );
413
  $wpdb->query( "DELETE FROM $wpdb->termmeta WHERE meta_key = '_language'" );
@@ -415,7 +415,7 @@ class PLL_Upgrade {
415
  $wpdb->query( "DELETE FROM $wpdb->termmeta WHERE meta_key = '_translations'" );
416
  }
417
 
418
- // delete the strings translations
419
  $languages = get_terms( 'language', array( 'hide_empty' => false ) );
420
  foreach ( $languages as $lang ) {
421
  delete_option( 'polylang_mo' . $lang->term_id );
@@ -425,8 +425,8 @@ class PLL_Upgrade {
425
  }
426
 
427
  /**
428
- * upgrades if the previous version is < 1.4.1
429
- * disables the browser detection when using multiple domains
430
  *
431
  * @since 1.4.1
432
  */
@@ -437,8 +437,8 @@ class PLL_Upgrade {
437
  }
438
 
439
  /**
440
- * upgrades if the previous version is < 1.4.4
441
- * uprades widgets options for language filter
442
  *
443
  * @since 1.4.4
444
  */
@@ -457,8 +457,8 @@ class PLL_Upgrade {
457
  }
458
 
459
  /**
460
- * upgrades if the previous version is < 1.5
461
- * deletes language cache (due to host property added and bug on search url)
462
  *
463
  * @since 1.5
464
  */
@@ -467,8 +467,8 @@ class PLL_Upgrade {
467
  }
468
 
469
  /**
470
- * upgrades if the previous version is < 1.6
471
- * upgrades core language files to get the .po file (only for WP 4.0+)
472
  *
473
  * @since 1.6
474
  */
@@ -479,17 +479,17 @@ class PLL_Upgrade {
479
  }
480
 
481
  /**
482
- * downloads language packs
483
- * intended to be used only one time (at upgrade to Polylang 1.6 or first upgrade of WP 4.0 or later)
484
- * adapted from wp_download_language_pack
485
- * rewritten because wp_download_language_pack checks the existence of .mo and I need to download .po
486
  *
487
  * @since 1.6
488
  */
489
  static function download_language_packs() {
490
  $languages = pll_languages_list( array( 'fields' => 'locale' ) );
491
 
492
- // prevents upgrade if the .po file is already here. Let WP manage the upgrades :)
493
  foreach ( $languages as $key => $locale ) {
494
  if ( file_exists( WP_LANG_DIR . "/$locale.po" ) ) {
495
  unset( $languages[ $key ] );
@@ -521,22 +521,22 @@ class PLL_Upgrade {
521
  }
522
 
523
  /**
524
- * upgrades if the previous version is < 1.7.4
525
  *
526
  * @since 1.7.4
527
  */
528
  protected function upgrade_1_7_4() {
529
- delete_transient( 'pll_languages_list' ); // deletes language cache (due to flag properties added in 1.7, page on front removed in 1.7.2, home url fixes in 1.7.4)
530
- flush_rewrite_rules(); // flush rewrite rules due to custom taxonomy rewrite rule bug fix
531
  }
532
 
533
  /**
534
- * upgrades if the previous version is < 1.8
535
  *
536
  * @since 1.8
537
  */
538
  protected function upgrade_1_8() {
539
- // adds the flag code in languages stored in DB
540
  include( PLL_SETTINGS_INC . '/languages.php' );
541
 
542
  $terms = get_terms( 'language', array( 'hide_empty' => 0 ) );
@@ -552,4 +552,15 @@ class PLL_Upgrade {
552
 
553
  delete_transient( 'pll_languages_list' );
554
  }
 
 
 
 
 
 
 
 
 
 
 
555
  }
1
  <?php
2
 
3
  /**
4
+ * Manages Polylang upgrades
5
  *
6
  * @since 1.2
7
  */
9
  public $options;
10
 
11
  /**
12
+ * Constructor
13
  *
14
  * @since 1.2
15
  */
18
  }
19
 
20
  /**
21
+ * Check if upgrade is possible otherwise die to avoid activation
22
  *
23
  * @since 1.2
24
  */
31
  }
32
 
33
  /**
34
+ * Upgrades if possible otherwise returns false to stop Polylang loading
35
  *
36
  * @since 1.2
37
  *
49
 
50
 
51
  /**
52
+ * Check if we the previous version is not too old
53
+ * Upgrades if OK
54
  * /!\ never start any upgrade before admin_init as it is likely to conflict with some other plugins
55
  *
56
  * @since 1.2
58
  * @return bool true if upgrade is possible, false otherwise
59
  */
60
  public function can_upgrade() {
61
+ // Don't manage upgrade from version < 0.8
62
  return version_compare( $this->options['version'], '0.8', '>=' );
63
  }
64
 
65
  /**
66
+ * Displays a notice when ugrading from a too old version
67
  *
68
  * @since 1.0
69
  */
82
  }
83
 
84
  /**
85
+ * Upgrades the plugin depending on the previous version
86
  *
87
  * @since 1.2
88
  */
89
  public function _upgrade() {
90
+ foreach ( array( '0.9', '1.0', '1.1', '1.2', '1.2.1', '1.2.3', '1.3', '1.4', '1.4.1', '1.4.4', '1.5', '1.6', '1.7.4', '1.8', '2.0.8' ) as $version ) {
91
  if ( version_compare( $this->options['version'], $version, '<' ) ) {
92
  call_user_func( array( $this, 'upgrade_' . str_replace( '.', '_', $version ) ) );
93
  }
98
  $this->delete_pre_1_2_data();
99
  }
100
 
101
+ $this->options['previous_version'] = $this->options['version']; // Remember the previous version of Polylang since v1.7.7
102
  $this->options['version'] = POLYLANG_VERSION;
103
  update_option( 'polylang', $this->options );
104
  }
105
 
106
  /**
107
+ * Upgrades if the previous version is < 0.9
108
  *
109
  * @since 1.2
110
  */
111
  protected function upgrade_0_9() {
112
+ $this->options['sync'] = defined( 'PLL_SYNC' ) && ! PLL_SYNC ? 0 : 1; // The option replaces PLL_SYNC in 0.9
113
  }
114
 
115
  /**
116
+ * Upgrades if the previous version is < 1.0
117
  *
118
  * @since 1.2
119
  */
120
  protected function upgrade_1_0() {
121
+ // The option replaces PLL_MEDIA_SUPPORT in 1.0
122
  $this->options['media_support'] = defined( 'PLL_MEDIA_SUPPORT' ) && ! PLL_MEDIA_SUPPORT ? 0 : 1;
123
 
124
+ // Split the synchronization options in 1.0
125
  $this->options['sync'] = empty( $this->options['sync'] ) ? array() : array_keys( PLL_Settings_Sync::list_metas_to_sync() );
126
 
127
+ // Set default values for post types and taxonomies to translate
128
  $this->options['post_types'] = array_values( get_post_types( array( '_builtin' => false, 'show_ui' => true ) ) );
129
  $this->options['taxonomies'] = array_values( get_taxonomies( array( '_builtin' => false, 'show_ui' => true ) ) );
130
  update_option( 'polylang', $this->options );
131
 
132
+ flush_rewrite_rules(); // Rewrite rules have been modified in 1.0
133
  }
134
 
135
  /**
136
+ * Upgrades if the previous version is < 1.1
137
  *
138
  * @since 1.2
139
  */
140
  protected function upgrade_1_1() {
141
+ // Update strings register with icl_register_string
142
  $strings = get_option( 'polylang_wpml_strings' );
143
  if ( $strings ) {
144
  foreach ( $strings as $key => $string ) {
147
  update_option( 'polylang_wpml_strings', $strings );
148
  }
149
 
150
+ // Move polylang_widgets options
151
  if ( $widgets = get_option( 'polylang_widgets' ) ) {
152
  $this->options['widgets'] = $widgets;
153
  delete_option( 'polylang_widgets' );
155
  }
156
 
157
  /**
158
+ * Upgrades if the previous version is < 1.2
159
  *
160
  * @since 1.2
161
  */
162
  protected function upgrade_1_2() {
163
+ $this->options['domains'] = array(); // Option added in 1.2
164
 
165
+ // Need to register the taxonomies
166
  foreach ( array( 'language', 'term_language', 'post_translations', 'term_translations' ) as $taxonomy ) {
167
  register_taxonomy( $taxonomy, null , array( 'label' => false, 'public' => false, 'query_var' => false, 'rewrite' => false ) );
168
  }
169
 
170
+ // Abort if the db upgrade has already been done previously
171
  if ( get_terms( 'term_language', array( 'hide_empty' => 0 ) ) ) {
172
  return;
173
  }
174
 
175
+ set_time_limit( 0 ); // In case we upgrade a huge site
176
 
177
+ // Upgrade old model based on metas to new model based on taxonomies
178
  global $wpdb;
179
+ $wpdb->termmeta = $wpdb->prefix . 'termmeta'; // Registers the termmeta table in wpdb
180
+ $languages = get_terms( 'language', array( 'hide_empty' => 0 ) ); // Don't use get_languages_list which can't work with the old model
181
 
182
  foreach ( $languages as $lang ) {
183
+ // First update language with new storage for locale and text direction
184
  $text_direction = get_metadata( 'term', $lang->term_id, '_rtl', true );
185
  $desc = serialize( array( 'locale' => $lang->description, 'rtl' => $text_direction ) );
186
  wp_update_term( (int) $lang->term_id, 'language', array( 'description' => $desc ) );
187
 
188
+ // Add language to new 'term_language' taxonomy
189
  $term_lang = wp_insert_term( $lang->name, 'term_language', array( 'slug' => 'pll_' . $lang->slug ) );
190
+ $lang_tt_ids[ $lang->term_id ] = $term_lang['term_taxonomy_id']; // Keep the term taxonomy id for future
191
  }
192
 
193
+ // Get all terms with a language defined
194
  $terms = $wpdb->get_results( "SELECT term_id, meta_value FROM $wpdb->termmeta WHERE meta_key = '_language'" );
195
  foreach ( $terms as $key => $term ) {
196
  $terms[ $key ] = $wpdb->prepare( '( %d, %d )', $term->term_id, $lang_tt_ids[ $term->meta_value ] );
198
 
199
  $terms = array_unique( $terms );
200
 
201
+ // Assign language to each term
202
  if ( ! empty( $terms ) ) {
203
  $wpdb->query( "INSERT INTO $wpdb->term_relationships ( object_id, term_taxonomy_id ) VALUES " . implode( ',', $terms ) );
204
  }
205
 
206
+ // Translations
207
  foreach ( array( 'post', 'term' ) as $type ) {
208
  $table = $type . 'meta';
209
  $terms = $slugs = $tts = $trs = array();
210
 
211
+ // Get all translated objects
212
  $objects = $wpdb->get_col( "SELECT DISTINCT meta_value FROM {$wpdb->$table} WHERE meta_key = '_translations'" );
213
 
214
  if ( empty( $objects ) ) {
216
  }
217
 
218
  foreach ( $objects as $obj ) {
219
+ $term = uniqid( 'pll_' ); // The term name
220
  $terms[] = $wpdb->prepare( '( "%1$s", "%1$s" )', $term );
221
  $slugs[] = $wpdb->prepare( '"%s"', $term );
222
  $translations = maybe_unserialize( maybe_unserialize( $obj ) ); // 2 unserialize due to an old storage bug
225
 
226
  $terms = array_unique( $terms );
227
 
228
+ // Insert terms
229
  if ( ! empty( $terms ) ) {
230
  $wpdb->query( "INSERT INTO $wpdb->terms ( slug, name ) VALUES " . implode( ',', $terms ) );
231
  }
232
 
233
+ // Get all terms with their term_id
234
  $terms = $wpdb->get_results( "SELECT term_id, slug FROM $wpdb->terms WHERE slug IN ( " . implode( ',', $slugs ) . " )" );
235
 
236
+ // Prepare terms taxonomy relationship
237
  foreach ( $terms as $term ) {
238
  $tts[] = $wpdb->prepare( '( %d, "%s", "%s" )', $term->term_id, $type . '_translations', $description[ $term->slug ] );
239
  }
240
 
241
  $tts = array_unique( $tts );
242
 
243
+ // Insert term_taxonomy
244
  if ( ! empty( $tts ) ) {
245
  $wpdb->query( "INSERT INTO $wpdb->term_taxonomy ( term_id, taxonomy, description ) VALUES " . implode( ',', $tts ) );
246
  }
247
 
248
+ // Get all terms with term_taxonomy_id
249
  $terms = get_terms( $type . '_translations', array( 'hide_empty' => false ) );
250
 
251
+ // Prepare objects relationships
252
  foreach ( $terms as $term ) {
253
  $translations = unserialize( $term->description );
254
  foreach ( $translations as $object_id ) {
260
 
261
  $trs = array_unique( $trs );
262
 
263
+ // Insert term_relationships
264
  if ( ! empty( $trs ) ) {
265
  $wpdb->query( "INSERT INTO $wpdb->term_relationships ( object_id, term_taxonomy_id ) VALUES " . implode( ',', $trs ) );
266
  }
267
  }
268
 
269
+ // Upgrade of string translations is now in upgrade_1_2_1
270
+ // Upgrade of nav menus is now in upgrade_1_2_3
271
  }
272
 
273
  /**
274
+ * Upgrades if the previous version is < 1.2.1
275
  *
276
  * @since 1.2.1
277
  */
278
  protected function upgrade_1_2_1() {
279
+ // Strings translations
280
  foreach ( get_terms( 'language', array( 'hide_empty' => 0 ) ) as $lang ) {
281
  if ( $strings = get_option( 'polylang_mo' . $lang->term_id ) ) {
282
  $mo = new PLL_MO();
289
  }
290
 
291
  /**
292
+ * Upgrades if the previous version is < 1.2.3
293
+ * Uprades multilingual menus depending on the old version due to multiple changes in menus management
294
  *
295
  * @since 1.2.3
296
  */
297
  public function upgrade_1_2_3() {
298
+ // Old version < 1.1
299
+ // Multilingal locations and switcher item were stored in a dedicated option
300
  if ( version_compare( $this->options['version'], '1.1', '<' ) ) {
301
  if ( $menu_lang = get_option( 'polylang_nav_menus' ) ) {
302
  foreach ( $menu_lang as $location => $arr ) {
309
  $has_switcher = array_shift( $switch_options );
310
 
311
  foreach ( get_terms( 'language', array( 'hide_empty' => 0 ) ) as $lang ) {
312
+ // Move nav menus locations
313
  if ( ! empty( $translations[ $lang->slug ] ) ) {
314
  $locations[ $location ][ $lang->slug ] = $translations[ $lang->slug ];
315
  }
316
 
317
+ // Create the menu items for the language switcher
318
  if ( ! empty( $has_switcher ) ) {
319
  $menu_item_db_id = wp_update_nav_menu_item( $translations[ $lang->slug ], 0, array(
320
  'menu-item-title' => __( 'Language switcher', 'polylang' ),
339
  $menus = get_theme_mod( 'nav_menu_locations' );
340
 
341
  if ( is_array( $menus ) ) {
342
+ // If old version < 1.2
343
+ // Clean the WP option as it was a bad idea to pollute it
344
  if ( version_compare( $this->options['version'], '1.2', '<' ) ) {
345
  foreach ( $menus as $loc => $menu ) {
346
  if ( $pos = strpos( $loc, '#' ) ) {
351
  set_theme_mod( 'nav_menu_locations', $menus );
352
  }
353
 
354
+ // Get the multilingual locations
355
  foreach ( $menus as $loc => $menu ) {
356
  foreach ( get_terms( 'language', array( 'hide_empty' => 0 ) ) as $lang ) {
357
  $arr[ $loc ][ $lang->slug ] = pll_get_term( $menu, $lang );
366
  }
367
 
368
  /**
369
+ * Upgrades if the previous version is < 1.3
370
+ * Moves the user biographies in default language to the 'description' user meta
371
  *
372
  * @since 1.3
373
  */
385
  }
386
 
387
  /**
388
+ * Upgrades if the previous version is < 1.4
389
+ * Sets a transient to delete old model data
390
+ * Deletes language cache (due to bug correction in home urls in 1.3.1 and added mo_id in 1.4)
391
  *
392
  * @since 1.4
393
  */
397
  }
398
 
399
  /**
400
+ * Old data were not deleted in 1.2, just in case...
401
+ * Delete them at first upgrade at least 60 days after upgrade to 1.4
402
  *
403
  * @since 1.4
404
  */
405
  protected function delete_pre_1_2_data() {
406
+ // Suppress data of the old model < 1.2
407
  global $wpdb;
408
  $wpdb->termmeta = $wpdb->prefix . 'termmeta'; // registers the termmeta table in wpdb in case WP < 4.4
409
 
410
+ // Do nothing if the termmeta table does not exists
411
  if ( count( $wpdb->get_results( "SHOW TABLES LIKE '$wpdb->termmeta'" ) ) ) {
412
  $wpdb->query( "DELETE FROM $wpdb->postmeta WHERE meta_key = '_translations'" );
413
  $wpdb->query( "DELETE FROM $wpdb->termmeta WHERE meta_key = '_language'" );
415
  $wpdb->query( "DELETE FROM $wpdb->termmeta WHERE meta_key = '_translations'" );
416
  }
417
 
418
+ // Delete the strings translations
419
  $languages = get_terms( 'language', array( 'hide_empty' => false ) );
420
  foreach ( $languages as $lang ) {
421
  delete_option( 'polylang_mo' . $lang->term_id );
425
  }
426
 
427
  /**
428
+ * Upgrades if the previous version is < 1.4.1
429
+ * Disables the browser detection when using multiple domains
430
  *
431
  * @since 1.4.1
432
  */
437
  }
438
 
439
  /**
440
+ * Upgrades if the previous version is < 1.4.4
441
+ * Uprades widgets options for language filter
442
  *
443
  * @since 1.4.4
444
  */
457
  }
458
 
459
  /**
460
+ * Upgrades if the previous version is < 1.5
461
+ * Deletes language cache (due to host property added and bug on search url)
462
  *
463
  * @since 1.5
464
  */
467
  }
468
 
469
  /**
470
+ * Upgrades if the previous version is < 1.6
471
+ * Upgrades core language files to get the .po file (only for WP 4.0+)
472
  *
473
  * @since 1.6
474
  */
479
  }
480
 
481
  /**
482
+ * Downloads language packs
483
+ * Intended to be used only one time (at upgrade to Polylang 1.6 or first upgrade of WP 4.0 or later)
484
+ * Adapted from wp_download_language_pack
485
+ * Rewritten because wp_download_language_pack checks the existence of .mo and I need to download .po
486
  *
487
  * @since 1.6
488
  */
489
  static function download_language_packs() {
490
  $languages = pll_languages_list( array( 'fields' => 'locale' ) );
491
 
492
+ // Prevents upgrade if the .po file is already here. Let WP manage the upgrades :)
493
  foreach ( $languages as $key => $locale ) {
494
  if ( file_exists( WP_LANG_DIR . "/$locale.po" ) ) {
495
  unset( $languages[ $key ] );
521
  }
522
 
523
  /**
524
+ * Upgrades if the previous version is < 1.7.4
525
  *
526
  * @since 1.7.4
527
  */
528
  protected function upgrade_1_7_4() {
529
+ delete_transient( 'pll_languages_list' ); // Deletes language cache (due to flag properties added in 1.7, page on front removed in 1.7.2, home url fixes in 1.7.4)
530
+ flush_rewrite_rules(); // Flush rewrite rules due to custom taxonomy rewrite rule bug fix
531
  }
532
 
533
  /**
534
+ * Upgrades if the previous version is < 1.8
535
  *
536
  * @since 1.8
537
  */
538
  protected function upgrade_1_8() {
539
+ // Adds the flag code in languages stored in DB
540
  include( PLL_SETTINGS_INC . '/languages.php' );
541
 
542
  $terms = get_terms( 'language', array( 'hide_empty' => 0 ) );
552
 
553
  delete_transient( 'pll_languages_list' );
554
  }
555
+
556
+ /**
557
+ * Upgrades if the previous version is < 2.0.8
558
+ * Changes the user meta 'user_lang' to 'locale' to match WP 4.7 choice
559
+ *
560
+ * @since 2.0.8
561
+ */
562
+ protected function upgrade_2_0_8() {
563
+ global $wpdb;
564
+ $wpdb->update( $wpdb->usermeta, array( 'meta_key' => 'locale' ), array( 'meta_key' => 'user_lang' ) );
565
+ }
566
  }
js/post.js CHANGED
@@ -2,7 +2,7 @@
2
  // valid for both tag metabox and quick edit
3
  (function( $ ){
4
  $.ajaxPrefilter(function( options, originalOptions, jqXHR ) {
5
- if ( -1 !== options.url.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
  });
2
  // valid for both tag metabox and quick edit
3
  (function( $ ){
4
  $.ajaxPrefilter(function( options, originalOptions, jqXHR ) {
5
+ if ( ( -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
  });
js/post.min.js CHANGED
@@ -1 +1 @@
1
- !function(a){a.ajaxPrefilter(function(t,n,e){-1!==t.url.indexOf("action=ajax-tag-search")&&((lang=a(".post_lang_choice").val())||(lang=a(':input[name="inline_lang_choice"]').val()))&&(t.data="lang="+lang+"&"+t.data)})}(jQuery),function(a){tagBox.get=function(t){var n=t.substr(t.indexOf("-")+1),e={action:"get-tagcloud",lang:a(".post_lang_choice").val(),tax:n};a.post(ajaxurl,e,function(e,i){(0==e||"success"!=i)&&(e=wpAjax.broken),e=a('<p id="tagcloud-'+n+'" class="the-tagcloud">'+e+"</p>"),a("a",e).click(function(){return tagBox.flushTags(a(this).closest(".inside").children(".tagsdiv"),this),!1}),(v=a(".the-tagcloud").css("display"))?(a(".the-tagcloud").replaceWith(e),a(".the-tagcloud").css("display",v)):a("#"+t).after(e)})}}(jQuery),function(a){a(document).bind("DOMNodeInserted",function(t){function n(t){"undefined"!=typeof pll_term_languages&&a.each(pll_term_languages,function(n,e){a.each(e,function(e,i){a.each(i,function(i){id="#"+e+"-"+pll_term_languages[n][e][i],t==n?a(id).show():a(id).hide()})})})}function e(t){"undefined"!=typeof pll_page_languages&&a.each(pll_page_languages,function(n,e){a.each(e,function(e){v=a('#post_parent option[value="'+pll_page_languages[n][e]+'"]'),t==n?v.show():v.hide()})})}var i=a(t.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=a("#lang_"+l).html();s.val(o),n(o),e(o),s.change(function(){n(a(this).val()),e(a(this).val())})}}})}(jQuery),function(a){a(document).ajaxSuccess(function(t,n,e){function i(t){var n=new Array;a(".translation_"+t).each(function(){n.push(a(this).parent().parent().attr("id").substring(5))});var e={action:"pll_update_post_rows",post_id:t,translations:n.join(","),post_type:a("input[name='post_type']").val(),screen:a("input[name='screen']").val(),_pll_nonce:a("input[name='_inline_edit']").val()};a.post(ajaxurl,e,function(t){if(t){var n=wpAjax.parseAjaxResponse(t,"ajax-response");a.each(n.responses,function(){"row"==this.what&&a("#post-"+this.supplemental.post_id).replaceWith(this.data)})}})}var l=wpAjax.unserialize(e.data);"undefined"!=typeof l.action&&"inline-save"==l.action&&i(l.post_ID)})}(jQuery),jQuery(document).ready(function(a){function t(){a(".tr_lang").each(function(){var t=a(this).attr("id").substring(8),n=a(this).parent().siblings(".pll-edit-column");a(this).autocomplete({minLength:0,source:ajaxurl+"?action=pll_posts_not_translated&post_language="+a(".post_lang_choice").val()+"&translation_language="+t+"&post_type="+a("#post_type").val()+"&_pll_nonce="+a("#_pll_nonce").val(),select:function(e,i){a("#htr_lang_"+t).val(i.item.id),n.html(i.item.link)}}),a(this).blur(function(){a(this).val()||(a("#htr_lang_"+t).val(0),n.html(n.siblings(".hidden").children().clone()))})})}var n=new Array;a(".categorydiv").each(function(){var t,e,i=a(this).attr("id");t=i.split("-"),t.shift(),e=t.join("-"),n.push(e),a("#"+e+"-add-submit").before(a("<input />").attr("type","hidden").attr("id",e+"-lang").attr("name","term_lang_choice").attr("value",a(".post_lang_choice").val()))}),a(".post_lang_choice").change(function(){var e={action:"post_lang_choice",lang:a(this).val(),post_type:a("#post_type").val(),taxonomies:n,post_id:a("#post_ID").val(),_pll_nonce:a("#_pll_nonce").val()};a.post(ajaxurl,e,function(n){var e=wpAjax.parseAjaxResponse(n,"ajax-response");a.each(e.responses,function(){switch(this.what){case"translations":a(".translations").html(this.data),t();break;case"taxonomy":var n=this.data;a("#"+n+"checklist").html(this.supplemental.all),a("#"+n+"checklist-pop").html(this.supplemental.populars),a("#new"+n+"_parent").replaceWith(this.supplemental.dropdown),a("#"+n+"-lang").val(a(".post_lang_choice").val());break;case"pages":a("#parent_id").html(this.data);break;case"flag":a(".pll-select-flag").html(this.data);break;case"permalink":var e=a("#edit-slug-box");"-1"!=this.data&&e.children().length&&e.html(this.data)}}),a(".tagcloud-link").each(function(){var t=a(this).attr("id");tagBox.get(t)})})}),t()});
1
+ !function(a){a.ajaxPrefilter(function(t){-1===t.url.indexOf("action=ajax-tag-search")&&-1===t.data.indexOf("action=ajax-tag-search")||!(lang=a(".post_lang_choice").val())&&!(lang=a(':input[name="inline_lang_choice"]').val())||(t.data="lang="+lang+"&"+t.data)})}(jQuery),function(a){tagBox.get=function(t){var n=t.substr(t.indexOf("-")+1),e={action:"get-tagcloud",lang:a(".post_lang_choice").val(),tax:n};a.post(ajaxurl,e,function(e,i){0!=e&&"success"==i||(e=wpAjax.broken),e=a('<p id="tagcloud-'+n+'" class="the-tagcloud">'+e+"</p>"),a("a",e).click(function(){return tagBox.flushTags(a(this).closest(".inside").children(".tagsdiv"),this),!1}),(v=a(".the-tagcloud").css("display"))?(a(".the-tagcloud").replaceWith(e),a(".the-tagcloud").css("display",v)):a("#"+t).after(e)})}}(jQuery),function(a){a(document).bind("DOMNodeInserted",function(t){function n(t){"undefined"!=typeof pll_term_languages&&a.each(pll_term_languages,function(n,e){a.each(e,function(e,i){a.each(i,function(i){id="#"+e+"-"+pll_term_languages[n][e][i],t==n?a(id).show():a(id).hide()})})})}function e(t){"undefined"!=typeof pll_page_languages&&a.each(pll_page_languages,function(n,e){a.each(e,function(e){v=a('#post_parent option[value="'+pll_page_languages[n][e]+'"]'),t==n?v.show():v.hide()})})}var i=a(t.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=a("#lang_"+l).html();s.val(o),n(o),e(o),s.change(function(){n(a(this).val()),e(a(this).val())})}}})}(jQuery),function(a){a(document).ajaxSuccess(function(t,n,e){function i(t){var n=new Array;a(".translation_"+t).each(function(){n.push(a(this).parent().parent().attr("id").substring(5))});var e={action:"pll_update_post_rows",post_id:t,translations:n.join(","),post_type:a("input[name='post_type']").val(),screen:a("input[name='screen']").val(),_pll_nonce:a("input[name='_inline_edit']").val()};a.post(ajaxurl,e,function(t){if(t){var n=wpAjax.parseAjaxResponse(t,"ajax-response");a.each(n.responses,function(){"row"==this.what&&a("#post-"+this.supplemental.post_id).replaceWith(this.data)})}})}var l=wpAjax.unserialize(e.data);"undefined"!=typeof l.action&&"inline-save"==l.action&&i(l.post_ID)})}(jQuery),jQuery(document).ready(function(a){function t(){a(".tr_lang").each(function(){var t=a(this).attr("id").substring(8),n=a(this).parent().siblings(".pll-edit-column");a(this).autocomplete({minLength:0,source:ajaxurl+"?action=pll_posts_not_translated&post_language="+a(".post_lang_choice").val()+"&translation_language="+t+"&post_type="+a("#post_type").val()+"&_pll_nonce="+a("#_pll_nonce").val(),select:function(e,i){a("#htr_lang_"+t).val(i.item.id),n.html(i.item.link)}}),a(this).blur(function(){a(this).val()||(a("#htr_lang_"+t).val(0),n.html(n.siblings(".hidden").children().clone()))})})}var n=new Array;a(".categorydiv").each(function(){var t,e,i=a(this).attr("id");t=i.split("-"),t.shift(),e=t.join("-"),n.push(e),a("#"+e+"-add-submit").before(a("<input />").attr("type","hidden").attr("id",e+"-lang").attr("name","term_lang_choice").attr("value",a(".post_lang_choice").val()))}),a(".post_lang_choice").change(function(){var e={action:"post_lang_choice",lang:a(this).val(),post_type:a("#post_type").val(),taxonomies:n,post_id:a("#post_ID").val(),_pll_nonce:a("#_pll_nonce").val()};a.post(ajaxurl,e,function(n){var e=wpAjax.parseAjaxResponse(n,"ajax-response");a.each(e.responses,function(){switch(this.what){case"translations":a(".translations").html(this.data),t();break;case"taxonomy":var n=this.data;a("#"+n+"checklist").html(this.supplemental.all),a("#"+n+"checklist-pop").html(this.supplemental.populars),a("#new"+n+"_parent").replaceWith(this.supplemental.dropdown),a("#"+n+"-lang").val(a(".post_lang_choice").val());break;case"pages":a("#parent_id").html(this.data);break;case"flag":a(".pll-select-flag").html(this.data);break;case"permalink":var e=a("#edit-slug-box");"-1"!=this.data&&e.children().length&&e.html(this.data)}}),a(".tagcloud-link").each(function(){var t=a(this).attr("id");tagBox.get(t)})})}),t()});
modules/sync/admin-sync.php CHANGED
@@ -1,14 +1,14 @@
1
  <?php
2
 
3
  /**
4
- * manages copy and synchronization of terms and post metas
5
  *
6
  * @since 1.2
7
  */
8
  class PLL_Admin_Sync {
9
 
10
  /**
11
- * constructor
12
  *
13
  * @since 1.2
14
  *
@@ -18,8 +18,8 @@ class PLL_Admin_Sync {
18
  $this->model = &$polylang->model;
19
  $this->options = &$polylang->options;
20
 
21
- add_filter( 'wp_insert_post_parent', array( $this, 'wp_insert_post_parent' ) );
22
- add_action( 'add_meta_boxes', array( $this, 'add_meta_boxes' ), 5, 2 ); // before Types which populates custom fields in same hook with priority 10
23
 
24
  add_action( 'pll_save_post', array( $this, 'pll_save_post' ), 10, 3 );
25
  add_action( 'pll_save_term', array( $this, 'pll_save_term' ), 10, 3 );
@@ -32,19 +32,22 @@ class PLL_Admin_Sync {
32
  }
33
 
34
  /**
35
- * translate post parent if exists when using "Add new" ( translation )
36
  *
37
  * @since 0.6
38
  *
39
- * @param int $post_parent
 
 
40
  * @return int
41
  */
42
- public function wp_insert_post_parent( $post_parent ) {
43
- return isset( $_GET['from_post'], $_GET['new_lang'] ) && ( $id = wp_get_post_parent_id( (int) $_GET['from_post'] ) ) && ( $parent = $this->model->post->get_translation( $id, $_GET['new_lang'] ) ) ? $parent : $post_parent;
 
44
  }
45
 
46
  /**
47
- * copy post metas, menu order, comment and ping status when using "Add new" ( translation )
48
  * formerly used dbx_post_advanced deprecated in WP 3.7
49
  *
50
  * @since 1.2
@@ -54,7 +57,7 @@ class PLL_Admin_Sync {
54
  */
55
  public function add_meta_boxes( $post_type, $post ) {
56
  if ( 'post-new.php' == $GLOBALS['pagenow'] && isset( $_GET['from_post'], $_GET['new_lang'] ) && $this->model->is_translated_post_type( $post->post_type ) ) {
57
- // capability check already done in post-new.php
58
  $from_post_id = (int) $_GET['from_post'];
59
  $from_post = get_post( $from_post_id );
60
  $lang = $this->model->get_language( $_GET['new_lang'] );
@@ -77,7 +80,7 @@ class PLL_Admin_Sync {
77
  }
78
 
79
  /**
80
- * get the list of taxonomies to copy or to synchronize
81
  *
82
  * @since 1.7
83
  *
@@ -102,7 +105,7 @@ class PLL_Admin_Sync {
102
  }
103
 
104
  /**
105
- * copy or synchronize terms
106
  *
107
  * @since 1.8
108
  *
@@ -112,29 +115,29 @@ class PLL_Admin_Sync {
112
  * @param bool $sync true if it is synchronization, false if it is a copy, defaults to false
113
  */
114
  public function copy_taxonomies( $from, $to, $lang, $sync = false ) {
115
- // get taxonomies to sync for this post type
116
  $taxonomies = array_intersect( get_post_taxonomies( $from ), $this->get_taxonomies_to_copy( $sync ) );
117
 
118
- // update the term cache to reduce the number of queries in the loop
119
  update_object_term_cache( $sync ? array( $from, $to ) : $from, get_post_type( $from ) );
120
 
121
- // copy or synchronize terms
122
  // FIXME quite a lot of query in foreach
123
  foreach ( $taxonomies as $tax ) {
124
  $terms = get_the_terms( $from, $tax );
125
 
126
- // translated taxonomy
127
  if ( $this->model->is_translated_taxonomy( $tax ) ) {
128
  $newterms = array();
129
  if ( is_array( $terms ) ) {
130
  foreach ( $terms as $term ) {
131
  if ( $term_id = $this->model->term->get_translation( $term->term_id, $lang ) ) {
132
- $newterms[] = (int) $term_id; // cast is important otherwise we get 'numeric' tags
133
  }
134
  }
135
  }
136
 
137
- // for some reasons, the user may have untranslated terms in the translation. don't forget them.
138
  if ( $sync ) {
139
  $tr_terms = get_the_terms( $to, $tax );
140
  if ( is_array( $tr_terms ) ) {
@@ -151,8 +154,8 @@ class PLL_Admin_Sync {
151
  }
152
  }
153
 
154
- // untranslated taxonomy ( post format )
155
- // don't use simple get_post_format / set_post_format to generalize the case to other taxonomies
156
  else {
157
  wp_set_object_terms( $to, is_array( $terms ) ? array_map( 'intval', wp_list_pluck( $terms, 'term_id' ) ) : null, $tax );
158
  }
@@ -160,21 +163,21 @@ class PLL_Admin_Sync {
160
  }
161
 
162
  /**
163
- * copy or synchronize metas (custom fields)
164
  *
165
  * @since 0.9
166
  *
167
  * @param int $from id of the post from which we copy informations
168
  * @param int $to id of the post to which we paste informations
169
  * @param string $lang language slug
170
- * @param bool $sync true if it is synchronization, false if it is a copy, defaults to false
171
  */
172
  public function copy_post_metas( $from, $to, $lang, $sync = false ) {
173
- // copy or synchronize post metas and allow plugins to do the same
174
  $metas = get_post_custom( $from );
175
  $keys = array();
176
 
177
- // get public meta keys ( including from translated post in case we just deleted a custom field )
178
  if ( ! $sync || in_array( 'post_meta', $this->options['sync'] ) ) {
179
  foreach ( $keys = array_unique( array_merge( array_keys( $metas ), array_keys( get_post_custom( $to ) ) ) ) as $k => $meta_key ) {
180
  if ( is_protected_meta( $meta_key ) ) {
@@ -183,7 +186,7 @@ class PLL_Admin_Sync {
183
  }
184
  }
185
 
186
- // add page template and featured image
187
  foreach ( array( '_wp_page_template', '_thumbnail_id' ) as $meta ) {
188
  if ( ! $sync || in_array( $meta, $this->options['sync'] ) ) {
189
  $keys[] = $meta;
@@ -204,15 +207,15 @@ class PLL_Admin_Sync {
204
  */
205
  $keys = array_unique( apply_filters( 'pll_copy_post_metas', $keys, $sync, $from, $to, $lang ) );
206
 
207
- // and now copy / synchronize
208
  foreach ( $keys as $key ) {
209
- delete_post_meta( $to, $key ); // the synchronization process of multiple values custom fields is easier if we delete all metas first
210
  if ( isset( $metas[ $key ] ) ) {
211
  foreach ( $metas[ $key ] as $value ) {
212
- // important: always maybe_unserialize value coming from get_post_custom. See codex.
213
- // thanks to goncalveshugo http://wordpress.org/support/topic/plugin-polylang-pll_copy_post_meta
214
  $value = maybe_unserialize( $value );
215
- // special case for featured images which can be translated
216
  add_post_meta( $to, $key, ( '_thumbnail_id' == $key && $tr_value = $this->model->post->get_translation( $value, $lang ) ) ? $tr_value : $value );
217
  }
218
  }
@@ -220,7 +223,7 @@ class PLL_Admin_Sync {
220
  }
221
 
222
  /**
223
- * synchronizes terms and metas in translations
224
  *
225
  * @since 1.2
226
  *
@@ -229,9 +232,9 @@ class PLL_Admin_Sync {
229
  * @param array $translations post translations
230
  */
231
  public function pll_save_post( $post_id, $post, $translations ) {
232
- global $wpdb;
233
 
234
- // prepare properties to synchronize
235
  foreach ( array( 'comment_status', 'ping_status', 'menu_order', 'post_date' ) as $property ) {
236
  if ( in_array( $property, $this->options['sync'] ) ) {
237
  $postarr[ $property ] = $post->$property;
@@ -242,35 +245,36 @@ class PLL_Admin_Sync {
242
  $postarr['post_date_gmt'] = $post->post_date_gmt;
243
  }
244
 
245
- // synchronize terms and metas in translations
246
  foreach ( $translations as $lang => $tr_id ) {
247
  if ( ! $tr_id || $tr_id === $post_id ) {
248
  continue;
249
  }
250
 
251
- // synchronize terms and metas
252
  $this->copy_taxonomies( $post_id, $tr_id, $lang, true );
253
  $this->copy_post_metas( $post_id, $tr_id, $lang, true );
254
 
255
- // sticky posts
256
  if ( in_array( 'sticky_posts', $this->options['sync'] ) ) {
257
  isset( $_REQUEST['sticky'] ) ? stick_post( $tr_id ) : unstick_post( $tr_id );
258
  }
259
 
260
- // add comment status, ping status, menu order... to synchronization
261
  $tr_arr = empty( $postarr ) ? array() : $postarr;
262
 
263
- // add post parent to synchronization
264
- // do not udpate the translation parent if the user set a parent with no translation
265
- if ( in_array( 'post_parent', $this->options['sync'] ) ) {
 
266
  $post_parent = ( $parent_id = wp_get_post_parent_id( $post_id ) ) ? $this->model->post->get_translation( $parent_id, $lang ) : 0;
267
  if ( ! ( $parent_id && ! $post_parent ) ) {
268
  $tr_arr['post_parent'] = $post_parent;
269
  }
270
  }
271
 
272
- // update all the row at once
273
- // don't use wp_update_post to avoid infinite loop
274
  if ( ! empty( $tr_arr ) ) {
275
  $wpdb->update( $wpdb->posts, $tr_arr, array( 'ID' => $tr_id ) );
276
  clean_post_cache( $tr_id );
@@ -279,7 +283,7 @@ class PLL_Admin_Sync {
279
  }
280
 
281
  /**
282
- * synchronize translations of a term in all posts
283
  *
284
  * @since 1.2
285
  *
@@ -288,12 +292,12 @@ class PLL_Admin_Sync {
288
  * @param array $translations translations of the term
289
  */
290
  public function pll_save_term( $term_id, $taxonomy, $translations ) {
291
- // check if the taxonomy is synchronized
292
  if ( ! $this->model->is_translated_taxonomy( $taxonomy ) || ! in_array( $taxonomy, $this->get_taxonomies_to_copy( true ) ) ) {
293
  return;
294
  }
295
 
296
- // get all posts associated to this term
297
  $posts = get_posts( array(
298
  'numberposts' => -1,
299
  'nopaging' => true,
@@ -308,7 +312,7 @@ class PLL_Admin_Sync {
308
  ) ),
309
  ) );
310
 
311
- // associate translated term to translated post
312
  // FIXME quite a lot of query in foreach
313
  foreach ( $this->model->get_languages_list() as $language ) {
314
  if ( $translated_term = $this->model->term->get( $term_id, $language ) ) {
@@ -320,16 +324,16 @@ class PLL_Admin_Sync {
320
  }
321
  }
322
 
323
- // synchronize parent in translations
324
- // calling clean_term_cache *after* this is mandatory otherwise the $taxonomy_children option is not correctly updated
325
- // 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
326
- // this is the reason to use the edit_term filter and not edited_term
327
- // take care that $_POST contains the only valid values for the current term
328
  // FIXME can I synchronize parent without using $_POST instead?
329
  if ( isset( $_POST['term_tr_lang'] ) ) {
330
  foreach ( $_POST['term_tr_lang'] as $lang => $tr_id ) {
331
  if ( $tr_id ) {
332
- if ( isset( $_POST['parent'] ) && -1 != $_POST['parent'] ) { // since WP 3.1
333
  $term_parent = $this->model->term->get_translation( (int) $_POST['parent'], $lang );
334
  }
335
 
@@ -346,7 +350,7 @@ class PLL_Admin_Sync {
346
  }
347
 
348
  /**
349
- * synchronizes terms and metas in translations for media
350
  *
351
  * @since 1.8
352
  *
1
  <?php
2
 
3
  /**
4
+ * Manages copy and synchronization of terms and post metas
5
  *
6
  * @since 1.2
7
  */
8
  class PLL_Admin_Sync {
9
 
10
  /**
11
+ * Constructor
12
  *
13
  * @since 1.2
14
  *
18
  $this->model = &$polylang->model;
19
  $this->options = &$polylang->options;
20
 
21
+ add_filter( 'wp_insert_post_parent', array( $this, 'wp_insert_post_parent' ), 10, 3 );
22
+ add_action( 'add_meta_boxes', array( $this, 'add_meta_boxes' ), 5, 2 ); // Before Types which populates custom fields in same hook with priority 10
23
 
24
  add_action( 'pll_save_post', array( $this, 'pll_save_post' ), 10, 3 );
25
  add_action( 'pll_save_term', array( $this, 'pll_save_term' ), 10, 3 );
32
  }
33
 
34
  /**
35
+ * Translate post parent if exists when using "Add new" ( translation )
36
  *
37
  * @since 0.6
38
  *
39
+ * @param int $post_parent Post parent ID
40
+ * @param int $post_id Post ID, unused
41
+ * @param array $postarr Array of parsed post data
42
  * @return int
43
  */
44
+ public function wp_insert_post_parent( $post_parent, $post_id, $postarr ) {
45
+ // Make sure not to impact media translations created at the same time
46
+ return isset( $_GET['from_post'], $_GET['new_lang'], $_GET['post_type'] ) && $_GET['post_type'] === $postarr['post_type'] && ( $id = wp_get_post_parent_id( (int) $_GET['from_post'] ) ) && ( $parent = $this->model->post->get_translation( $id, $_GET['new_lang'] ) ) ? $parent : $post_parent;
47
  }
48
 
49
  /**
50
+ * Copy post metas, menu order, comment and ping status when using "Add new" ( translation )
51
  * formerly used dbx_post_advanced deprecated in WP 3.7
52
  *
53
  * @since 1.2
57
  */
58
  public function add_meta_boxes( $post_type, $post ) {
59
  if ( 'post-new.php' == $GLOBALS['pagenow'] && isset( $_GET['from_post'], $_GET['new_lang'] ) && $this->model->is_translated_post_type( $post->post_type ) ) {
60
+ // Capability check already done in post-new.php
61
  $from_post_id = (int) $_GET['from_post'];
62
  $from_post = get_post( $from_post_id );
63
  $lang = $this->model->get_language( $_GET['new_lang'] );
80
  }
81
 
82
  /**
83
+ * Get the list of taxonomies to copy or to synchronize
84
  *
85
  * @since 1.7
86
  *
105
  }
106
 
107
  /**
108
+ * Copy or synchronize terms
109
  *
110
  * @since 1.8
111
  *
115
  * @param bool $sync true if it is synchronization, false if it is a copy, defaults to false
116
  */
117
  public function copy_taxonomies( $from, $to, $lang, $sync = false ) {
118
+ // Get taxonomies to sync for this post type
119
  $taxonomies = array_intersect( get_post_taxonomies( $from ), $this->get_taxonomies_to_copy( $sync ) );
120
 
121
+ // Update the term cache to reduce the number of queries in the loop
122
  update_object_term_cache( $sync ? array( $from, $to ) : $from, get_post_type( $from ) );
123
 
124
+ // Copy or synchronize terms
125
  // FIXME quite a lot of query in foreach
126
  foreach ( $taxonomies as $tax ) {
127
  $terms = get_the_terms( $from, $tax );
128
 
129
+ // Translated taxonomy
130
  if ( $this->model->is_translated_taxonomy( $tax ) ) {
131
  $newterms = array();
132
  if ( is_array( $terms ) ) {
133
  foreach ( $terms as $term ) {
134
  if ( $term_id = $this->model->term->get_translation( $term->term_id, $lang ) ) {
135
+ $newterms[] = (int) $term_id; // Cast is important otherwise we get 'numeric' tags
136
  }
137
  }
138
  }
139
 
140
+ // For some reasons, the user may have untranslated terms in the translation. don't forget them.
141
  if ( $sync ) {
142
  $tr_terms = get_the_terms( $to, $tax );
143
  if ( is_array( $tr_terms ) ) {
154
  }
155
  }
156
 
157
+ // Untranslated taxonomy ( post format )
158
+ // Don't use simple get_post_format / set_post_format to generalize the case to other taxonomies
159
  else {
160
  wp_set_object_terms( $to, is_array( $terms ) ? array_map( 'intval', wp_list_pluck( $terms, 'term_id' ) ) : null, $tax );
161
  }
163
  }
164
 
165
  /**
166
+ * Copy or synchronize metas (custom fields)
167
  *
168
  * @since 0.9
169
  *
170
  * @param int $from id of the post from which we copy informations
171
  * @param int $to id of the post to which we paste informations
172
  * @param string $lang language slug
173
+ * @param bool $sync true if it is synchronization, false if it is a copy, defaults to false
174
  */
175
  public function copy_post_metas( $from, $to, $lang, $sync = false ) {
176
+ // Copy or synchronize post metas and allow plugins to do the same
177
  $metas = get_post_custom( $from );
178
  $keys = array();
179
 
180
+ // Get public meta keys ( including from translated post in case we just deleted a custom field )
181
  if ( ! $sync || in_array( 'post_meta', $this->options['sync'] ) ) {
182
  foreach ( $keys = array_unique( array_merge( array_keys( $metas ), array_keys( get_post_custom( $to ) ) ) ) as $k => $meta_key ) {
183
  if ( is_protected_meta( $meta_key ) ) {
186
  }
187
  }
188
 
189
+ // Add page template and featured image
190
  foreach ( array( '_wp_page_template', '_thumbnail_id' ) as $meta ) {
191
  if ( ! $sync || in_array( $meta, $this->options['sync'] ) ) {
192
  $keys[] = $meta;
207
  */
208
  $keys = array_unique( apply_filters( 'pll_copy_post_metas', $keys, $sync, $from, $to, $lang ) );
209
 
210
+ // And now copy / synchronize
211
  foreach ( $keys as $key ) {
212
+ delete_post_meta( $to, $key ); // The synchronization process of multiple values custom fields is easier if we delete all metas first
213
  if ( isset( $metas[ $key ] ) ) {
214
  foreach ( $metas[ $key ] as $value ) {
215
+ // Important: always maybe_unserialize value coming from get_post_custom. See codex.
216
+ // Thanks to goncalveshugo http://wordpress.org/support/topic/plugin-polylang-pll_copy_post_meta
217
  $value = maybe_unserialize( $value );
218
+ // Special case for featured images which can be translated
219
  add_post_meta( $to, $key, ( '_thumbnail_id' == $key && $tr_value = $this->model->post->get_translation( $value, $lang ) ) ? $tr_value : $value );
220
  }
221
  }
223
  }
224
 
225
  /**
226
+ * Synchronizes terms and metas in translations
227
  *
228
  * @since 1.2
229
  *
232
  * @param array $translations post translations
233
  */
234
  public function pll_save_post( $post_id, $post, $translations ) {
235
+ global $wpdb, $post_type;
236
 
237
+ // Prepare properties to synchronize
238
  foreach ( array( 'comment_status', 'ping_status', 'menu_order', 'post_date' ) as $property ) {
239
  if ( in_array( $property, $this->options['sync'] ) ) {
240
  $postarr[ $property ] = $post->$property;
245
  $postarr['post_date_gmt'] = $post->post_date_gmt;
246
  }
247
 
248
+ // Synchronize terms and metas in translations
249
  foreach ( $translations as $lang => $tr_id ) {
250
  if ( ! $tr_id || $tr_id === $post_id ) {
251
  continue;
252
  }
253
 
254
+ // Synchronize terms and metas
255
  $this->copy_taxonomies( $post_id, $tr_id, $lang, true );
256
  $this->copy_post_metas( $post_id, $tr_id, $lang, true );
257
 
258
+ // Sticky posts
259
  if ( in_array( 'sticky_posts', $this->options['sync'] ) ) {
260
  isset( $_REQUEST['sticky'] ) ? stick_post( $tr_id ) : unstick_post( $tr_id );
261
  }
262
 
263
+ // Add comment status, ping status, menu order... to synchronization
264
  $tr_arr = empty( $postarr ) ? array() : $postarr;
265
 
266
+ // Add post parent to synchronization
267
+ // Make sure not to impact media translations when creating them at the same time as post
268
+ // Do not udpate the translation parent if the user set a parent with no translation
269
+ if ( in_array( 'post_parent', $this->options['sync'] ) && $post_type === $post->post_type ) {
270
  $post_parent = ( $parent_id = wp_get_post_parent_id( $post_id ) ) ? $this->model->post->get_translation( $parent_id, $lang ) : 0;
271
  if ( ! ( $parent_id && ! $post_parent ) ) {
272
  $tr_arr['post_parent'] = $post_parent;
273
  }
274
  }
275
 
276
+ // Update all the row at once
277
+ // Don't use wp_update_post to avoid infinite loop
278
  if ( ! empty( $tr_arr ) ) {
279
  $wpdb->update( $wpdb->posts, $tr_arr, array( 'ID' => $tr_id ) );
280
  clean_post_cache( $tr_id );
283
  }
284
 
285
  /**
286
+ * Synchronize translations of a term in all posts
287
  *
288
  * @since 1.2
289
  *
292
  * @param array $translations translations of the term
293
  */
294
  public function pll_save_term( $term_id, $taxonomy, $translations ) {
295
+ // Check if the taxonomy is synchronized
296
  if ( ! $this->model->is_translated_taxonomy( $taxonomy ) || ! in_array( $taxonomy, $this->get_taxonomies_to_copy( true ) ) ) {
297
  return;
298
  }
299
 
300
+ // Get all posts associated to this term
301
  $posts = get_posts( array(
302
  'numberposts' => -1,
303
  'nopaging' => true,
312
  ) ),
313
  ) );
314
 
315
+ // Associate translated term to translated post
316
  // FIXME quite a lot of query in foreach
317
  foreach ( $this->model->get_languages_list() as $language ) {
318
  if ( $translated_term = $this->model->term->get( $term_id, $language ) ) {
324
  }
325
  }
326
 
327
+ // Synchronize parent in translations
328
+ // Calling clean_term_cache *after* this is mandatory otherwise the $taxonomy_children option is not correctly updated
329
+ // 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
330
+ // This is the reason to use the edit_term filter and not edited_term
331
+ // Take care that $_POST contains the only valid values for the current term
332
  // FIXME can I synchronize parent without using $_POST instead?
333
  if ( isset( $_POST['term_tr_lang'] ) ) {
334
  foreach ( $_POST['term_tr_lang'] as $lang => $tr_id ) {
335
  if ( $tr_id ) {
336
+ if ( isset( $_POST['parent'] ) && -1 != $_POST['parent'] ) { // Since WP 3.1
337
  $term_parent = $this->model->term->get_translation( (int) $_POST['parent'], $lang );
338
  }
339
 
350
  }
351
 
352
  /**
353
+ * Synchronizes terms and metas in translations for media
354
  *
355
  * @since 1.8
356
  *
polylang.php CHANGED
@@ -3,7 +3,7 @@
3
  /*
4
  Plugin Name: Polylang
5
  Plugin URI: https://polylang.pro
6
- Version: 2.0.7
7
  Author: Frédéric Demarle
8
  Author uri: https://polylang.pro
9
  Description: Adds multilingual capability to WordPress
@@ -35,7 +35,7 @@ if ( ! defined( 'ABSPATH' ) ) {
35
  exit; // don't access directly
36
  };
37
 
38
- define( 'POLYLANG_VERSION', '2.0.7' );
39
  define( 'PLL_MIN_WP_VERSION', '4.0' );
40
 
41
  define( 'POLYLANG_FILE', __FILE__ ); // this file
3
  /*
4
  Plugin Name: Polylang
5
  Plugin URI: https://polylang.pro
6
+ Version: 2.0.8
7
  Author: Frédéric Demarle
8
  Author uri: https://polylang.pro
9
  Description: Adds multilingual capability to WordPress
35
  exit; // don't access directly
36
  };
37
 
38
+ define( 'POLYLANG_VERSION', '2.0.8' );
39
  define( 'PLL_MIN_WP_VERSION', '4.0' );
40
 
41
  define( 'POLYLANG_FILE', __FILE__ ); // this file
readme.txt CHANGED
@@ -3,8 +3,8 @@ Contributors: Chouby
3
  Donate link: https://polylang.pro
4
  Tags: multilingual, bilingual, translate, translation, language, multilanguage, international, localization
5
  Requires at least: 4.0
6
- Tested up to: 4.6
7
- Stable tag: 2.0.7
8
  License: GPLv2 or later
9
 
10
  Making WordPress multilingual
@@ -77,6 +77,16 @@ Don't hesitate to [give your feedback](http://wordpress.org/support/view/plugin-
77
 
78
  == Changelog ==
79
 
 
 
 
 
 
 
 
 
 
 
80
  = 2.0.7 (2016-10-18) =
81
 
82
  * Fix issues with static front pages introduced in version 2.0.6
3
  Donate link: https://polylang.pro
4
  Tags: multilingual, bilingual, translate, translation, language, multilanguage, international, localization
5
  Requires at least: 4.0
6
+ Tested up to: 4.7
7
+ Stable tag: 2.0.8
8
  License: GPLv2 or later
9
 
10
  Making WordPress multilingual
77
 
78
  == Changelog ==
79
 
80
+ = 2.0.8 (2016-11-14) =
81
+
82
+ * Disable admin language feature in WP 4.7+
83
+ * Pro: fix case where a media could lose its parent post when translated on the fly by the content duplication
84
+ * Pro: fix on the fly media created at content duplication attached to parent page instead of child page
85
+ * Fix translations input fields not populated in languages metabox when creating a new translation in WP 4.7
86
+ * Fix possibility to delete the translations of the default category in WP 4.7
87
+ * Fix tag search not filtered per language in Quick edit in WP 4.7
88
+ * Fix dropdown language switcher not working for untranslated pages
89
+
90
  = 2.0.7 (2016-10-18) =
91
 
92
  * Fix issues with static front pages introduced in version 2.0.6
uninstall.php CHANGED
@@ -1,27 +1,27 @@
1
  <?php
2
 
3
- // if uninstall not called from WordPress exit
4
  if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
5
  exit();
6
  }
7
 
8
  /**
9
- * manages Polylang uninstallation
10
- * the goal is to remove ALL Polylang related data in db
11
  *
12
  * @since 0.5
13
  */
14
  class PLL_Uninstall {
15
 
16
  /**
17
- * constructor: manages uninstall for multisite
18
  *
19
  * @since 0.5
20
  */
21
  function __construct() {
22
  global $wpdb;
23
 
24
- // check if it is a multisite uninstall - if so, run the uninstall function for each blog id
25
  if ( is_multisite() ) {
26
  foreach ( $wpdb->get_col( "SELECT blog_id FROM $wpdb->blogs" ) as $blog_id ) {
27
  switch_to_blog( $blog_id );
@@ -35,7 +35,7 @@ class PLL_Uninstall {
35
  }
36
 
37
  /**
38
- * removes ALL plugin data
39
  * only when the relevant option is active
40
  *
41
  * @since 0.5
@@ -47,12 +47,12 @@ class PLL_Uninstall {
47
  return;
48
  }
49
 
50
- // suppress data of the old model < 1.2
51
  // FIXME: to remove when support for v1.1.6 will be dropped
52
  global $wpdb;
53
  $wpdb->termmeta = $wpdb->prefix . 'termmeta'; // registers the termmeta table in wpdb
54
 
55
- // do nothing if the termmeta table does not exists
56
  if ( count( $wpdb->get_results( "SHOW TABLES LIKE '$wpdb->termmeta'" ) ) ) {
57
  $wpdb->query( "DELETE FROM $wpdb->postmeta WHERE meta_key = '_translations'" );
58
  $wpdb->query( "DELETE FROM $wpdb->termmeta WHERE meta_key = '_language'" );
@@ -60,7 +60,7 @@ class PLL_Uninstall {
60
  $wpdb->query( "DELETE FROM $wpdb->termmeta WHERE meta_key = '_translations'" );
61
  }
62
 
63
- // need to register the taxonomies
64
  $pll_taxonomies = array( 'language', 'term_language', 'post_translations', 'term_translations' );
65
  foreach ( $pll_taxonomies as $taxonomy ) {
66
  register_taxonomy( $taxonomy, null , array( 'label' => false, 'public' => false, 'query_var' => false, 'rewrite' => false ) );
@@ -68,16 +68,15 @@ class PLL_Uninstall {
68
 
69
  $languages = get_terms( 'language', array( 'hide_empty' => false ) );
70
 
71
- // delete users options
72
  foreach ( get_users( array( 'fields' => 'ID' ) ) as $user_id ) {
73
- delete_user_meta( $user_id, 'user_lang' );
74
  delete_user_meta( $user_id, 'pll_filter_content' );
75
  foreach ( $languages as $lang ) {
76
  delete_user_meta( $user_id, 'description_' . $lang->slug );
77
  }
78
  }
79
 
80
- // delete menu language switchers
81
  $ids = get_posts( array(
82
  'post_type' => 'nav_menu_item',
83
  'numberposts' => -1,
@@ -90,13 +89,13 @@ class PLL_Uninstall {
90
  wp_delete_post( $id, true );
91
  }
92
 
93
- // delete the strings translations ( <1.2 )
94
  // FIXME: to remove when support for v1.1.6 will be dropped
95
  foreach ( $languages as $lang ) {
96
  delete_option( 'polylang_mo' . $lang->term_id );
97
  }
98
 
99
- // delete the strings translations 1.2+
100
  register_post_type( 'polylang_mo', array( 'rewrite' => false, 'query_var' => false ) );
101
  $ids = get_posts( array(
102
  'post_type' => 'polylang_mo',
@@ -108,7 +107,7 @@ class PLL_Uninstall {
108
  wp_delete_post( $id, true );
109
  }
110
 
111
- // delete all what is related to languages and translations
112
  foreach ( get_terms( $pll_taxonomies, array( 'hide_empty' => false ) ) as $term ) {
113
  $term_ids[] = (int) $term->term_id;
114
  $tt_ids[] = (int) $term->term_taxonomy_id;
@@ -125,13 +124,13 @@ class PLL_Uninstall {
125
  $wpdb->query( "DELETE FROM $wpdb->term_relationships WHERE term_taxonomy_id IN ( " . implode( ',', $tt_ids ) . " )" );
126
  }
127
 
128
- // delete options
129
  delete_option( 'polylang' );
130
- delete_option( 'widget_polylang' ); // automatically created by WP
131
- delete_option( 'polylang_wpml_strings' ); // strings registered with icl_register_string
132
  delete_option( 'polylang_licenses' );
133
 
134
- //delete transients
135
  delete_transient( 'pll_languages_list' );
136
  delete_transient( 'pll_upgrade_1_4' );
137
  delete_transient( 'pll_translated_slugs' );
1
  <?php
2
 
3
+ // If uninstall not called from WordPress exit
4
  if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
5
  exit();
6
  }
7
 
8
  /**
9
+ * Manages Polylang uninstallation
10
+ * The goal is to remove ALL Polylang related data in db
11
  *
12
  * @since 0.5
13
  */
14
  class PLL_Uninstall {
15
 
16
  /**
17
+ * Constructor: manages uninstall for multisite
18
  *
19
  * @since 0.5
20
  */
21
  function __construct() {
22
  global $wpdb;
23
 
24
+ // Check if it is a multisite uninstall - if so, run the uninstall function for each blog id
25
  if ( is_multisite() ) {
26
  foreach ( $wpdb->get_col( "SELECT blog_id FROM $wpdb->blogs" ) as $blog_id ) {
27
  switch_to_blog( $blog_id );
35
  }
36
 
37
  /**
38
+ * Removes ALL plugin data
39
  * only when the relevant option is active
40
  *
41
  * @since 0.5
47
  return;
48
  }
49
 
50
+ // Suppress data of the old model < 1.2
51
  // FIXME: to remove when support for v1.1.6 will be dropped
52
  global $wpdb;
53
  $wpdb->termmeta = $wpdb->prefix . 'termmeta'; // registers the termmeta table in wpdb
54
 
55
+ // Do nothing if the termmeta table does not exists
56
  if ( count( $wpdb->get_results( "SHOW TABLES LIKE '$wpdb->termmeta'" ) ) ) {
57
  $wpdb->query( "DELETE FROM $wpdb->postmeta WHERE meta_key = '_translations'" );
58
  $wpdb->query( "DELETE FROM $wpdb->termmeta WHERE meta_key = '_language'" );
60
  $wpdb->query( "DELETE FROM $wpdb->termmeta WHERE meta_key = '_translations'" );
61
  }
62
 
63
+ // Need to register the taxonomies
64
  $pll_taxonomies = array( 'language', 'term_language', 'post_translations', 'term_translations' );
65
  foreach ( $pll_taxonomies as $taxonomy ) {
66
  register_taxonomy( $taxonomy, null , array( 'label' => false, 'public' => false, 'query_var' => false, 'rewrite' => false ) );
68
 
69
  $languages = get_terms( 'language', array( 'hide_empty' => false ) );
70
 
71
+ // Delete users options
72
  foreach ( get_users( array( 'fields' => 'ID' ) ) as $user_id ) {
 
73
  delete_user_meta( $user_id, 'pll_filter_content' );
74
  foreach ( $languages as $lang ) {
75
  delete_user_meta( $user_id, 'description_' . $lang->slug );
76
  }
77
  }
78
 
79
+ // Delete menu language switchers
80
  $ids = get_posts( array(
81
  'post_type' => 'nav_menu_item',
82
  'numberposts' => -1,
89
  wp_delete_post( $id, true );
90
  }
91
 
92
+ // Delete the strings translations ( <1.2 )
93
  // FIXME: to remove when support for v1.1.6 will be dropped
94
  foreach ( $languages as $lang ) {
95
  delete_option( 'polylang_mo' . $lang->term_id );
96
  }
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',
107
  wp_delete_post( $id, true );
108
  }
109
 
110
+ // Delete all what is related to languages and translations
111
  foreach ( get_terms( $pll_taxonomies, array( 'hide_empty' => false ) ) as $term ) {
112
  $term_ids[] = (int) $term->term_id;
113
  $tt_ids[] = (int) $term->term_taxonomy_id;
124
  $wpdb->query( "DELETE FROM $wpdb->term_relationships WHERE term_taxonomy_id IN ( " . implode( ',', $tt_ids ) . " )" );
125
  }
126
 
127
+ // Delete options
128
  delete_option( 'polylang' );
129
+ delete_option( 'widget_polylang' ); // Automatically created by WP
130
+ delete_option( 'polylang_wpml_strings' ); // Strings registered with icl_register_string
131
  delete_option( 'polylang_licenses' );
132
 
133
+ //Delete transients
134
  delete_transient( 'pll_languages_list' );
135
  delete_transient( 'pll_upgrade_1_4' );
136
  delete_transient( 'pll_translated_slugs' );