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

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