Plugin Directory

source: multisite-language-switcher/trunk/includes/MslsAdmin.php

Last change on this file was 3409411, checked in by realloc, 4 months ago

Update to version 2.10.0 from GitHub

File size: 14.9 KB
Line 
1<?php declare( strict_types=1 );
2
3namespace lloc\Msls;
4
5use lloc\Msls\Component\Input\Checkbox;
6use lloc\Msls\Component\Input\Group;
7use lloc\Msls\Component\Input\Label;
8use lloc\Msls\Component\Input\Text;
9use lloc\Msls\Component\Input\Select;
10
11/**
12 * Administration of the options
13 *
14 * @method void activate_autocomplete()
15 * @method void sort_by_description()
16 * @method void exclude_current_blog()
17 * @method void only_with_translation()
18 * @method void output_current_blog()
19 * @method void before_output()
20 * @method void after_output()
21 * @method void before_item()
22 * @method void after_item()
23 * @method void content_filter()
24 *
25 * @package Msls
26 */
27final class MslsAdmin extends MslsMain {
28
29        const MSLS_REGISTER_ACTION = 'msls_admin_register';
30
31        const MSLS_ACTION_PREFIX = 'msls_admin_';
32
33        /**
34         * Maximum number of users in the reference user select box
35         *
36         * @var int
37         */
38        public const MAX_REFERENCE_USERS = 100;
39
40        /**
41         * @codeCoverageIgnore
42         */
43        public static function init(): void {
44                $obj = MslsRegistry::get_object( __CLASS__ );
45                if ( ! $obj ) {
46                        $obj = new self( msls_options(), msls_blog_collection() );
47
48                        MslsRegistry::set_object( __CLASS__, $obj );
49
50                        /**
51                         * Override the capabilities needed for the plugin's settings
52                         *
53                         * @param string $capability
54                         *
55                         * @since 2.0
56                         */
57                        $caps = apply_filters( 'msls_admin_caps', 'manage_options' );
58                        if ( current_user_can( $caps ) ) {
59                                $title = __( 'Multisite Language Switcher', 'multisite-language-switcher' );
60                                add_options_page( $title, $title, 'manage_options', $obj->get_menu_slug(), array( $obj, 'render' ) );
61
62                                add_action( 'admin_init', array( $obj, 'register' ) );
63                                add_action( 'admin_notices', array( $obj, 'has_problems' ) );
64
65                                add_filter( 'msls_admin_validate', array( $obj, 'set_blog_language' ) );
66                        }
67                }
68        }
69
70        /**
71         * Let's do this simple
72         *
73         * @return string
74         */
75        public function get_menu_slug(): string {
76                return 'MslsAdmin';
77        }
78
79        /**
80         * Gets the link for the switcher-settings in the wp-admin
81         *
82         * @return string
83         */
84        public function get_options_page_link(): string {
85                return sprintf( '/options-general.php?page=%s', $this->get_menu_slug() );
86        }
87
88        /**
89         * You can use every method of the decorated object
90         *
91         * @param string $method
92         * @param mixed  $args
93         *
94         * @return mixed
95         */
96        public function __call( $method, $args ) {
97                $parts = explode( '_', $method, 2 );
98                if ( 2 === count( $parts ) && 'rewrite' === $parts[0] ) {
99                        $this->render_rewrite( $parts[1] );
100                        return;
101                }
102
103                $checkboxes = array(
104                        'activate_autocomplete'   => __(
105                                'Activate experimental autocomplete inputs',
106                                'multisite-language-switcher'
107                        ),
108                        'activate_content_import' => __(
109                                'Activate the content import functionality',
110                                'multisite-language-switcher'
111                        ),
112                        'sort_by_description'     => __( 'Sort languages by description', 'multisite-language-switcher' ),
113                        'exclude_current_blog'    => __( 'Exclude this blog from output', 'multisite-language-switcher' ),
114                        'only_with_translation'   => __( 'Show only links with a translation', 'multisite-language-switcher' ),
115                        'output_current_blog'     => __( 'Display link to the current language', 'multisite-language-switcher' ),
116                        'content_filter'          => __( 'Add hint for available translations', 'multisite-language-switcher' ),
117                );
118
119                if ( isset( $checkboxes[ $method ] ) ) {
120                        $group = ( new Group() )
121                                ->add( new Checkbox( $method, $this->options->$method ) )
122                                ->add( new Label( $method, $checkboxes[ $method ] ) );
123
124                        echo $group->render(); // phpcs:ignore WordPress.Security.EscapeOutput
125                } else {
126                        $text = new Text( $method, ! empty( $this->options->$method ) ? $this->options->$method : '' );
127
128                        echo $text->render(); // // phpcs:ignore WordPress.Security.EscapeOutput
129                }
130        }
131
132        /**
133         * There is something wrong? Here comes the message...
134         *
135         * @return void
136         */
137        public function has_problems(): void {
138                $message = '';
139
140                if ( $this->options->is_empty() ) {
141                        /* translators: %s: URL to the options page */
142                        $format  = __(
143                                'Multisite Language Switcher is almost ready. You must <a href="%s">complete the configuration process</a>.',
144                                'multisite-language-switcher'
145                        );
146                        $message = sprintf( $format, esc_url( admin_url( $this->get_options_page_link() ) ) );
147                } elseif ( 1 === count( $this->options->get_available_languages() ) ) {
148                        /* translators: %1$s: URL to a page at WordPress.orgs */
149                        $format  = __(
150                                'No language files are currently installed. Learn how to install various languages in WordPress by <a href="%1$s">reading more here</a>.',
151                                'multisite-language-switcher'
152                        );
153                        $message = sprintf(
154                                $format,
155                                esc_url( 'https://developer.wordpress.org/advanced-administration/before-install/in-your-language/#Manually_Installing_Language_Files' )
156                        );
157                }
158
159                MslsPlugin::message_handler( $message, 'updated fade' );
160        }
161
162        /**
163         * Render the options-page
164         */
165        public function render(): void {
166                printf(
167                        '<div class="wrap"><div class="icon32" id="icon-options-general"><br/></div><h1>%s</h1>%s<br class="clear"/><form action="options.php" method="post"><p>%s</p>',
168                        esc_html__( 'Multisite Language Switcher Options', 'multisite-language-switcher' ),
169                        $this->subsubsub(), // phpcs:ignore WordPress.Security.EscapeOutput
170                        esc_html__(
171                                'To achieve maximum flexibility, you have to configure each blog separately.',
172                                'multisite-language-switcher'
173                        )
174                );
175
176                settings_fields( 'msls' );
177                do_settings_sections( __CLASS__ );
178
179                $value = $this->options->is_empty() ? __( 'Configure', 'multisite-language-switcher' ) : __( 'Update', 'multisite-language-switcher' );
180
181                printf(
182                        '<p class="submit"><input name="Submit" type="submit" class="button button-primary" value="%s" /></p></form></div>',
183                        esc_html( $value )
184                );
185        }
186
187
188        /**
189         * Create a submenu which contains links to all blogs of the current user
190         *
191         * @return string
192         */
193        public function subsubsub(): string {
194                $icon_type = $this->options->get_icon_type();
195
196                $arr = array();
197                foreach ( $this->collection->get_plugin_active_blogs() as $blog ) {
198                        $admin_url = get_admin_url( $blog->userblog_id, $this->get_options_page_link() );
199                        $current   = $blog->userblog_id === $this->collection->get_current_blog_id() ? ' class="current"' : '';
200
201                        $arr[] = sprintf( '<a href="%1$s"%2$s>%3$s</a>', $admin_url, $current, $blog->get_title( $icon_type ) );
202                }
203
204                return empty( $arr ) ? '' : sprintf(
205                        '<ul class="subsubsub"><li>%s</li></ul>',
206                        implode( ' | </li><li>', $arr )
207                );
208        }
209
210        /**
211         * Register the form-elements
212         */
213        public function register(): void {
214                register_setting( 'msls', 'msls', array( $this, 'validate' ) );
215
216                $sections = array(
217                        'language_section' => __( 'Language Settings', 'multisite-language-switcher' ),
218                        'main_section'     => __( 'Main Settings', 'multisite-language-switcher' ),
219                        'advanced_section' => __( 'Advanced Settings', 'multisite-language-switcher' ),
220                );
221
222                global $wp_rewrite;
223                if ( $wp_rewrite->using_permalinks() ) {
224                        $sections['rewrites_section'] = __( 'Rewrites Settings', 'multisite-language-switcher' );
225                }
226
227                foreach ( $sections as $id => $title ) {
228                        add_settings_section( $id, $title, array( $this, $id ), __CLASS__ );
229                }
230
231                /**
232                 * Lets you add your own settings section
233                 *
234                 * @param string $page
235                 *
236                 * @since 1.0
237                 */
238                do_action( self::MSLS_REGISTER_ACTION, __CLASS__ );
239        }
240
241        /**
242         * Registers the fields in the language_section
243         *
244         * Returns the number of added fields
245         *
246         * @return int
247         */
248        public function language_section(): int {
249                $map = array( 'blog_language' => __( 'Blog Language', 'multisite-language-switcher' ) );
250
251                return $this->add_settings_fields( $map, 'language_section' );
252        }
253
254        /**
255         * Registers the fields in the main_section
256         *
257         * Returns the number of added fields
258         *
259         * @return int
260         */
261        public function main_section(): int {
262                $map = array(
263                        'display'               => esc_html__( 'Display', 'multisite-language-switcher' ),
264                        'admin_display'         => esc_html__( 'Admin Display', 'multisite-language-switcher' ),
265                        'sort_by_description'   => esc_html__( 'Sort languages', 'multisite-language-switcher' ),
266                        'output_current_blog'   => esc_html__( 'Current language link', 'multisite-language-switcher' ),
267                        'only_with_translation' => esc_html__( 'Translation links', 'multisite-language-switcher' ),
268                        'description'           => esc_html__( 'Description', 'multisite-language-switcher' ),
269                        'before_output'         => esc_html__( 'Text/HTML before the list', 'multisite-language-switcher' ),
270                        'after_output'          => esc_html__( 'Text/HTML after the list', 'multisite-language-switcher' ),
271                        'before_item'           => esc_html__( 'Text/HTML before each item', 'multisite-language-switcher' ),
272                        'after_item'            => esc_html__( 'Text/HTML after each item', 'multisite-language-switcher' ),
273                        'content_filter'        => esc_html__( 'Available translations hint', 'multisite-language-switcher' ),
274                        'content_priority'      => esc_html__( 'Hint priority', 'multisite-language-switcher' ),
275                );
276
277                return $this->add_settings_fields( $map, 'main_section' );
278        }
279
280        /**
281         * Registers the fields in the advanced_section
282         *
283         * Returns the number of added fields
284         *
285         * @return int
286         */
287        public function advanced_section(): int {
288                $map = array(
289                        'activate_autocomplete'   => esc_html__( 'Autocomplete', 'multisite-language-switcher' ),
290                        'image_url'               => esc_html__( 'Custom URL for flag-images', 'multisite-language-switcher' ),
291                        'reference_user'          => esc_html__( 'Reference user', 'multisite-language-switcher' ),
292                        'exclude_current_blog'    => esc_html__( 'Exclude blog', 'multisite-language-switcher' ),
293                        'activate_content_import' => esc_html__( 'Content import', 'multisite-language-switcher' ),
294                );
295
296                return $this->add_settings_fields( $map, 'advanced_section' );
297        }
298
299        /**
300         * Registers the fields in the rewrites_section
301         *
302         * Returns the number of added fields
303         *
304         * @return int
305         */
306        public function rewrites_section(): int {
307                $map = array();
308                foreach ( get_post_types( array( 'public' => true ), 'objects' ) as $key => $object ) {
309                        /* translators: %s: post type label */
310                        $format = __( '%s Slug', 'multisite-language-switcher' );
311
312                        $map[ "rewrite_{$key}" ] = sprintf( $format, $object->label );
313                }
314
315                return $this->add_settings_fields( $map, 'rewrites_section' );
316        }
317
318        /**
319         * @param array<string, string> $map
320         * @param string                $section
321         *
322         * @return int
323         */
324        protected function add_settings_fields( array $map, string $section ): int {
325                foreach ( $map as $id => $title ) {
326                        add_settings_field( $id, $title, array( $this, $id ), __CLASS__, $section, array( 'label_for' => $id ) );
327                }
328
329                /**
330                 * Lets you add your own field to the section
331                 *
332                 * @param string $page
333                 * @param string $section
334                 *
335                 * @since 2.4.4
336                 */
337                do_action( self::MSLS_ACTION_PREFIX . $section, __CLASS__, $section );
338
339                return count( $map );
340        }
341
342        /**
343         * Shows the select-form-field 'blog_language'
344         */
345        public function blog_language(): void {
346                $languages = $this->options->get_available_languages();
347                $selected  = get_locale();
348
349        // phpcs:ignore WordPress.Security.EscapeOutput
350                echo ( new Select( 'blog_language', $languages, $selected ) )->render();
351        }
352
353        /**
354         * Shows the select-form-field 'display'
355         */
356        public function display(): void {
357        // phpcs:ignore WordPress.Security.EscapeOutput
358                echo ( new Select( 'display', MslsLink::get_types_description(), strval( $this->options->display ) ) )->render();
359        }
360
361        /**
362         * Shows the select-form-field 'admin_display'
363         */
364        public function admin_display(): void {
365                $select = new Select(
366                        'admin_display',
367                        array(
368                                MslsAdminIcon::TYPE_FLAG  => __( 'Flag', 'multisite-language-switcher' ),
369                                MslsAdminIcon::TYPE_LABEL => __( 'Label', 'multisite-language-switcher' ),
370                        ),
371                        $this->options->get_icon_type()
372                );
373
374                echo $select->render(); // phpcs:ignore WordPress.Security.EscapeOutput
375        }
376
377        /**
378         * Shows the select-form-field 'reference_user'
379         */
380        public function reference_user(): void {
381                $users = array();
382
383                foreach ( (array) apply_filters( 'msls_reference_users', $this->collection->get_users() ) as $user ) {
384                        $users[ $user->ID ] = $user->user_nicename;
385                }
386
387                if ( count( $users ) > self::MAX_REFERENCE_USERS ) {
388                        $users = array_slice( $users, 0, self::MAX_REFERENCE_USERS, true );
389
390                        /* translators: %s: maximum number of users */
391                        $format = __(
392                                'Multisite Language Switcher: Collection for reference user has been truncated because it exceeded the maximum of %d users. Please, use the hook "msls_reference_users" to filter the result before!',
393                                'multisite-language-switcher'
394                        );
395
396                        // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error
397                        trigger_error( esc_html( sprintf( $format, strval( self::MAX_REFERENCE_USERS ) ) ) );
398                }
399
400        // phpcs:ignore WordPress.Security.EscapeOutput
401                echo ( new Select( 'reference_user', $users, strval( $this->options->reference_user ) ) )->render();
402        }
403
404        /**
405         * The description for the current blog
406         *
407         * The language will be used ff there is no description.
408         */
409        public function description(): void {
410        // phpcs:ignore WordPress.Security.EscapeOutput
411                echo ( new Text( 'description', $this->options->description, 40 ) )->render();
412        }
413
414        /**
415         * If the output in the_content is active you can set the priority too
416         *
417         * Default is 10. But may be there are other plugins active and you run into
418         * trouble. So you can decide a higher (from 1) or a lower (to 100) priority
419         * for the output
420         */
421        public function content_priority(): void {
422                $temp     = array_merge( range( 1, 10 ), array( 20, 50, 100 ) );
423                $arr      = array_combine( $temp, $temp );
424                $selected = empty( $this->options->content_priority ) ? 10 : $this->options->content_priority;
425
426        // phpcs:ignore WordPress.Security.EscapeOutput
427                echo ( new Select( 'content_priority', $arr, strval( $selected ) ) )->render();
428        }
429
430        /**
431         * Rewrites slugs for registered post types
432         *
433         * @param mixed $key
434         */
435        public function render_rewrite( $key ): void {
436                $rewrite = get_post_type_object( $key )->rewrite;
437                $value   = $rewrite['slug'] ?? '';
438
439        // phpcs:ignore WordPress.Security.EscapeOutput
440                echo ( new Text( "rewrite_{$key}", $value, 30, true ) )->render();
441        }
442
443        /**
444         * Validates input before saving it
445         *
446         * @param array<string, mixed> $arr Values of the submitted form.
447         *
448         * @return array<string, mixed>
449         */
450        public function validate( array $arr ) {
451                /**
452                 * Returns custom filtered input array
453                 *
454                 * @param array $arr
455                 *
456                 * @since 1.0
457                 */
458                $arr = (array) apply_filters( 'msls_admin_validate', $arr );
459
460                $arr['display'] = intval( $arr['display'] ?? 0 );
461                if ( isset( $arr['image_url'] ) ) {
462                        $arr['image_url'] = rtrim( esc_attr( $arr['image_url'] ), '/' );
463                }
464
465                return $arr;
466        }
467
468        /**
469         * Filter which sets the global blog language
470         *
471         * @param string[] $arr
472         *
473         * @return string[]
474         */
475        public function set_blog_language( array $arr ) {
476                if ( isset( $arr['blog_language'] ) ) {
477                        $blog_language = ( 'en_US' === $arr['blog_language'] ) ? '' : $arr['blog_language'];
478                        update_option( 'WPLANG', $blog_language );
479                        unset( $arr['blog_language'] );
480                }
481
482                return $arr;
483        }
484}
Note: See TracBrowser for help on using the repository browser.