PluginProbe
Polylang / 3.8.7
Polylang v3.8.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
polylang / src / settings / settings.php

settings.php in Polylang 3.8.7, at src/settings/settings.php

418 lines 11.7 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 defined( 'ABSPATH' ) || exit;
7
8 /**
9 * A class for the Polylang settings pages, accessible from @see PLL().
10 *
11 * @since 1.2
12 */
13 class PLL_Settings extends PLL_Admin_Base {
14 /**
15 * Name of the active module.
16 *
17 * @var string|null
18 */
19 protected $active_tab;
20
21 /**
22 * Array of modules classes.
23 *
24 * @var PLL_Settings_Module[]|null
25 */
26 protected $modules;
27
28 /**
29 * Constructor
30 *
31 * @since 1.2
32 *
33 * @param PLL_Links_Model $links_model Reference to the links model.
34 */
35 public function __construct( &$links_model ) {
36 parent::__construct( $links_model );
37
38 if ( isset( $_GET['page'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
39 $this->active_tab = 'mlang' === $_GET['page'] ? 'lang' : substr( sanitize_key( $_GET['page'] ), 6 ); // phpcs:ignore WordPress.Security.NonceVerification
40 }
41
42 PLL_Admin_Strings::init();
43
44 add_action( 'admin_init', array( $this, 'register_settings_modules' ) );
45
46 // Adds screen options and the about box in the languages admin panel.
47 add_action( 'load-' . self::get_screen_id( 'lang' ), array( $this, 'load_page' ) );
48 add_action( 'load-' . self::get_screen_id( 'strings' ), array( $this, 'load_page_strings' ) );
49
50 // Saves the per-page value in screen options.
51 add_filter( 'set_screen_option_pll_lang_per_page', array( $this, 'set_screen_option' ), 10, 3 );
52 add_filter( 'set_screen_option_pll_strings_per_page', array( $this, 'set_screen_option' ), 10, 3 );
53 }
54
55 /**
56 * Initializes the modules
57 *
58 * @since 1.8
59 *
60 * @return void
61 */
62 public function register_settings_modules() {
63 $modules = array();
64
65 if ( $this->model->has_languages() ) {
66 $modules = array(
67 'PLL_Settings_Url',
68 'PLL_Settings_Browser',
69 'PLL_Settings_Media',
70 'PLL_Settings_CPT',
71 );
72 }
73
74 $modules[] = 'PLL_Settings_Licenses';
75
76 /**
77 * Filter the list of setting modules
78 *
79 * @since 1.8
80 *
81 * @param array $modules the list of module classes
82 */
83 $modules = apply_filters( 'pll_settings_modules', $modules );
84
85 foreach ( $modules as $key => $class ) {
86 $key = is_numeric( $key ) ? strtolower( str_replace( 'PLL_Settings_', '', $class ) ) : $key;
87 $this->modules[ $key ] = new $class( $this );
88 }
89 }
90
91 /**
92 * Loads the about metabox
93 *
94 * @since 0.8
95 *
96 * @return void
97 */
98 public function metabox_about() {
99 include __DIR__ . '/view-about.php';
100 }
101
102 /**
103 * Adds screen options and the about box in the languages admin panel
104 *
105 * @since 0.9.5
106 *
107 * @return void
108 */
109 public function load_page() {
110 if ( ! defined( 'PLL_DISPLAY_ABOUT' ) || PLL_DISPLAY_ABOUT ) {
111 add_meta_box(
112 'pll-about-box',
113 __( 'About Polylang', 'polylang' ),
114 array( $this, 'metabox_about' ),
115 self::get_screen_id( 'lang' ),
116 'normal'
117 );
118 }
119
120 add_screen_option(
121 'per_page',
122 array(
123 'label' => __( 'Languages', 'polylang' ),
124 'default' => 10,
125 'option' => 'pll_lang_per_page',
126 )
127 );
128
129 add_action( 'admin_notices', array( $this, 'notice_objects_with_no_lang' ) );
130 }
131
132 /**
133 * Adds screen options in the strings translations admin panel
134 *
135 * @since 2.1
136 *
137 * @return void
138 */
139 public function load_page_strings() {
140 add_screen_option(
141 'per_page',
142 array(
143 'label' => __( 'Strings translations', 'polylang' ),
144 'default' => 10,
145 'option' => 'pll_strings_per_page',
146 )
147 );
148 }
149
150 /**
151 * Saves the number of rows in the languages or strings table set by this user.
152 *
153 * @since 0.9.5
154 *
155 * @param mixed $screen_option False or value returned by a previous filter, not used.
156 * @param string $option The name of the option, not used.
157 * @param int $value The new value of the option to save.
158 * @return int The new value of the option.
159 */
160 public function set_screen_option( $screen_option, $option, $value ) {
161 return (int) $value;
162 }
163
164 /**
165 * Manages the user input for the languages pages.
166 *
167 * @since 1.9
168 *
169 * @param string $action The action name.
170 * @return void
171 *
172 * @phpstan-param non-empty-string $action
173 * @phpstan-return never
174 */
175 public function handle_actions( string $action ): void {
176 switch ( $action ) {
177 case 'add':
178 check_admin_referer( 'add-lang', '_wpnonce_add-lang' );
179 $language = $this->model->add_language( $_POST );
180
181 if ( is_wp_error( $language ) ) {
182 pll_add_notice( $language );
183 } else {
184 pll_add_notice( new WP_Error( 'pll_languages_created', __( 'Language added.', 'polylang' ), 'success' ) );
185
186 if ( 'en_US' !== $language->locale && current_user_can( 'install_languages' ) ) {
187 // Attempts to install the language pack
188 require_once ABSPATH . 'wp-admin/includes/translation-install.php';
189 if ( ! wp_download_language_pack( $language->locale ) ) {
190 pll_add_notice( new WP_Error( 'pll_download_mo', __( 'The language was created, but the WordPress language file was not downloaded. Please install it manually.', 'polylang' ), 'warning' ) );
191 }
192
193 // Force checking for themes and plugins translations updates
194 wp_clean_themes_cache();
195 wp_clean_plugins_cache();
196 }
197 }
198 break;
199
200 case 'delete':
201 check_admin_referer( 'delete-lang' );
202
203 if ( ! empty( $_GET['lang'] ) && $this->model->delete_language( (int) $_GET['lang'] ) ) {
204 pll_add_notice( new WP_Error( 'pll_languages_deleted', __( 'Language deleted.', 'polylang' ), 'success' ) );
205 }
206
207 break;
208
209 case 'update':
210 check_admin_referer( 'add-lang', '_wpnonce_add-lang' );
211 $errors = $this->model->update_language( $_POST );
212
213 if ( is_wp_error( $errors ) ) {
214 pll_add_notice( $errors );
215 } else {
216 pll_add_notice( new WP_Error( 'pll_languages_updated', __( 'Language updated.', 'polylang' ), 'success' ) );
217 }
218
219 break;
220
221 case 'default-lang':
222 check_admin_referer( 'default-lang' );
223
224 if ( $lang = $this->model->get_language( (int) $_GET['lang'] ) ) {
225 $this->model->update_default_lang( $lang->slug );
226 }
227
228 break;
229
230 case 'content-default-lang':
231 check_admin_referer( 'content-default-lang' );
232
233 $this->model->set_language_in_mass();
234
235 break;
236
237 case 'activate':
238 check_admin_referer( 'pll_activate' );
239 if ( isset( $_GET['module'] ) ) {
240 $module = sanitize_key( $_GET['module'] );
241 if ( isset( $this->modules[ $module ] ) ) {
242 $this->modules[ $module ]->activate();
243 }
244 }
245 break;
246
247 case 'deactivate':
248 check_admin_referer( 'pll_deactivate' );
249 if ( isset( $_GET['module'] ) ) {
250 $module = sanitize_key( $_GET['module'] );
251 if ( isset( $this->modules[ $module ] ) ) {
252 $this->modules[ $module ]->deactivate();
253 }
254 }
255 break;
256
257 default:
258 /**
259 * Fires when a non default action has been sent to Polylang settings
260 *
261 * @since 1.8
262 */
263 do_action( "mlang_action_$action" );
264 break;
265 }
266
267 self::redirect();
268 }
269
270 /**
271 * Displays the 3 tabs pages: languages, strings translations, settings
272 * Also manages user input for these pages
273 *
274 * @since 0.1
275 *
276 * @return void
277 */
278 public function languages_page() {
279 switch ( $this->active_tab ) {
280 case 'lang':
281 // Prepare the list table of languages
282 $list_table = new PLL_Table_Languages();
283 $list_table->prepare_items( $this->model->get_languages_list() );
284 break;
285
286 case 'strings':
287 $string_table = new PLL_Table_String( $this->model->languages );
288 $string_table->prepare_items();
289 break;
290 }
291
292 // Handle user input.
293 $action = isset( $_REQUEST['pll_action'] ) && is_string( $_REQUEST['pll_action'] ) ? sanitize_key( $_REQUEST['pll_action'] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification
294 if ( 'edit' === $action && ! empty( $_GET['lang'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
295 // phpcs:ignore WordPress.Security.NonceVerification, VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
296 $edit_lang = $this->model->get_language( (int) $_GET['lang'] );
297 } elseif ( ! empty( $action ) ) {
298 $this->handle_actions( $action );
299 }
300
301 // Displays the page
302 $modules = $this->modules;
303 $active_tab = $this->active_tab;
304 include __DIR__ . '/view-languages.php';
305 }
306
307 /**
308 * Enqueues scripts and styles
309 *
310 * @return void
311 */
312 public function admin_enqueue_scripts() {
313 parent::admin_enqueue_scripts();
314
315 $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
316
317 wp_enqueue_script( 'pll_settings', plugins_url( '/js/build/settings' . $suffix . '.js', POLYLANG_ROOT_FILE ), array( 'jquery', 'wp-ajax-response', 'postbox', 'jquery-ui-selectmenu', 'wp-hooks' ), POLYLANG_VERSION, true );
318 wp_localize_script( 'pll_settings', 'pll_settings', array( 'dismiss_notice' => esc_html__( 'Dismiss this notice.', 'polylang' ) ) );
319
320 wp_enqueue_style( 'pll_selectmenu', plugins_url( '/css/build/selectmenu' . $suffix . '.css', POLYLANG_ROOT_FILE ), array(), POLYLANG_VERSION );
321 }
322
323 /**
324 * Displays a notice when there are objects with no language assigned
325 *
326 * @since 1.8
327 *
328 * @return void
329 */
330 public function notice_objects_with_no_lang() {
331 if ( ! empty( $this->options['default_lang'] ) && $this->model->get_objects_with_no_lang( 1 ) ) {
332 printf(
333 '<div class="error"><p>%s <a href="%s">%s</a></p></div>',
334 esc_html__( 'There are posts, pages, categories or tags without language.', 'polylang' ),
335 esc_url( wp_nonce_url( '?page=mlang&pll_action=content-default-lang&noheader=true', 'content-default-lang' ) ),
336 esc_html__( 'You can set them all to the default language.', 'polylang' )
337 );
338 }
339 }
340
341 /**
342 * Redirects to language page ( current active tab )
343 * saves error messages in a transient for reuse in redirected page
344 *
345 * @since 1.5
346 *
347 * @param array $args query arguments to add to the url
348 * @return void
349 *
350 * @phpstan-return never
351 */
352 public static function redirect( array $args = array() ): void {
353 $errors = get_settings_errors( 'polylang' );
354 if ( ! empty( $errors ) ) {
355 set_transient( 'settings_errors', $errors, 30 );
356 $args['settings-updated'] = 1;
357 }
358 // Remove all known query args from the referer before redirecting.
359 $to_remove = array( 'lang', 'module', 'pll_action', 'noheader', '_wpnonce' );
360 wp_safe_redirect( add_query_arg( $args, remove_query_arg( $to_remove, wp_get_referer() ) ) );
361 exit;
362 }
363
364 /**
365 * Get the list of predefined languages
366 *
367 * @since 2.3
368 *
369 * @return string[][] {
370 * An array of array of language properties.
371 *
372 * @type string[] {
373 * @type string $code ISO 639-1 language code.
374 * @type string $locale WordPress locale.
375 * @type string $name Native language name.
376 * @type string $dir Text direction: 'ltr' or 'rtl'.
377 * @type string $flag Flag code, generally the country code.
378 * @type string $w3c W3C locale.
379 * @type string $facebook Facebook locale.
380 * }
381 * }
382 */
383 public static function get_predefined_languages() {
384 require_once ABSPATH . 'wp-admin/includes/translation-install.php';
385
386 $languages = include __DIR__ . '/languages.php';
387 $translations = wp_get_available_translations();
388
389 // Keep only languages with existing WP language pack
390 // Unless the transient has expired and we don't have an internet connection to refresh it
391 if ( ! empty( $translations ) ) {
392 $translations['en_US'] = ''; // Languages packs don't include en_US
393 $languages = array_intersect_key( $languages, $translations );
394 }
395
396 /**
397 * Filters the list of predefined languages.
398 *
399 * @see src/settings/languages.php the list of predefined languages.
400 *
401 * @since 1.7.10
402 * @since 2.3 The languages arrays use associative keys instead of numerical keys.
403 *
404 * @param array $languages
405 */
406 $languages = apply_filters( 'pll_predefined_languages', $languages );
407
408 // Keep only languages with all necessary information
409 foreach ( $languages as $k => $lang ) {
410 if ( ! isset( $lang['code'], $lang['locale'], $lang['name'], $lang['dir'], $lang['flag'] ) ) {
411 unset( $languages[ $k ] );
412 }
413 }
414
415 return $languages;
416 }
417 }
418