PluginProbe
Polylang / trunk
Polylang vtrunk
3.8.9 3.8.8 3.8.7 3.8.6 3.8.5 3.8.4 3.8.3 2.7 2.7.0.1 2.7.1 2.7.2 2.7.3 2.7.4 2.8 2.8.1 2.8.2 2.8.3 2.8.4 2.9 2.9.1 2.9.2 3.0 3.0.1 3.0.2 3.0.3 All 233 releases
polylang / src / install / upgrade.php

upgrade.php in Polylang trunk, at src/install/upgrade.php

429 lines 10.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package Polylang
4 */
5
6 use WP_Syntex\Polylang\Options\Options;
7 /**
8 * Manages Polylang upgrades
9 *
10 * @since 1.2
11 */
12 class PLL_Upgrade {
13 /**
14 * Stores the plugin options.
15 *
16 * @var Options
17 */
18 public $options;
19
20 /**
21 * Constructor
22 *
23 * @since 1.2
24 * @since 3.7 The `$options` parameter is an instance of `Options`.
25 *
26 * @param Options $options Polylang options.
27 */
28 public function __construct( Options $options ) {
29 $this->options = $options;
30 }
31
32 /**
33 * Upgrades if possible otherwise returns false to stop Polylang loading
34 *
35 * @since 1.2
36 *
37 * @return bool true if upgrade is possible, false otherwise
38 */
39 public function upgrade() {
40 if ( ! $this->can_upgrade() ) {
41 add_action( 'all_admin_notices', array( $this, 'admin_notices' ) );
42 return false;
43 }
44
45 add_action( 'admin_init', array( $this, '_upgrade' ) );
46 return true;
47 }
48
49
50 /**
51 * Check if we the previous version is not too old
52 * Upgrades if OK
53 * /!\ never start any upgrade before admin_init as it is likely to conflict with some other plugins
54 *
55 * @since 1.2
56 *
57 * @return bool true if upgrade is possible, false otherwise
58 */
59 public function can_upgrade() {
60 // Don't manage upgrade from version < 1.8
61 return version_compare( $this->options['version'], '1.8', '>=' );
62 }
63
64 /**
65 * Displays a notice when upgrading from a too old version.
66 *
67 * @since 1.0
68 *
69 * @return void
70 */
71 public function admin_notices() {
72 $message = sprintf(
73 '<p>%s</p><p>%s</p>',
74 esc_html__( 'Polylang has been deactivated because you upgraded from a too old version.', 'polylang' ),
75 sprintf(
76 /* translators: %1$s and %2$s are Polylang version numbers */
77 esc_html__( 'Before upgrading to %2$s, please upgrade to %1$s.', 'polylang' ),
78 '<strong>2.9</strong>',
79 esc_html( POLYLANG_VERSION )
80 )
81 );
82
83 $args = array(
84 'type' => 'error',
85 'paragraph_wrap' => false,
86 );
87
88 wp_admin_notice( $message, $args );
89 }
90
91 /**
92 * Upgrades the plugin depending on the previous version
93 *
94 * @since 1.2
95 *
96 * @return void
97 */
98 public function _upgrade() {
99 /*
100 * Delete the transient precisely at this point (`admin_init`)
101 * to ensure `Model\Languages` callbacks do their job.
102 * i.e. delete the transient from the options table when external object cache is used.
103 */
104 delete_transient( 'pll_languages_list' );
105
106 foreach ( array( '2.0.8', '2.1', '2.7', '3.4', '3.7', '3.8', '3.9' ) as $version ) {
107 if ( version_compare( $this->options['version'], $version, '<' ) ) {
108 $method_to_call = array( $this, 'upgrade_' . str_replace( '.', '_', $version ) );
109 if ( is_callable( $method_to_call ) ) {
110 call_user_func( $method_to_call );
111 }
112 }
113 }
114
115 /**
116 * Fires after Polylang has been upgraded and before the new version is saved in options.
117 *
118 * @since 3.7
119 */
120 do_action( 'pll_upgrade' );
121
122 $this->options['previous_version'] = $this->options['version']; // Remember the previous version of Polylang since v1.7.7
123 $this->options['version'] = POLYLANG_VERSION;
124 }
125
126 /**
127 * Upgrades if the previous version is < 2.0.8
128 * Changes the user meta 'user_lang' to 'locale' to match WP 4.7 choice
129 *
130 * @since 2.0.8
131 *
132 * @return void
133 */
134 protected function upgrade_2_0_8() {
135 global $wpdb;
136 $wpdb->update( $wpdb->usermeta, array( 'meta_key' => 'locale' ), array( 'meta_key' => 'user_lang' ) );
137 }
138
139 /**
140 * Upgrades if the previous version is < 2.1.
141 * Moves strings translations from polylang_mo post_content to post meta _pll_strings_translations.
142 *
143 * @since 2.1
144 *
145 * @return void
146 */
147 protected function upgrade_2_1() {
148 $posts = get_posts(
149 array(
150 'post_type' => 'polylang_mo',
151 'post_status' => 'any',
152 'numberposts' => -1,
153 'nopaging' => true,
154 )
155 );
156
157 if ( is_array( $posts ) ) {
158 foreach ( $posts as $post ) {
159 $meta = get_post_meta( $post->ID, '_pll_strings_translations', true );
160
161 if ( empty( $meta ) ) {
162 $strings = maybe_unserialize( $post->post_content );
163 if ( is_array( $strings ) ) {
164 update_post_meta( $post->ID, '_pll_strings_translations', $strings );
165 }
166 }
167 }
168 }
169 }
170
171 /**
172 * Upgrades if the previous version is < 2.7
173 * Replace numeric keys by hashes in WPML registered strings
174 * Dismiss the wizard notice for existing sites
175 *
176 * @since 2.7
177 *
178 * @return void
179 */
180 protected function upgrade_2_7() {
181 $strings = get_option( 'polylang_wpml_strings' );
182 if ( is_array( $strings ) ) {
183 $new_strings = array();
184
185 foreach ( $strings as $string ) {
186 $context = $string['context'];
187 $name = $string['name'];
188
189 $key = md5( "$context | $name" );
190 $new_strings[ $key ] = $string;
191 }
192 update_option( 'polylang_wpml_strings', $new_strings );
193 }
194
195 PLL_Admin_Notices::dismiss( 'wizard' );
196 }
197
198 /**
199 * Upgrades if the previous version is < 3.4.0.
200 *
201 * @since 3.4
202 *
203 * @return void
204 */
205 protected function upgrade_3_4() {
206 $this->migrate_locale_fallback_to_language_description();
207
208 $this->migrate_strings_translations();
209 }
210
211 /**
212 * Upgrades if the previous version is < 3.7.
213 * Hides the "The language is set from content" option if it isn't the one selected.
214 * Cleans up strings translations so we don't store translations duplicated from the source.
215 *
216 * @since 3.7
217 *
218 * @return void
219 */
220 protected function upgrade_3_7() {
221 $this->allow_to_hide_language_from_content();
222 $this->empty_duplicated_strings_translations();
223 }
224
225 /**
226 * Upgrades if the previous version is < 3.8.
227 * Migrates language taxonomies from `polylang` option to `pll_language_taxonomies` option.
228 *
229 * @since 3.8
230 *
231 * @return void
232 */
233 protected function upgrade_3_8() {
234 $options = get_option( 'polylang' );
235
236 $language_taxonomies = array();
237 if ( is_array( $options ) && isset( $options['language_taxonomies'] ) && is_array( $options['language_taxonomies'] ) ) {
238 $language_taxonomies = $options['language_taxonomies'];
239 }
240
241 update_option( 'pll_language_taxonomies', $language_taxonomies );
242 }
243
244 /**
245 * Upgrades if the previous version is < 3.9.
246 * Migrates flag codes in language terms.
247 *
248 * @since 3.9
249 *
250 * @return void
251 */
252 protected function upgrade_3_9() {
253 $to_migrate = array(
254 'arab' => 'ar.lang',
255 'basque' => 'es-pv',
256 'catalonia' => 'es-ct',
257 'england' => 'gb-eng',
258 'esperanto' => 'eo.lang',
259 'galicia' => 'es-ga',
260 'kurdistan' => 'iq-kr',
261 'occitania' => 'oci.lang',
262 'quebec' => 'ca-qc',
263 'scotland' => 'gb-sct',
264 'tibet' => 'bo.lang',
265 'veneto' => 'it-34',
266 'wales' => 'gb-wls',
267 );
268
269 $terms = get_terms(
270 array(
271 'taxonomy' => 'language',
272 'hide_empty' => false,
273 )
274 );
275
276 if ( ! is_array( $terms ) ) {
277 return;
278 }
279
280 foreach ( $terms as $term ) {
281 $description = maybe_unserialize( $term->description );
282 $description = is_array( $description ) ? $description : array();
283
284 if ( isset( $description['flag_code'] ) && is_string( $description['flag_code'] ) && isset( $to_migrate[ $description['flag_code'] ] ) ) {
285 $description['flag_code'] = $to_migrate[ $description['flag_code'] ];
286 /** @var string */
287 $description = maybe_serialize( $description );
288
289 wp_update_term( $term->term_id, 'language', array( 'description' => $description ) );
290 }
291 }
292 }
293
294 /**
295 * Moves strings translations from post meta to term meta _pll_strings_translations.
296 *
297 * @since 3.4
298 *
299 * @return void
300 */
301 protected function migrate_strings_translations() {
302 $posts = get_posts(
303 array(
304 'post_type' => 'polylang_mo',
305 'post_status' => 'any',
306 'numberposts' => -1,
307 'nopaging' => true,
308 )
309 );
310
311 if ( ! is_array( $posts ) ) {
312 return;
313 }
314
315 foreach ( $posts as $post ) {
316 $meta = get_post_meta( $post->ID, '_pll_strings_translations', true );
317
318 $term_id = (int) substr( $post->post_title, 12 );
319
320 // Do not delete post metas in case a user needs to rollback to Polylang < 3.4.
321
322 if ( empty( $meta ) || ! is_array( $meta ) ) {
323 continue;
324 }
325
326 update_term_meta( $term_id, '_pll_strings_translations', wp_slash( $meta ) );
327 }
328 }
329
330 /**
331 * Migrate locale fallback to language term description.
332 *
333 * @since 3.4
334 *
335 * @return void
336 */
337 protected function migrate_locale_fallback_to_language_description() {
338 // Migrate locale fallbacks from term metas to language term description.
339 $terms = get_terms(
340 array(
341 'taxonomy' => 'language',
342 'hide_empty' => false,
343 'meta_query' => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
344 array(
345 'key' => 'fallback',
346 'compare_key' => 'EXISTS',
347 ),
348 ),
349 )
350 );
351
352 if ( ! is_array( $terms ) ) {
353 return;
354 }
355
356 foreach ( $terms as $term ) {
357 $fallbacks = get_term_meta( $term->term_id, 'fallback', true );
358
359 delete_term_meta( $term->term_id, 'fallback' );
360
361 if ( empty( $fallbacks ) || ! is_array( $fallbacks ) ) {
362 // Empty or invalid value, should not happen.
363 continue;
364 }
365
366 $description = maybe_unserialize( $term->description );
367 $description = is_array( $description ) ? $description : array();
368
369 $description['fallbacks'] = $fallbacks;
370 /** @var string */
371 $description = maybe_serialize( $description );
372
373 wp_update_term( $term->term_id, 'language', array( 'description' => $description ) );
374 }
375 }
376
377 /**
378 * Hides the language from content option if it is not the one selected.
379 *
380 * @since 3.7
381 *
382 * @return void
383 */
384 private function allow_to_hide_language_from_content() {
385 update_option(
386 'pll_language_from_content_available',
387 0 === $this->options['force_lang'] ? 'yes' : 'no'
388 );
389 }
390
391 /**
392 * Cleans up strings translations so we don't store translations duplicated from the source.
393 *
394 * @since 3.7
395 *
396 * @return void
397 */
398 private function empty_duplicated_strings_translations() {
399 $terms = get_terms(
400 array(
401 'taxonomy' => 'language',
402 'hide_empty' => false,
403 )
404 );
405
406 if ( ! is_array( $terms ) ) {
407 return;
408 }
409
410 foreach ( $terms as $term ) {
411 $strings = get_term_meta( $term->term_id, '_pll_strings_translations', true );
412
413 if ( empty( $strings ) || ! is_array( $strings ) ) {
414 continue;
415 }
416
417 foreach ( $strings as $i => $tuple ) {
418 if ( $tuple[0] !== $tuple[1] ) {
419 continue;
420 }
421
422 $strings[ $i ][1] = '';
423 }
424
425 update_term_meta( $term->term_id, '_pll_strings_translations', $strings );
426 }
427 }
428 }
429