PluginProbe
Polylang / 3.7.7
Polylang v3.7.7
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
← All changes | modules/wizard/wizard.php +186 -96 2.93.7.7 View file →
@@ -2,8 +2,12 @@
2 2 /**
3 3 * @package Polylang
4 4 */
5 5
6 +defined( 'ABSPATH' ) || exit;
7 +
8 +use WP_Syntex\Polylang\Options\Options;
9 +
6 10 /**
7 11 * Main class for Polylang wizard.
8 12 *
9 13 * @since 2.7
@@ -9,39 +13,50 @@
9 13 * @since 2.7
10 14 */
11 15 class PLL_Wizard {
12 16 /**
13 - * Reference to PLL_Model object
17 + * Reference to the model object
14 18 *
15 - * @var object $model
19 + * @var PLL_Admin_Model
16 20 */
17 21 protected $model;
18 22
19 23 /**
20 - * Reference to Polylang options array
24 + * Reference to the Polylang options array.
21 25 *
22 - * @var array $options
26 + * @var array
23 27 */
24 28 protected $options;
25 29
26 30 /**
27 - * List of steps
31 + * List of steps.
28 32 *
29 - * @var array $steps {
30 - * @type string $name i18n string which names the step.
31 - * @type callable $view The callback function use to display the step content.
32 - * @type callable $handler The callback function use to process the step after it is submitted.
33 - * @type array $scripts List of scripts handle needed by the step.
34 - * @type array $styles The list of styles handle needed by the step.
33 + * @var array[] $steps {
34 + * @type array {
35 + * List of step properties.
36 + *
37 + * @type string $name I18n string which names the step.
38 + * @type callable $view The callback function use to display the step content.
39 + * @type callable $handler The callback function use to process the step after it is submitted.
40 + * @type array $scripts List of scripts handle needed by the step.
41 + * @type array $styles The list of styles handle needed by the step.
42 + * }
35 43 * }
36 44 */
37 45 protected $steps = array();
38 46
39 47 /**
40 - * List of WordPress CSS file handles
48 + * The current step.
41 49 *
42 - * @var array $styles
50 + * @var string|null
43 51 */
52 + protected $current_step;
53 +
54 + /**
55 + * List of WordPress CSS file handles.
56 + *
57 + * @var string[]
58 + */
44 59 protected $styles = array();
45 60
46 61 /**
47 62 * Constructor
@@ -53,9 +68,9 @@
53 68 $this->options = &$polylang->options;
54 69 $this->model = &$polylang->model;
55 70
56 71 // Display Wizard page before any other action to ensure displaying it outside the WordPress admin context.
57 - // Hooked on admin_init with priority 40 to ensure PLL_Wizard_Pro is corretly initialized.
72 + // Hooked on admin_init with priority 40 to ensure PLL_Wizard_Pro is correctly initialized.
58 73 add_action( 'admin_init', array( $this, 'setup_wizard_page' ), 40 );
59 74 // Add Wizard submenu.
60 75 add_filter( 'pll_settings_tabs', array( $this, 'settings_tabs' ), 10, 1 );
61 76 // Add filter to select screens where to display the notice.
@@ -72,15 +87,17 @@
72 87
73 88 /**
74 89 * Save an activation transient when Polylang is activating to redirect to the wizard
75 90 *
91 + * @since 2.7
92 + *
76 93 * @param bool $network_wide if activated for all sites in the network.
77 - * @since 2.7
94 + * @return void
78 95 */
79 96 public static function start_wizard( $network_wide ) {
80 - $options = get_option( 'polylang' );
97 + $options = (array) get_option( Options::OPTION_NAME, array() );
81 98
82 - if ( wp_doing_ajax() || $network_wide || ! empty( $options ) ) {
99 + if ( wp_doing_ajax() || $network_wide || ! empty( $options['version'] ) ) {
83 100 return;
84 101 }
85 102 set_transient( 'pll_activation_redirect', 1, 30 );
86 103 }
@@ -88,13 +105,15 @@
88 105 /**
89 106 * Redirect to the wizard depending on the context
90 107 *
91 108 * @since 2.7
109 + *
110 + * @return void
92 111 */
93 112 public function redirect_to_wizard() {
94 113 if ( get_transient( 'pll_activation_redirect' ) ) {
95 114 $do_redirect = true;
96 - if ( ( isset( $_GET['page'] ) && 'mlang_wizard' === sanitize_key( $_GET['page'] ) || isset( $_GET['activate-multi'] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
115 + if ( ( isset( $_GET['page'] ) && 'mlang_wizard' === sanitize_key( $_GET['page'] ) ) || isset( $_GET['activate-multi'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
97 116 delete_transient( 'pll_activation_redirect' );
98 117 $do_redirect = false;
99 118 }
100 119
@@ -99,9 +118,9 @@
99 118 }
100 119
101 120 if ( $do_redirect ) {
102 121 wp_safe_redirect(
103 - esc_url_raw(
122 + sanitize_url(
104 123 add_query_arg(
105 124 array(
106 125 'page' => 'mlang_wizard',
107 126 ),
@@ -116,11 +135,12 @@
116 135
117 136 /**
118 137 * Add an admin Polylang submenu to access the wizard
119 138 *
120 - * @param array $tabs Submenus list.
121 - * @return array Submenus list updated.
122 139 * @since 2.7
140 + *
141 + * @param string[] $tabs Submenus list.
142 + * @return string[] Submenus list updated.
123 143 */
124 144 public function settings_tabs( $tabs ) {
125 145 $tabs['wizard'] = esc_html__( 'Setup', 'polylang' );
126 146 return $tabs;
@@ -126,13 +146,14 @@
126 146 return $tabs;
127 147 }
128 148
129 149 /**
130 - * Return if the media step is displayable
150 + * Returns true if the media step is displayable, false otherwise.
131 151 *
132 - * @param array $languages List of language objects.
152 + * @since 2.7
153 + *
154 + * @param PLL_Language[] $languages List of language objects.
133 155 * @return bool
134 - * @since 2.7
135 156 */
136 157 public function is_media_step_displayable( $languages ) {
137 158 $media = array();
138 159 // If there is no language or only one the media step is displayable.
@@ -153,10 +174,11 @@
153 174
154 175 /**
155 176 * Check if the licenses step is displayable
156 177 *
178 + * @since 2.7
179 + *
157 180 * @return bool
158 - * @since 2.7
159 181 */
160 182 public function is_licenses_step_displayable() {
161 183 $licenses = apply_filters( 'pll_settings_licenses', array() );
162 184 return count( $licenses ) > 0;
@@ -165,8 +187,10 @@
165 187 /**
166 188 * Setup the wizard page
167 189 *
168 190 * @since 2.7
191 + *
192 + * @return void
169 193 */
170 194 public function setup_wizard_page() {
171 195
172 196 PLL_Admin_Notices::add_notice( 'wizard', $this->wizard_notice() );
@@ -184,26 +208,26 @@
184 208
185 209 $this->steps = apply_filters( 'pll_wizard_steps', $this->steps );
186 210 $step = isset( $_GET['step'] ) ? sanitize_key( $_GET['step'] ) : false; // phpcs:ignore WordPress.Security.NonceVerification
187 211
188 - $this->step = $step && array_key_exists( $step, $this->steps ) ? $step : current( array_keys( $this->steps ) );
212 + $this->current_step = $step && array_key_exists( $step, $this->steps ) ? $step : current( array_keys( $this->steps ) );
189 213
190 - $languages = $this->model->get_languages_list();
214 + $has_languages = $this->model->has_languages();
191 215
192 - if ( count( $languages ) === 0 && ! in_array( $this->step, array( 'licenses', 'languages' ) ) ) {
193 - wp_safe_redirect( esc_url_raw( $this->get_step_link( 'languages' ) ) );
216 + if ( ! $has_languages && ! in_array( $this->current_step, array( 'licenses', 'languages' ) ) ) {
217 + wp_safe_redirect( sanitize_url( $this->get_step_link( 'languages' ) ) );
194 218 exit;
195 219 }
196 220
197 - if ( count( $languages ) > 0 && $this->model->get_objects_with_no_lang( 1 ) && ! in_array( $this->step, array( 'licenses', 'languages', 'media', 'untranslated-contents' ) ) ) {
198 - wp_safe_redirect( esc_url_raw( $this->get_step_link( 'untranslated-contents' ) ) );
221 + if ( $has_languages && $this->model->get_objects_with_no_lang( 1 ) && ! in_array( $this->current_step, array( 'licenses', 'languages', 'media', 'untranslated-contents' ) ) ) {
222 + wp_safe_redirect( sanitize_url( $this->get_step_link( 'untranslated-contents' ) ) );
199 223 exit;
200 224 }
201 225
202 226 // Call the handler of the step for going to the next step.
203 227 // Be careful nonce verification with check_admin_referer must be done in each handler.
204 - if ( ! empty( $_POST['save_step'] ) && isset( $this->steps[ $this->step ]['handler'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
205 - call_user_func( $this->steps[ $this->step ]['handler'] );
228 + if ( ! empty( $_POST['save_step'] ) && isset( $this->steps[ $this->current_step ]['handler'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
229 + call_user_func( $this->steps[ $this->current_step ]['handler'] );
206 230 }
207 231
208 232 $this->display_wizard_page();
209 233 // Ensure nothing is done after including the page.
@@ -212,17 +236,18 @@
212 236
213 237 /**
214 238 * Adds some admin screens where to display the wizard notice
215 239 *
240 + * @since 2.7
241 + *
216 242 * @param bool $can_display_notice Whether the notice can be displayed.
217 243 * @param string $notice The notice name.
218 244 * @return bool
219 - * @since 2.7
220 245 */
221 246 public function can_display_notice( $can_display_notice, $notice ) {
222 247 if ( ! $can_display_notice && 'wizard' === $notice ) {
223 248 $screen = get_current_screen();
224 - $can_display_notice = in_array(
249 + $can_display_notice = ! empty( $screen ) && in_array(
225 250 $screen->base,
226 251 array(
227 252 'edit',
228 253 'upload',
@@ -236,8 +261,10 @@
236 261 /**
237 262 * Return html code of the wizard notice
238 263 *
239 264 * @since 2.7
265 + *
266 + * @return string
240 267 */
241 268 public function wizard_notice() {
242 269 ob_start();
243 270 include __DIR__ . '/html-wizard-notice.php';
@@ -247,11 +274,17 @@
247 274 /**
248 275 * Display the wizard page
249 276 *
250 277 * @since 2.7
278 + *
279 + * @return void
251 280 */
252 281 public function display_wizard_page() {
253 - set_current_screen();
282 + set_current_screen( 'pll-wizard' );
283 + do_action( 'admin_enqueue_scripts' );
284 + $steps = $this->steps;
285 + $current_step = $this->current_step;
286 + $styles = $this->styles;
254 287 include __DIR__ . '/view-wizard-page.php';
255 288 }
256 289
257 290 /**
@@ -257,12 +290,14 @@
257 290 /**
258 291 * Enqueue scripts and styles for the wizard
259 292 *
260 293 * @since 2.7
294 + *
295 + * @return void
261 296 */
262 297 public function enqueue_scripts() {
263 - wp_enqueue_style( 'polylang_admin', plugins_url( '/css/admin' . $this->get_suffix() . '.css', POLYLANG_FILE ), array(), POLYLANG_VERSION );
264 - wp_enqueue_style( 'pll-wizard', plugins_url( '/modules/wizard/css/wizard' . $this->get_suffix() . '.css', POLYLANG_FILE ), array( 'dashicons', 'install', 'common', 'forms' ), POLYLANG_VERSION );
298 + wp_enqueue_style( 'polylang_admin', plugins_url( '/css/build/admin' . $this->get_suffix() . '.css', POLYLANG_ROOT_FILE ), array(), POLYLANG_VERSION );
299 + wp_enqueue_style( 'pll-wizard', plugins_url( '/css/build/wizard' . $this->get_suffix() . '.css', POLYLANG_ROOT_FILE ), array( 'dashicons', 'install', 'common', 'forms' ), POLYLANG_VERSION );
265 300
266 301 $this->styles = array( 'polylang_admin', 'pll-wizard' );
267 302 }
268 303
@@ -268,11 +303,12 @@
268 303
269 304 /**
270 305 * Get the suffix to enqueue non minified files in a Debug context
271 306 *
307 + * @since 2.7
308 + *
272 309 * @return string Empty when SCRIPT_DEBUG equal to true
273 310 * otherwise .min
274 - * @since 2.7
275 311 */
276 312 public function get_suffix() {
277 313 return defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
278 314 }
@@ -279,16 +315,17 @@
279 315
280 316 /**
281 317 * Get the URL for the step's screen.
282 318 *
319 + * @since 2.7
320 + *
283 321 * @param string $step slug (default: current step).
284 322 * @return string URL for the step if it exists.
285 323 * Empty string on failure.
286 - * @since 2.7
287 324 */
288 325 public function get_step_link( $step = '' ) {
289 326 if ( ! $step ) {
290 - $step = $this->step;
327 + $step = $this->current_step;
291 328 }
292 329
293 330 $keys = array_keys( $this->steps );
294 331
@@ -302,17 +339,18 @@
302 339
303 340 /**
304 341 * Get the URL for the next step's screen.
305 342 *
343 + * @since 2.7
344 + *
306 345 * @param string $step slug (default: current step).
307 346 * @return string URL for next step if a next step exists.
308 347 * Admin URL if it's the last step.
309 348 * Empty string on failure.
310 - * @since 2.7
311 349 */
312 350 public function get_next_step_link( $step = '' ) {
313 351 if ( ! $step ) {
314 - $step = $this->step;
352 + $step = $this->current_step;
315 353 }
316 354
317 355 $keys = array_keys( $this->steps );
318 356 if ( end( $keys ) === $step ) {
@@ -329,24 +367,28 @@
329 367
330 368 /**
331 369 * Add licenses step to the wizard
332 370 *
371 + * @since 2.7
372 + *
333 373 * @param array $steps List of steps.
334 374 * @return array List of steps updated.
335 - * @since 2.7
336 375 */
337 376 public function add_step_licenses( $steps ) {
338 377 // Add ajax action on deactivate button in licenses step.
339 378 add_action( 'wp_ajax_pll_deactivate_license', array( $this, 'deactivate_license' ) );
340 379
341 - wp_enqueue_script( 'pll_admin', plugins_url( '/js/admin' . $this->get_suffix() . '.js', POLYLANG_FILE ), array( 'jquery', 'jquery-ui-selectmenu' ), POLYLANG_VERSION, true );
342 - wp_localize_script( 'pll_admin', 'pll_dismiss_notice', esc_html__( 'Dismiss this notice.', 'polylang' ) );
380 + // Be careful `settings` script is enqueued here without dependency except jquery because only code useful for deactivate license button is needed.
381 + // To be really loaded the script needs to be passed to the `$steps['licenses']['scripts']` array below with the same handle than in `wp_enqueue_script()`.
382 + wp_enqueue_script( 'pll_settings', plugins_url( '/js/build/settings' . $this->get_suffix() . '.js', POLYLANG_ROOT_FILE ), array( 'jquery' ), POLYLANG_VERSION, true );
383 + wp_localize_script( 'pll_settings', 'pll_settings', array( 'dismiss_notice' => esc_html__( 'Dismiss this notice.', 'polylang' ) ) );
384 +
343 385 if ( $this->is_licenses_step_displayable() ) {
344 386 $steps['licenses'] = array(
345 387 'name' => esc_html__( 'Licenses', 'polylang' ),
346 388 'view' => array( $this, 'display_step_licenses' ),
347 389 'handler' => array( $this, 'save_step_licenses' ),
348 - 'scripts' => array( 'pll_admin' ), // Polylang admin script used by deactivate license button.
390 + 'scripts' => array( 'pll_settings' ), // Polylang admin script used by deactivate license button.
349 391 'styles' => array(),
350 392 );
351 393 }
352 394 return $steps;
@@ -355,8 +397,10 @@
355 397 /**
356 398 * Display the languages step form
357 399 *
358 400 * @since 2.7
401 + *
402 + * @return void
359 403 */
360 404 public function display_step_licenses() {
361 405 include __DIR__ . '/view-wizard-step-licenses.php';
362 406 }
@@ -364,8 +408,10 @@
364 408 /**
365 409 * Execute the languages step
366 410 *
367 411 * @since 2.7
412 + *
413 + * @return void
368 414 */
369 415 public function save_step_licenses() {
370 416 check_admin_referer( 'pll-wizard', '_pll_nonce' );
371 417
@@ -378,9 +424,9 @@
378 424 if ( ! empty( $updated_license->license_data ) && false === $updated_license->license_data->success ) {
379 425 // Stay on this step with an error.
380 426 $redirect = add_query_arg(
381 427 array(
382 - 'step' => $this->step,
428 + 'step' => $this->current_step,
383 429 'activate_error' => 'i18n_license_key_error',
384 430 )
385 431 );
386 432 }
@@ -386,9 +432,9 @@
386 432 }
387 433 }
388 434 }
389 435
390 - wp_safe_redirect( esc_url_raw( $redirect ) );
436 + wp_safe_redirect( sanitize_url( $redirect ) );
391 437 exit;
392 438 }
393 439
394 440 /**
@@ -394,8 +440,10 @@
394 440 /**
395 441 * Ajax method to deactivate a license
396 442 *
397 443 * @since 2.7
444 + *
445 + * @return void
398 446 */
399 447 public function deactivate_license() {
400 448 check_ajax_referer( 'pll-wizard', '_pll_nonce' );
401 449
@@ -422,16 +470,20 @@
422 470
423 471 /**
424 472 * Add languages step to the wizard
425 473 *
474 + * @since 2.7
475 + *
426 476 * @param array $steps List of steps.
427 477 * @return array List of steps updated.
428 - * @since 2.7
429 478 */
430 479 public function add_step_languages( $steps ) {
431 - wp_enqueue_script( 'pll-wizard-language-choice', plugins_url( '/js/admin' . $this->get_suffix() . '.js', POLYLANG_FILE ), array( 'jquery', 'jquery-ui-selectmenu' ), POLYLANG_VERSION, true );
432 - wp_localize_script( 'pll-wizard-language-choice', 'pll_dismiss_notice', esc_html__( 'Dismiss this notice.', 'polylang' ) );
433 - wp_register_script( 'pll-wizard-languages', plugins_url( '/modules/wizard/js/languages-step' . $this->get_suffix() . '.js', POLYLANG_FILE ), array( 'jquery', 'jquery-ui-dialog' ), POLYLANG_VERSION, true );
480 + wp_deregister_script( 'pll_settings' ); // Deregister after the licenses step enqueue to update jquery-ui-selectmenu dependency.
481 + // The wp-ajax-response and postbox dependencies is useless in wizard steps especially postbox which triggers a javascript error otherwise.
482 + // To be really loaded the script needs to be passed to the `$steps['languages']['scripts']` array below with the same handle than in `wp_enqueue_script()`.
483 + wp_enqueue_script( 'pll_settings', plugins_url( '/js/build/settings' . $this->get_suffix() . '.js', POLYLANG_ROOT_FILE ), array( 'jquery', 'jquery-ui-selectmenu' ), POLYLANG_VERSION, true );
484 + wp_localize_script( 'pll_settings', 'pll_settings', array( 'dismiss_notice' => esc_html__( 'Dismiss this notice.', 'polylang' ) ) );
485 + wp_register_script( 'pll-wizard-languages', plugins_url( '/js/build/languages-step' . $this->get_suffix() . '.js', POLYLANG_ROOT_FILE ), array( 'jquery', 'jquery-ui-dialog' ), POLYLANG_VERSION, true );
434 486 wp_localize_script(
435 487 'pll-wizard-languages',
436 488 'pll_wizard_params',
437 489 array(
@@ -452,14 +504,14 @@
452 504 'i18n_remove_language_icon' => esc_html__( 'Remove this language', 'polylang' ),
453 505 )
454 506 );
455 507 wp_enqueue_script( 'pll-wizard-languages' );
456 - wp_enqueue_style( 'pll-wizard-selectmenu', plugins_url( '/css/selectmenu' . $this->get_suffix() . '.css', POLYLANG_FILE ), array( 'dashicons', 'install', 'common', 'wp-jquery-ui-dialog' ), POLYLANG_VERSION );
508 + wp_enqueue_style( 'pll-wizard-selectmenu', plugins_url( '/css/build/selectmenu' . $this->get_suffix() . '.css', POLYLANG_ROOT_FILE ), array( 'dashicons', 'install', 'common', 'wp-jquery-ui-dialog' ), POLYLANG_VERSION );
457 509 $steps['languages'] = array(
458 510 'name' => esc_html__( 'Languages', 'polylang' ),
459 511 'view' => array( $this, 'display_step_languages' ),
460 512 'handler' => array( $this, 'save_step_languages' ),
461 - 'scripts' => array( 'pll-wizard-languages', 'pll-wizard-language-choice' ),
513 + 'scripts' => array( 'pll-wizard-languages', 'pll_settings' ),
462 514 'styles' => array( 'pll-wizard-selectmenu' ),
463 515 );
464 516 return $steps;
465 517 }
@@ -467,10 +519,13 @@
467 519 /**
468 520 * Display the languages step form
469 521 *
470 522 * @since 2.7
523 + *
524 + * @return void
471 525 */
472 526 public function display_step_languages() {
527 + $model = $this->model;
473 528 include __DIR__ . '/view-wizard-step-languages.php';
474 529 }
475 530
476 531 /**
@@ -476,26 +531,26 @@
476 531 /**
477 532 * Execute the languages step
478 533 *
479 534 * @since 2.7
535 + *
536 + * @return void
480 537 */
481 538 public function save_step_languages() {
482 539 check_admin_referer( 'pll-wizard', '_pll_nonce' );
483 540
484 - $existing_languages = $this->model->get_languages_list();
485 -
486 - $all_languages = include POLYLANG_DIR . '/settings/languages.php';
487 - $languages = isset( $_POST['languages'] ) ? array_map( 'sanitize_text_field', wp_unslash( $_POST['languages'] ) ) : false;
541 + $all_languages = include POLYLANG_DIR . '/settings/languages.php';
542 + $languages = isset( $_POST['languages'] ) && is_array( $_POST['languages'] ) ? array_map( 'sanitize_locale_name', $_POST['languages'] ) : false;
488 543 $saved_languages = array();
489 544
490 545 // If there is no language added or defined.
491 - if ( empty( $languages ) && empty( $existing_languages ) ) {
546 + if ( empty( $languages ) && ! $this->model->has_languages() ) {
492 547 // Stay on this step with an error.
493 548 wp_safe_redirect(
494 - esc_url_raw(
549 + sanitize_url(
495 550 add_query_arg(
496 551 array(
497 - 'step' => $this->step,
552 + 'step' => $this->current_step,
498 553 'activate_error' => 'i18n_no_language_added',
499 554 )
500 555 )
501 556 )
@@ -527,12 +582,12 @@
527 582 if ( $language_added instanceof WP_Error ) {
528 583 // Stay on this step with an error.
529 584 $error_keys = array_keys( $language_added->errors );
530 585 wp_safe_redirect(
531 - esc_url_raw(
586 + sanitize_url(
532 587 add_query_arg(
533 588 array(
534 - 'step' => $this->step,
589 + 'step' => $this->current_step,
535 590 'activate_error' => 'i18n_' . reset( $error_keys ),
536 591 )
537 592 )
538 593 )
@@ -544,19 +599,19 @@
544 599 wp_download_language_pack( $locale );
545 600 }
546 601 }
547 602 }
548 - wp_safe_redirect( esc_url_raw( $this->get_next_step_link() ) );
603 + wp_safe_redirect( sanitize_url( $this->get_next_step_link() ) );
549 604 exit;
550 605 }
551 606
552 607 /**
553 - * Add media step to the wizard
554 - * Add media step to the wizard
608 + * Add the media step to the wizard.
555 609 *
610 + * @since 2.7
611 + *
556 612 * @param array $steps List of steps.
557 613 * @return array List of steps updated.
558 - * @since 2.7
559 614 */
560 615 public function add_step_media( $steps ) {
561 616 $languages = $this->model->get_languages_list();
562 617
@@ -575,10 +630,13 @@
575 630 /**
576 631 * Display the media step form
577 632 *
578 633 * @since 2.7
634 + *
635 + * @return void
579 636 */
580 637 public function display_step_media() {
638 + $options = $this->options;
581 639 include __DIR__ . '/view-wizard-step-media.php';
582 640 }
583 641
584 642 /**
@@ -584,8 +642,10 @@
584 642 /**
585 643 * Execute the media step
586 644 *
587 645 * @since 2.7
646 + *
647 + * @return void
588 648 */
589 649 public function save_step_media() {
590 650 check_admin_referer( 'pll-wizard', '_pll_nonce' );
591 651
@@ -594,9 +654,9 @@
594 654 $this->options['media_support'] = $media_support;
595 655
596 656 update_option( 'polylang', $this->options );
597 657
598 - wp_safe_redirect( esc_url_raw( $this->get_next_step_link() ) );
658 + wp_safe_redirect( sanitize_url( $this->get_next_step_link() ) );
599 659 exit;
600 660 }
601 661
602 662 /**
@@ -601,22 +661,25 @@
601 661
602 662 /**
603 663 * Add untranslated contents step to the wizard
604 664 *
665 + * @since 2.7
666 + *
605 667 * @param array $steps List of steps.
606 668 * @return array List of steps updated.
607 - * @since 2.7
608 669 */
609 670 public function add_step_untranslated_contents( $steps ) {
610 - if ( ! $this->model->get_languages_list() || $this->model->get_objects_with_no_lang( 1 ) ) {
611 - wp_enqueue_script( 'pll-wizard-language-choice', plugins_url( '/js/admin' . $this->get_suffix() . '.js', POLYLANG_FILE ), array( 'jquery', 'jquery-ui-selectmenu' ), POLYLANG_VERSION, true );
612 - wp_localize_script( 'pll-wizard-language-choice', 'pll_dismiss_notice', esc_html__( 'Dismiss this notice.', 'polylang' ) );
613 - wp_enqueue_style( 'pll-wizard-selectmenu', plugins_url( '/css/selectmenu' . $this->get_suffix() . '.css', POLYLANG_FILE ), array( 'dashicons', 'install', 'common' ), POLYLANG_VERSION );
671 + if ( ! $this->model->has_languages() || $this->model->get_objects_with_no_lang( 1 ) ) {
672 + // Even if `pll_settings` is already enqueued with the same dependencies by the languages step, it is interesting to keep that it's also useful for the untranslated-contents step.
673 + // To be really loaded the script needs to be passed to the `$steps['untranslated-contents']['scripts']` array below with the same handle than in `wp_enqueue_script()`.
674 + wp_enqueue_script( 'pll_settings', plugins_url( '/js/build/settings' . $this->get_suffix() . '.js', POLYLANG_ROOT_FILE ), array( 'jquery', 'jquery-ui-selectmenu' ), POLYLANG_VERSION, true );
675 + wp_localize_script( 'pll_settings', 'pll_settings', array( 'dismiss_notice' => esc_html__( 'Dismiss this notice.', 'polylang' ) ) );
676 + wp_enqueue_style( 'pll-wizard-selectmenu', plugins_url( '/css/build/selectmenu' . $this->get_suffix() . '.css', POLYLANG_ROOT_FILE ), array( 'dashicons', 'install', 'common' ), POLYLANG_VERSION );
614 677 $steps['untranslated-contents'] = array(
615 678 'name' => esc_html__( 'Content', 'polylang' ),
616 679 'view' => array( $this, 'display_step_untranslated_contents' ),
617 680 'handler' => array( $this, 'save_step_untranslated_contents' ),
618 - 'scripts' => array( 'pll-wizard-language-choice' ),
681 + 'scripts' => array( 'pll_settings' ),
619 682 'styles' => array( 'pll-wizard-selectmenu' ),
620 683 );
621 684 }
622 685 return $steps;
@@ -625,10 +688,13 @@
625 688 /**
626 689 * Display the untranslated contents step form
627 690 *
628 691 * @since 2.7
692 + *
693 + * @return void
629 694 */
630 695 public function display_step_untranslated_contents() {
696 + $model = $this->model;
631 697 include __DIR__ . '/view-wizard-step-untranslated-contents.php';
632 698 }
633 699
634 700 /**
@@ -634,13 +700,15 @@
634 700 /**
635 701 * Execute the untranslated contents step
636 702 *
637 703 * @since 2.7
704 + *
705 + * @return void
638 706 */
639 707 public function save_step_untranslated_contents() {
640 708 check_admin_referer( 'pll-wizard', '_pll_nonce' );
641 709
642 - $lang = isset( $_POST['language'] ) ? sanitize_text_field( wp_unslash( $_POST['language'] ) ) : false;
710 + $lang = ! empty( $_POST['language'] ) && is_string( $_POST['language'] ) ? sanitize_locale_name( $_POST['language'] ) : false;
643 711
644 712 if ( empty( $lang ) ) {
645 713 $lang = $this->options['default_lang'];
646 714 }
@@ -646,18 +714,13 @@
646 714 }
647 715
648 716 $language = $this->model->get_language( $lang );
649 717
650 - while ( $nolang = $this->model->get_objects_with_no_lang( 1000 ) ) {
651 - if ( ! empty( $nolang['posts'] ) ) {
652 - $this->model->set_language_in_mass( 'post', $nolang['posts'], $language->slug );
653 - }
654 - if ( ! empty( $nolang['terms'] ) ) {
655 - $this->model->set_language_in_mass( 'term', $nolang['terms'], $language->slug );
656 - }
718 + if ( $language instanceof PLL_Language ) {
719 + $this->model->set_language_in_mass( $language );
657 720 }
658 721
659 - wp_safe_redirect( esc_url_raw( $this->get_next_step_link() ) );
722 + wp_safe_redirect( sanitize_url( $this->get_next_step_link() ) );
660 723 exit;
661 724 }
662 725
663 726 /**
@@ -662,11 +725,12 @@
662 725
663 726 /**
664 727 * Add home page step to the wizard
665 728 *
729 + * @since 2.7
730 + *
666 731 * @param array $steps List of steps.
667 732 * @return array List of steps updated.
668 - * @since 2.7
669 733 */
670 734 public function add_step_home_page( $steps ) {
671 735 $languages = $this->model->get_languages_list();
672 736 $home_page_id = get_option( 'page_on_front' );
@@ -688,10 +752,30 @@
688 752 /**
689 753 * Display the home page step form
690 754 *
691 755 * @since 2.7
756 + *
757 + * @return void
692 758 */
693 759 public function display_step_home_page() {
760 + $model = $this->model;
761 + $languages = $model->languages->get_list();
762 + $home_page_id = get_option( 'page_on_front' );
763 + $home_page_id = is_numeric( $home_page_id ) ? (int) $home_page_id : 0;
764 + $translations = $model->post->get_translations( $home_page_id );
765 + $home_page = $home_page_id > 0 ? get_post( $home_page_id ) : null;
766 + $home_page_language = $model->post->get_language( $home_page_id );
767 + $untranslated_languages = array();
768 +
769 + if ( empty( $home_page ) ) {
770 + return;
771 + }
772 +
773 + foreach ( $languages as $language ) {
774 + if ( ! $model->post->get( $home_page_id, $language ) ) {
775 + $untranslated_languages[] = $language;
776 + }
777 + }
694 778 include __DIR__ . '/view-wizard-step-home-page.php';
695 779 }
696 780
697 781 /**
@@ -697,15 +781,15 @@
697 781 /**
698 782 * Execute the home page step
699 783 *
700 784 * @since 2.7
785 + *
786 + * @return void
701 787 */
702 788 public function save_step_home_page() {
703 789 check_admin_referer( 'pll-wizard', '_pll_nonce' );
704 790
705 - $languages = $this->model->get_languages_list();
706 -
707 - $default_language = count( $languages ) > 0 ? $this->options['default_lang'] : null;
791 + $default_language = $this->model->has_languages() ? $this->options['default_lang'] : null;
708 792 $home_page = isset( $_POST['home_page'] ) ? sanitize_key( $_POST['home_page'] ) : false;
709 793 $home_page_title = isset( $_POST['home_page_title'] ) ? sanitize_text_field( wp_unslash( $_POST['home_page_title'] ) ) : esc_html__( 'Homepage', 'polylang' );
710 794 $home_page_language = isset( $_POST['home_page_language'] ) ? sanitize_key( $_POST['home_page_language'] ) : false;
711 795
@@ -721,9 +805,9 @@
721 805 );
722 806
723 807 $this->model->clean_languages_cache();
724 808
725 - wp_safe_redirect( esc_url_raw( $this->get_next_step_link() ) );
809 + wp_safe_redirect( sanitize_url( $this->get_next_step_link() ) );
726 810 exit;
727 811 }
728 812
729 813 /**
@@ -730,13 +814,14 @@
730 814 * Create home page translations for each language defined.
731 815 *
732 816 * @since 2.7
733 817 *
734 - * @param string $default_language slug of the default language; null if no default language is defined.
735 - * @param int $home_page post_id of the home page if it's defined, false otherwise.
736 - * @param string $home_page_title home page title if it's defined, 'Homepage' otherwise.
737 - * @param string $home_page_language slug of the home page if it's defined, false otherwise.
738 - * @param array $untranslated_languages array of languages which needs to have a home page translated.
818 + * @param string $default_language Slug of the default language; null if no default language is defined.
819 + * @param int $home_page Post ID of the home page if it's defined, false otherwise.
820 + * @param string $home_page_title Home page title if it's defined, 'Homepage' otherwise.
821 + * @param string $home_page_language Slug of the home page if it's defined, false otherwise.
822 + * @param string[] $untranslated_languages Array of languages which needs to have a home page translated.
823 + * @return void
739 824 */
740 825 public function create_home_page_translations( $default_language, $home_page, $home_page_title, $home_page_language, $untranslated_languages ) {
741 826 $translations = $this->model->post->get_translations( $home_page );
742 827
@@ -757,11 +842,12 @@
757 842
758 843 /**
759 844 * Add last step to the wizard
760 845 *
846 + * @since 2.7
847 + *
761 848 * @param array $steps List of steps.
762 849 * @return array List of steps updated.
763 - * @since 2.7
764 850 */
765 851 public function add_step_last( $steps ) {
766 852 $steps['last'] = array(
767 853 'name' => esc_html__( 'Ready!', 'polylang' ),
@@ -776,8 +862,10 @@
776 862 /**
777 863 * Display the last step form
778 864 *
779 865 * @since 2.7
866 + *
867 + * @return void
780 868 */
781 869 public function display_step_last() {
782 870 // We ran the wizard once. So we can dismiss its notice.
783 871 PLL_Admin_Notices::dismiss( 'wizard' );
@@ -787,12 +875,14 @@
787 875 /**
788 876 * Execute the last step
789 877 *
790 878 * @since 2.7
879 + *
880 + * @return void
791 881 */
792 882 public function save_step_last() {
793 883 check_admin_referer( 'pll-wizard', '_pll_nonce' );
794 884
795 - wp_safe_redirect( esc_url_raw( $this->get_next_step_link() ) );
885 + wp_safe_redirect( sanitize_url( $this->get_next_step_link() ) );
796 886 exit;
797 887 }
798 888 }