PluginProbe
Polylang / 2.8.2
Polylang v2.8.2
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 / modules / wizard / wizard.php

wizard.php in Polylang 2.8.2, at modules/wizard/wizard.php

798 lines 24.5 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 /**
7 * Main class for Polylang wizard.
8 *
9 * @since 2.7
10 */
11 class PLL_Wizard {
12 /**
13 * Reference to PLL_Model object
14 *
15 * @var object $model
16 */
17 protected $model;
18
19 /**
20 * Reference to Polylang options array
21 *
22 * @var array $options
23 */
24 protected $options;
25
26 /**
27 * List of steps
28 *
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.
35 * }
36 */
37 protected $steps = array();
38
39 /**
40 * List of WordPress CSS file handles
41 *
42 * @var array $styles
43 */
44 protected $styles = array();
45
46 /**
47 * Constructor
48 *
49 * @param object $polylang Reference to Polylang global object.
50 * @since 2.7
51 */
52 public function __construct( &$polylang ) {
53 $this->options = &$polylang->options;
54 $this->model = &$polylang->model;
55
56 // 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.
58 add_action( 'admin_init', array( $this, 'setup_wizard_page' ), 40 );
59 // Add Wizard submenu.
60 add_filter( 'pll_settings_tabs', array( $this, 'settings_tabs' ), 10, 1 );
61 // Add filter to select screens where to display the notice.
62 add_filter( 'pll_can_display_notice', array( $this, 'can_display_notice' ), 10, 2 );
63
64 // Default steps.
65 add_filter( 'pll_wizard_steps', array( $this, 'add_step_licenses' ), 100 );
66 add_filter( 'pll_wizard_steps', array( $this, 'add_step_languages' ), 200 );
67 add_filter( 'pll_wizard_steps', array( $this, 'add_step_media' ), 300 );
68 add_filter( 'pll_wizard_steps', array( $this, 'add_step_untranslated_contents' ), 400 );
69 add_filter( 'pll_wizard_steps', array( $this, 'add_step_home_page' ), 500 );
70 add_filter( 'pll_wizard_steps', array( $this, 'add_step_last' ), 999 );
71 }
72
73 /**
74 * Save an activation transient when Polylang is activating to redirect to the wizard
75 *
76 * @param bool $network_wide if activated for all sites in the network.
77 * @since 2.7
78 */
79 public static function start_wizard( $network_wide ) {
80 $options = get_option( 'polylang' );
81
82 if ( wp_doing_ajax() || $network_wide || ! empty( $options ) ) {
83 return;
84 }
85 set_transient( 'pll_activation_redirect', 1, 30 );
86 }
87
88 /**
89 * Redirect to the wizard depending on the context
90 *
91 * @since 2.7
92 */
93 public function redirect_to_wizard() {
94 if ( get_transient( 'pll_activation_redirect' ) ) {
95 $do_redirect = true;
96 if ( ( isset( $_GET['page'] ) && 'mlang_wizard' === sanitize_key( $_GET['page'] ) || isset( $_GET['activate-multi'] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
97 delete_transient( 'pll_activation_redirect' );
98 $do_redirect = false;
99 }
100
101 if ( $do_redirect ) {
102 wp_safe_redirect(
103 esc_url_raw(
104 add_query_arg(
105 array(
106 'page' => 'mlang_wizard',
107 ),
108 admin_url( 'admin.php' )
109 )
110 )
111 );
112 exit;
113 }
114 }
115 }
116
117 /**
118 * Add an admin Polylang submenu to access the wizard
119 *
120 * @param array $tabs Submenus list.
121 * @return array Submenus list updated.
122 * @since 2.7
123 */
124 public function settings_tabs( $tabs ) {
125 $tabs['wizard'] = esc_html__( 'Setup', 'polylang' );
126 return $tabs;
127 }
128
129 /**
130 * Return if the media step is displayable
131 *
132 * @param array $languages List of language objects.
133 * @return bool
134 * @since 2.7
135 */
136 public function is_media_step_displayable( $languages ) {
137 $media = array();
138 // If there is no language or only one the media step is displayable.
139 if ( ! $languages || count( $languages ) < 2 ) {
140 return true;
141 }
142 foreach ( $languages as $language ) {
143 $media[ $language->slug ] = $this->model->count_posts(
144 $language,
145 array(
146 'post_type' => array( 'attachment' ),
147 'post_status' => 'inherit',
148 )
149 );
150 }
151 return count( array_filter( $media ) ) === 0;
152 }
153
154 /**
155 * Check if the licenses step is displayable
156 *
157 * @return bool
158 * @since 2.7
159 */
160 public function is_licenses_step_displayable() {
161 $licenses = apply_filters( 'pll_settings_licenses', array() );
162 return count( $licenses ) > 0;
163 }
164
165 /**
166 * Setup the wizard page
167 *
168 * @since 2.7
169 */
170 public function setup_wizard_page() {
171
172 PLL_Admin_Notices::add_notice( 'wizard', $this->wizard_notice() );
173
174 $this->redirect_to_wizard();
175 if ( ! Polylang::is_wizard() ) {
176 return;
177 }
178 if ( ! current_user_can( 'manage_options' ) ) {
179 wp_die( esc_html__( 'Sorry, you are not allowed to manage options for this site.', 'polylang' ) );
180 }
181
182 // Enqueue scripts and styles especially for the wizard.
183 add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
184
185 $this->steps = apply_filters( 'pll_wizard_steps', $this->steps );
186 $step = isset( $_GET['step'] ) ? sanitize_key( $_GET['step'] ) : false; // phpcs:ignore WordPress.Security.NonceVerification
187
188 $this->step = $step && array_key_exists( $step, $this->steps ) ? $step : current( array_keys( $this->steps ) );
189
190 $languages = $this->model->get_languages_list();
191
192 if ( count( $languages ) === 0 && ! in_array( $this->step, array( 'licenses', 'languages' ) ) ) {
193 wp_safe_redirect( esc_url_raw( $this->get_step_link( 'languages' ) ) );
194 exit;
195 }
196
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' ) ) );
199 exit;
200 }
201
202 // Call the handler of the step for going to the next step.
203 // 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'] );
206 }
207
208 $this->display_wizard_page();
209 // Ensure nothing is done after including the page.
210 exit;
211 }
212
213 /**
214 * Adds some admin screens where to display the wizard notice
215 *
216 * @param bool $can_display_notice Whether the notice can be displayed.
217 * @param string $notice The notice name.
218 * @return bool
219 * @since 2.7
220 */
221 public function can_display_notice( $can_display_notice, $notice ) {
222 if ( ! $can_display_notice && 'wizard' === $notice ) {
223 $screen = get_current_screen();
224 $can_display_notice = in_array(
225 $screen->base,
226 array(
227 'edit',
228 'upload',
229 'options-general',
230 )
231 );
232 }
233 return $can_display_notice;
234 }
235
236 /**
237 * Return html code of the wizard notice
238 *
239 * @since 2.7
240 */
241 public function wizard_notice() {
242 ob_start();
243 include __DIR__ . '/html-wizard-notice.php';
244 return ob_get_clean();
245 }
246
247 /**
248 * Display the wizard page
249 *
250 * @since 2.7
251 */
252 public function display_wizard_page() {
253 set_current_screen();
254 include __DIR__ . '/view-wizard-page.php';
255 }
256
257 /**
258 * Enqueue scripts and styles for the wizard
259 *
260 * @since 2.7
261 */
262 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 );
265
266 $this->styles = array( 'polylang_admin', 'pll-wizard' );
267 }
268
269 /**
270 * Get the suffix to enqueue non minified files in a Debug context
271 *
272 * @return string Empty when SCRIPT_DEBUG equal to true
273 * otherwise .min
274 * @since 2.7
275 */
276 public function get_suffix() {
277 return defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
278 }
279
280 /**
281 * Get the URL for the step's screen.
282 *
283 * @param string $step slug (default: current step).
284 * @return string URL for the step if it exists.
285 * Empty string on failure.
286 * @since 2.7
287 */
288 public function get_step_link( $step = '' ) {
289 if ( ! $step ) {
290 $step = $this->step;
291 }
292
293 $keys = array_keys( $this->steps );
294
295 $step_index = array_search( $step, $keys, true );
296 if ( false === $step_index ) {
297 return '';
298 }
299
300 return add_query_arg( 'step', $keys[ $step_index ], remove_query_arg( 'activate_error' ) );
301 }
302
303 /**
304 * Get the URL for the next step's screen.
305 *
306 * @param string $step slug (default: current step).
307 * @return string URL for next step if a next step exists.
308 * Admin URL if it's the last step.
309 * Empty string on failure.
310 * @since 2.7
311 */
312 public function get_next_step_link( $step = '' ) {
313 if ( ! $step ) {
314 $step = $this->step;
315 }
316
317 $keys = array_keys( $this->steps );
318 if ( end( $keys ) === $step ) {
319 return admin_url();
320 }
321
322 $step_index = array_search( $step, $keys, true );
323 if ( false === $step_index ) {
324 return '';
325 }
326
327 return add_query_arg( 'step', $keys[ $step_index + 1 ], remove_query_arg( 'activate_error' ) );
328 }
329
330 /**
331 * Add licenses step to the wizard
332 *
333 * @param array $steps List of steps.
334 * @return array List of steps updated.
335 * @since 2.7
336 */
337 public function add_step_licenses( $steps ) {
338 // Add ajax action on deactivate button in licenses step.
339 add_action( 'wp_ajax_pll_deactivate_license', array( $this, 'deactivate_license' ) );
340
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' ) );
343 if ( $this->is_licenses_step_displayable() ) {
344 $steps['licenses'] = array(
345 'name' => esc_html__( 'Licenses', 'polylang' ),
346 'view' => array( $this, 'display_step_licenses' ),
347 'handler' => array( $this, 'save_step_licenses' ),
348 'scripts' => array( 'pll_admin' ), // Polylang admin script used by deactivate license button.
349 'styles' => array(),
350 );
351 }
352 return $steps;
353 }
354
355 /**
356 * Display the languages step form
357 *
358 * @since 2.7
359 */
360 public function display_step_licenses() {
361 include __DIR__ . '/view-wizard-step-licenses.php';
362 }
363
364 /**
365 * Execute the languages step
366 *
367 * @since 2.7
368 */
369 public function save_step_licenses() {
370 check_admin_referer( 'pll-wizard', '_pll_nonce' );
371
372 $redirect = $this->get_next_step_link();
373 $licenses = apply_filters( 'pll_settings_licenses', array() );
374
375 foreach ( $licenses as $license ) {
376 if ( ! empty( $_POST['licenses'][ $license->id ] ) ) {
377 $updated_license = $license->activate_license( sanitize_key( $_POST['licenses'][ $license->id ] ) );
378 if ( ! empty( $updated_license->license_data ) && false === $updated_license->license_data->success ) {
379 // Stay on this step with an error.
380 $redirect = add_query_arg(
381 array(
382 'step' => $this->step,
383 'activate_error' => 'i18n_license_key_error',
384 )
385 );
386 }
387 }
388 }
389
390 wp_safe_redirect( esc_url_raw( $redirect ) );
391 exit;
392 }
393
394 /**
395 * Ajax method to deactivate a license
396 *
397 * @since 2.7
398 */
399 public function deactivate_license() {
400 check_ajax_referer( 'pll-wizard', '_pll_nonce' );
401
402 if ( ! current_user_can( 'manage_options' ) ) {
403 wp_die( -1 );
404 }
405
406 if ( ! isset( $_POST['id'] ) ) {
407 wp_die( 0 );
408 }
409
410 $id = substr( sanitize_text_field( wp_unslash( $_POST['id'] ) ), 11 );
411 $licenses = apply_filters( 'pll_settings_licenses', array() );
412 $license = $licenses[ $id ];
413 $license->deactivate_license();
414
415 wp_send_json(
416 array(
417 'id' => $id,
418 'html' => $license->get_form_field(),
419 )
420 );
421 }
422
423 /**
424 * Add languages step to the wizard
425 *
426 * @param array $steps List of steps.
427 * @return array List of steps updated.
428 * @since 2.7
429 */
430 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 );
434 wp_localize_script(
435 'pll-wizard-languages',
436 'pll_wizard_params',
437 array(
438 'i18n_no_language_selected' => esc_html__( 'You need to select a language to be added.', 'polylang' ),
439 'i18n_language_already_added' => esc_html__( 'You already added this language.', 'polylang' ),
440 'i18n_no_language_added' => esc_html__( 'You need to add at least one language.', 'polylang' ),
441 'i18n_add_language_needed' => esc_html__( 'You selected a language, however, to be able to continue, you need to add it.', 'polylang' ),
442 'i18n_pll_add_language' => esc_html__( 'Impossible to add the language.', 'polylang' ),
443 'i18n_pll_invalid_locale' => esc_html__( 'Enter a valid WordPress locale', 'polylang' ),
444 'i18n_pll_invalid_slug' => esc_html__( 'The language code contains invalid characters', 'polylang' ),
445 'i18n_pll_non_unique_slug' => esc_html__( 'The language code must be unique', 'polylang' ),
446 'i18n_pll_invalid_name' => esc_html__( 'The language must have a name', 'polylang' ),
447 'i18n_pll_invalid_flag' => esc_html__( 'The flag does not exist', 'polylang' ),
448 'i18n_dialog_title' => esc_html__( "A language wasn't added.", 'polylang' ),
449 'i18n_dialog_yes_button' => esc_html__( 'Yes', 'polylang' ),
450 'i18n_dialog_no_button' => esc_html__( 'No', 'polylang' ),
451 'i18n_dialog_ignore_button' => esc_html__( 'Ignore', 'polylang' ),
452 'i18n_remove_language_icon' => esc_html__( 'Remove this language', 'polylang' ),
453 )
454 );
455 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 );
457 $steps['languages'] = array(
458 'name' => esc_html__( 'Languages', 'polylang' ),
459 'view' => array( $this, 'display_step_languages' ),
460 'handler' => array( $this, 'save_step_languages' ),
461 'scripts' => array( 'pll-wizard-languages', 'pll-wizard-language-choice' ),
462 'styles' => array( 'pll-wizard-selectmenu' ),
463 );
464 return $steps;
465 }
466
467 /**
468 * Display the languages step form
469 *
470 * @since 2.7
471 */
472 public function display_step_languages() {
473 include __DIR__ . '/view-wizard-step-languages.php';
474 }
475
476 /**
477 * Execute the languages step
478 *
479 * @since 2.7
480 */
481 public function save_step_languages() {
482 check_admin_referer( 'pll-wizard', '_pll_nonce' );
483
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;
488 $saved_languages = array();
489
490 // If there is no language added or defined.
491 if ( empty( $languages ) && empty( $existing_languages ) ) {
492 // Stay on this step with an error.
493 wp_safe_redirect(
494 esc_url_raw(
495 add_query_arg(
496 array(
497 'step' => $this->step,
498 'activate_error' => 'i18n_no_language_added',
499 )
500 )
501 )
502 );
503 exit;
504 }
505
506 // Otherwise process the languages to add or skip the step if no language has been added.
507 if ( ! empty( $languages ) ) {
508 require_once ABSPATH . 'wp-admin/includes/translation-install.php';
509 // Remove duplicate values.
510 $languages = array_unique( $languages );
511 // For each language add it in Polylang settings.
512 foreach ( $languages as $locale ) {
513 $saved_languages = $all_languages[ $locale ];
514
515 $saved_languages['slug'] = $saved_languages['code'];
516 $saved_languages['rtl'] = (int) ( 'rtl' === $saved_languages['dir'] );
517 $saved_languages['term_group'] = 0; // Default term_group.
518
519 $language_added = $this->model->add_language( $saved_languages );
520
521 if ( $language_added instanceof WP_Error && array_key_exists( 'pll_non_unique_slug', $language_added->errors ) ) {
522 // Get the slug from the locale : lowercase and dash instead of underscore.
523 $saved_languages['slug'] = strtolower( str_replace( '_', '-', $saved_languages['locale'] ) );
524 $language_added = $this->model->add_language( $saved_languages );
525 }
526
527 if ( $language_added instanceof WP_Error ) {
528 // Stay on this step with an error.
529 $error_keys = array_keys( $language_added->errors );
530 wp_safe_redirect(
531 esc_url_raw(
532 add_query_arg(
533 array(
534 'step' => $this->step,
535 'activate_error' => 'i18n_' . reset( $error_keys ),
536 )
537 )
538 )
539 );
540 exit;
541 }
542 if ( 'en_US' !== $locale ) {
543 wp_download_language_pack( $locale );
544 }
545 }
546 }
547 wp_safe_redirect( esc_url_raw( $this->get_next_step_link() ) );
548 exit;
549 }
550
551 /**
552 * Add media step to the wizard
553 * Add media step to the wizard
554 *
555 * @param array $steps List of steps.
556 * @return array List of steps updated.
557 * @since 2.7
558 */
559 public function add_step_media( $steps ) {
560 $languages = $this->model->get_languages_list();
561
562 if ( $this->is_media_step_displayable( $languages ) ) {
563 $steps['media'] = array(
564 'name' => esc_html__( 'Media', 'polylang' ),
565 'view' => array( $this, 'display_step_media' ),
566 'handler' => array( $this, 'save_step_media' ),
567 'scripts' => array(),
568 'styles' => array(),
569 );
570 }
571 return $steps;
572 }
573
574 /**
575 * Display the media step form
576 *
577 * @since 2.7
578 */
579 public function display_step_media() {
580 include __DIR__ . '/view-wizard-step-media.php';
581 }
582
583 /**
584 * Execute the media step
585 *
586 * @since 2.7
587 */
588 public function save_step_media() {
589 check_admin_referer( 'pll-wizard', '_pll_nonce' );
590
591 $media_support = isset( $_POST['media_support'] ) ? sanitize_key( $_POST['media_support'] ) === 'yes' : false;
592
593 $this->options['media_support'] = $media_support;
594
595 update_option( 'polylang', $this->options );
596
597 wp_safe_redirect( esc_url_raw( $this->get_next_step_link() ) );
598 exit;
599 }
600
601 /**
602 * Add untranslated contents step to the wizard
603 *
604 * @param array $steps List of steps.
605 * @return array List of steps updated.
606 * @since 2.7
607 */
608 public function add_step_untranslated_contents( $steps ) {
609 if ( ! $this->model->get_languages_list() || $this->model->get_objects_with_no_lang( 1 ) ) {
610 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 );
611 wp_localize_script( 'pll-wizard-language-choice', 'pll_dismiss_notice', esc_html__( 'Dismiss this notice.', 'polylang' ) );
612 wp_enqueue_style( 'pll-wizard-selectmenu', plugins_url( '/css/selectmenu' . $this->get_suffix() . '.css', POLYLANG_FILE ), array( 'dashicons', 'install', 'common' ), POLYLANG_VERSION );
613 $steps['untranslated-contents'] = array(
614 'name' => esc_html__( 'Content', 'polylang' ),
615 'view' => array( $this, 'display_step_untranslated_contents' ),
616 'handler' => array( $this, 'save_step_untranslated_contents' ),
617 'scripts' => array( 'pll-wizard-language-choice' ),
618 'styles' => array( 'pll-wizard-selectmenu' ),
619 );
620 }
621 return $steps;
622 }
623
624 /**
625 * Display the untranslated contents step form
626 *
627 * @since 2.7
628 */
629 public function display_step_untranslated_contents() {
630 include __DIR__ . '/view-wizard-step-untranslated-contents.php';
631 }
632
633 /**
634 * Execute the untranslated contents step
635 *
636 * @since 2.7
637 */
638 public function save_step_untranslated_contents() {
639 check_admin_referer( 'pll-wizard', '_pll_nonce' );
640
641 $lang = isset( $_POST['language'] ) ? sanitize_text_field( wp_unslash( $_POST['language'] ) ) : false;
642
643 if ( empty( $lang ) ) {
644 $lang = $this->options['default_lang'];
645 }
646
647 $language = $this->model->get_language( $lang );
648
649 while ( $nolang = $this->model->get_objects_with_no_lang( 1000 ) ) {
650 if ( ! empty( $nolang['posts'] ) ) {
651 $this->model->set_language_in_mass( 'post', $nolang['posts'], $language->slug );
652 }
653 if ( ! empty( $nolang['terms'] ) ) {
654 $this->model->set_language_in_mass( 'term', $nolang['terms'], $language->slug );
655 }
656 }
657
658 wp_safe_redirect( esc_url_raw( $this->get_next_step_link() ) );
659 exit;
660 }
661
662 /**
663 * Add home page step to the wizard
664 *
665 * @param array $steps List of steps.
666 * @return array List of steps updated.
667 * @since 2.7
668 */
669 public function add_step_home_page( $steps ) {
670 $languages = $this->model->get_languages_list();
671 $home_page_id = get_option( 'page_on_front' );
672
673 $translations = $this->model->post->get_translations( $home_page_id );
674
675 if ( $home_page_id > 0 && ( ! $languages || count( $languages ) === 1 || count( $translations ) !== count( $languages ) ) ) {
676 $steps['home-page'] = array(
677 'name' => esc_html__( 'Homepage', 'polylang' ),
678 'view' => array( $this, 'display_step_home_page' ),
679 'handler' => array( $this, 'save_step_home_page' ),
680 'scripts' => array(),
681 'styles' => array(),
682 );
683 }
684 return $steps;
685 }
686
687 /**
688 * Display the home page step form
689 *
690 * @since 2.7
691 */
692 public function display_step_home_page() {
693 include __DIR__ . '/view-wizard-step-home-page.php';
694 }
695
696 /**
697 * Execute the home page step
698 *
699 * @since 2.7
700 */
701 public function save_step_home_page() {
702 check_admin_referer( 'pll-wizard', '_pll_nonce' );
703
704 $languages = $this->model->get_languages_list();
705
706 $default_language = count( $languages ) > 0 ? $this->options['default_lang'] : null;
707 $home_page = isset( $_POST['home_page'] ) ? sanitize_key( $_POST['home_page'] ) : false;
708 $home_page_title = isset( $_POST['home_page_title'] ) ? sanitize_text_field( wp_unslash( $_POST['home_page_title'] ) ) : esc_html__( 'Homepage', 'polylang' );
709 $home_page_language = isset( $_POST['home_page_language'] ) ? sanitize_key( $_POST['home_page_language'] ) : false;
710
711 $untranslated_languages = isset( $_POST['untranslated_languages'] ) ? array_map( 'sanitize_key', $_POST['untranslated_languages'] ) : array();
712
713 call_user_func(
714 apply_filters( 'pll_wizard_create_home_page_translations', array( $this, 'create_home_page_translations' ) ),
715 $default_language,
716 $home_page,
717 $home_page_title,
718 $home_page_language,
719 $untranslated_languages
720 );
721
722 $this->model->clean_languages_cache();
723
724 wp_safe_redirect( esc_url_raw( $this->get_next_step_link() ) );
725 exit;
726 }
727
728 /**
729 * Create home page translations for each language defined.
730 *
731 * @since 2.7
732 *
733 * @param string $default_language slug of the default language; null if no default language is defined.
734 * @param int $home_page post_id of the home page if it's defined, false otherwise.
735 * @param string $home_page_title home page title if it's defined, 'Homepage' otherwise.
736 * @param string $home_page_language slug of the home page if it's defined, false otherwise.
737 * @param array $untranslated_languages array of languages which needs to have a home page translated.
738 */
739 public function create_home_page_translations( $default_language, $home_page, $home_page_title, $home_page_language, $untranslated_languages ) {
740 $translations = $this->model->post->get_translations( $home_page );
741
742 foreach ( $untranslated_languages as $language ) {
743 $language_properties = $this->model->get_language( $language );
744 $id = wp_insert_post(
745 array(
746 'post_title' => $home_page_title . ' - ' . $language_properties->name,
747 'post_type' => 'page',
748 'post_status' => 'publish',
749 )
750 );
751 $translations[ $language ] = $id;
752 pll_set_post_language( $id, $language );
753 }
754 pll_save_post_translations( $translations );
755 }
756
757 /**
758 * Add last step to the wizard
759 *
760 * @param array $steps List of steps.
761 * @return array List of steps updated.
762 * @since 2.7
763 */
764 public function add_step_last( $steps ) {
765 $steps['last'] = array(
766 'name' => esc_html__( 'Ready!', 'polylang' ),
767 'view' => array( $this, 'display_step_last' ),
768 'handler' => array( $this, 'save_step_last' ),
769 'scripts' => array(),
770 'styles' => array(),
771 );
772 return $steps;
773 }
774
775 /**
776 * Display the last step form
777 *
778 * @since 2.7
779 */
780 public function display_step_last() {
781 // We ran the wizard once. So we can dismiss its notice.
782 PLL_Admin_Notices::dismiss( 'wizard' );
783 include __DIR__ . '/view-wizard-step-last.php';
784 }
785
786 /**
787 * Execute the last step
788 *
789 * @since 2.7
790 */
791 public function save_step_last() {
792 check_admin_referer( 'pll-wizard', '_pll_nonce' );
793
794 wp_safe_redirect( esc_url_raw( $this->get_next_step_link() ) );
795 exit;
796 }
797 }
798