PluginProbe
Polylang / 2.9
Polylang v2.9
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.9, at modules/wizard/wizard.php

799 lines 24.6 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
543 if ( 'en_US' !== $locale && current_user_can( 'install_languages' ) ) {
544 wp_download_language_pack( $locale );
545 }
546 }
547 }
548 wp_safe_redirect( esc_url_raw( $this->get_next_step_link() ) );
549 exit;
550 }
551
552 /**
553 * Add media step to the wizard
554 * Add media step to the wizard
555 *
556 * @param array $steps List of steps.
557 * @return array List of steps updated.
558 * @since 2.7
559 */
560 public function add_step_media( $steps ) {
561 $languages = $this->model->get_languages_list();
562
563 if ( $this->is_media_step_displayable( $languages ) ) {
564 $steps['media'] = array(
565 'name' => esc_html__( 'Media', 'polylang' ),
566 'view' => array( $this, 'display_step_media' ),
567 'handler' => array( $this, 'save_step_media' ),
568 'scripts' => array(),
569 'styles' => array(),
570 );
571 }
572 return $steps;
573 }
574
575 /**
576 * Display the media step form
577 *
578 * @since 2.7
579 */
580 public function display_step_media() {
581 include __DIR__ . '/view-wizard-step-media.php';
582 }
583
584 /**
585 * Execute the media step
586 *
587 * @since 2.7
588 */
589 public function save_step_media() {
590 check_admin_referer( 'pll-wizard', '_pll_nonce' );
591
592 $media_support = isset( $_POST['media_support'] ) ? sanitize_key( $_POST['media_support'] ) === 'yes' : false;
593
594 $this->options['media_support'] = $media_support;
595
596 update_option( 'polylang', $this->options );
597
598 wp_safe_redirect( esc_url_raw( $this->get_next_step_link() ) );
599 exit;
600 }
601
602 /**
603 * Add untranslated contents step to the wizard
604 *
605 * @param array $steps List of steps.
606 * @return array List of steps updated.
607 * @since 2.7
608 */
609 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 );
614 $steps['untranslated-contents'] = array(
615 'name' => esc_html__( 'Content', 'polylang' ),
616 'view' => array( $this, 'display_step_untranslated_contents' ),
617 'handler' => array( $this, 'save_step_untranslated_contents' ),
618 'scripts' => array( 'pll-wizard-language-choice' ),
619 'styles' => array( 'pll-wizard-selectmenu' ),
620 );
621 }
622 return $steps;
623 }
624
625 /**
626 * Display the untranslated contents step form
627 *
628 * @since 2.7
629 */
630 public function display_step_untranslated_contents() {
631 include __DIR__ . '/view-wizard-step-untranslated-contents.php';
632 }
633
634 /**
635 * Execute the untranslated contents step
636 *
637 * @since 2.7
638 */
639 public function save_step_untranslated_contents() {
640 check_admin_referer( 'pll-wizard', '_pll_nonce' );
641
642 $lang = isset( $_POST['language'] ) ? sanitize_text_field( wp_unslash( $_POST['language'] ) ) : false;
643
644 if ( empty( $lang ) ) {
645 $lang = $this->options['default_lang'];
646 }
647
648 $language = $this->model->get_language( $lang );
649
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 }
657 }
658
659 wp_safe_redirect( esc_url_raw( $this->get_next_step_link() ) );
660 exit;
661 }
662
663 /**
664 * Add home page step to the wizard
665 *
666 * @param array $steps List of steps.
667 * @return array List of steps updated.
668 * @since 2.7
669 */
670 public function add_step_home_page( $steps ) {
671 $languages = $this->model->get_languages_list();
672 $home_page_id = get_option( 'page_on_front' );
673
674 $translations = $this->model->post->get_translations( $home_page_id );
675
676 if ( $home_page_id > 0 && ( ! $languages || count( $languages ) === 1 || count( $translations ) !== count( $languages ) ) ) {
677 $steps['home-page'] = array(
678 'name' => esc_html__( 'Homepage', 'polylang' ),
679 'view' => array( $this, 'display_step_home_page' ),
680 'handler' => array( $this, 'save_step_home_page' ),
681 'scripts' => array(),
682 'styles' => array(),
683 );
684 }
685 return $steps;
686 }
687
688 /**
689 * Display the home page step form
690 *
691 * @since 2.7
692 */
693 public function display_step_home_page() {
694 include __DIR__ . '/view-wizard-step-home-page.php';
695 }
696
697 /**
698 * Execute the home page step
699 *
700 * @since 2.7
701 */
702 public function save_step_home_page() {
703 check_admin_referer( 'pll-wizard', '_pll_nonce' );
704
705 $languages = $this->model->get_languages_list();
706
707 $default_language = count( $languages ) > 0 ? $this->options['default_lang'] : null;
708 $home_page = isset( $_POST['home_page'] ) ? sanitize_key( $_POST['home_page'] ) : false;
709 $home_page_title = isset( $_POST['home_page_title'] ) ? sanitize_text_field( wp_unslash( $_POST['home_page_title'] ) ) : esc_html__( 'Homepage', 'polylang' );
710 $home_page_language = isset( $_POST['home_page_language'] ) ? sanitize_key( $_POST['home_page_language'] ) : false;
711
712 $untranslated_languages = isset( $_POST['untranslated_languages'] ) ? array_map( 'sanitize_key', $_POST['untranslated_languages'] ) : array();
713
714 call_user_func(
715 apply_filters( 'pll_wizard_create_home_page_translations', array( $this, 'create_home_page_translations' ) ),
716 $default_language,
717 $home_page,
718 $home_page_title,
719 $home_page_language,
720 $untranslated_languages
721 );
722
723 $this->model->clean_languages_cache();
724
725 wp_safe_redirect( esc_url_raw( $this->get_next_step_link() ) );
726 exit;
727 }
728
729 /**
730 * Create home page translations for each language defined.
731 *
732 * @since 2.7
733 *
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.
739 */
740 public function create_home_page_translations( $default_language, $home_page, $home_page_title, $home_page_language, $untranslated_languages ) {
741 $translations = $this->model->post->get_translations( $home_page );
742
743 foreach ( $untranslated_languages as $language ) {
744 $language_properties = $this->model->get_language( $language );
745 $id = wp_insert_post(
746 array(
747 'post_title' => $home_page_title . ' - ' . $language_properties->name,
748 'post_type' => 'page',
749 'post_status' => 'publish',
750 )
751 );
752 $translations[ $language ] = $id;
753 pll_set_post_language( $id, $language );
754 }
755 pll_save_post_translations( $translations );
756 }
757
758 /**
759 * Add last step to the wizard
760 *
761 * @param array $steps List of steps.
762 * @return array List of steps updated.
763 * @since 2.7
764 */
765 public function add_step_last( $steps ) {
766 $steps['last'] = array(
767 'name' => esc_html__( 'Ready!', 'polylang' ),
768 'view' => array( $this, 'display_step_last' ),
769 'handler' => array( $this, 'save_step_last' ),
770 'scripts' => array(),
771 'styles' => array(),
772 );
773 return $steps;
774 }
775
776 /**
777 * Display the last step form
778 *
779 * @since 2.7
780 */
781 public function display_step_last() {
782 // We ran the wizard once. So we can dismiss its notice.
783 PLL_Admin_Notices::dismiss( 'wizard' );
784 include __DIR__ . '/view-wizard-step-last.php';
785 }
786
787 /**
788 * Execute the last step
789 *
790 * @since 2.7
791 */
792 public function save_step_last() {
793 check_admin_referer( 'pll-wizard', '_pll_nonce' );
794
795 wp_safe_redirect( esc_url_raw( $this->get_next_step_link() ) );
796 exit;
797 }
798 }
799