Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
73.13% covered (warning)
73.13%
49 / 67
66.67% covered (warning)
66.67%
4 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
Settings_Page
73.13% covered (warning)
73.13%
49 / 67
66.67% covered (warning)
66.67%
4 / 6
20.96
0.00% covered (danger)
0.00%
0 / 1
 init
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 register_menu
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
2
 render_sections
100.00% covered (success)
100.00%
23 / 23
100.00% covered (success)
100.00%
1 / 1
7
 render_saved_notice
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
3
 render_multibyte_warning
10.53% covered (danger)
10.53%
2 / 19
0.00% covered (danger)
0.00%
0 / 1
4.87
 render
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2/**
3 * The Settings > Sharing screen.
4 *
5 * @package automattic/jetpack-sharing-likes
6 */
7
8declare( strict_types = 1 );
9
10namespace Automattic\Jetpack\Sharing_Likes\Settings;
11
12/**
13 * Registers Settings > Sharing and renders its sections.
14 *
15 * Registration does not depend on any module being active, so the screen and
16 * every section on it exist whatever the site is running, as long as it can
17 * run them at all: see `Environment::settings_screen_supported()`.
18 */
19final class Settings_Page {
20
21    /**
22     * Submenu slug. Unchanged from when sharedaddy registered this screen, so
23     * existing links and bookmarks keep working.
24     */
25    public const SLUG = 'sharing';
26
27    /**
28     * Hook the screen up.
29     */
30    public static function init(): void {
31        add_action( 'admin_menu', array( __CLASS__, 'register_menu' ) );
32    }
33
34    /**
35     * Add the submenu entry under Settings.
36     */
37    public static function register_menu(): void {
38        if ( ! Environment::settings_screen_supported() ) {
39            return;
40        }
41
42        add_submenu_page(
43            'options-general.php',
44            __( 'Sharing Settings', 'jetpack-sharing-likes' ),
45            __( 'Sharing', 'jetpack-sharing-likes' ),
46            'manage_options',
47            self::SLUG,
48            array( __CLASS__, 'render' )
49        );
50    }
51
52    /**
53     * Render whichever sections apply, ruled off from one another, then the
54     * one Save button that covers them all.
55     */
56    private static function render_sections(): void {
57        // The submenu registers against this too. Repeated here because the sections
58        // mint the nonces that authorise every save, and the screen is public API.
59        if ( ! current_user_can( 'manage_options' ) ) {
60            return;
61        }
62
63        $sections = array(
64            array( Sharing_Section::class, 'render' ),
65            array( Likes_Section::class, 'render' ),
66        );
67
68        $sharing_state = Sharing_Section::state();
69
70        if ( Section_State::shows_placement( $sharing_state, Likes_Section::state() ) ) {
71            $sections[] = array( Placement_Section::class, 'render' );
72        }
73
74        if ( ! Section_State::configures( $sharing_state ) ) {
75            $sections[] = array( Extras_Section::class, 'render' );
76        }
77
78        $rendered = 0;
79
80        foreach ( $sections as $section ) {
81            ob_start();
82            call_user_func( $section );
83            $markup = trim( (string) ob_get_clean() );
84
85            // A section can decline to render, and a rule with nothing after it is worse than no rule.
86            if ( '' === $markup ) {
87                continue;
88            }
89
90            if ( $rendered > 0 ) {
91                echo '<hr />';
92            }
93
94            echo $markup; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- each section escapes its own output.
95            ++$rendered;
96        }
97
98        Settings_Form::render();
99    }
100
101    /**
102     * Confirm a save, when one just happened.
103     */
104    private static function render_saved_notice(): void {
105        // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- only decides whether to print a confirmation.
106        if ( ! isset( $_GET['update'] ) || 'saved' !== $_GET['update'] ) {
107            return;
108        }
109
110        printf(
111            '<div class="updated"><p>%s</p></div>',
112            esc_html__( 'Settings have been saved', 'jetpack-sharing-likes' )
113        );
114    }
115
116    /**
117     * Warn when PHP has no mbstring extension.
118     *
119     * Sharing sources fall back to byte-wise string functions without it, which
120     * can cut multibyte text mid-character when a service truncates it.
121     */
122    private static function render_multibyte_warning(): void {
123        if ( function_exists( 'mb_stripos' ) ) {
124            return;
125        }
126
127        printf(
128            '<div class="notice notice-warning"><p><strong>%1$s</strong></p><p>%2$s</p></div>',
129            esc_html__( 'Warning! Multibyte support missing!', 'jetpack-sharing-likes' ),
130            wp_kses(
131                sprintf(
132                    /* translators: placeholder is a link to a PHP support document. */
133                    __( 'This plugin will work without it, but multibyte support is used <a href="%s" rel="noopener noreferrer" target="_blank">if available</a>. You may see minor problems with Tweets and other sharing services.', 'jetpack-sharing-likes' ),
134                    'https://www.php.net/manual/en/mbstring.installation.php'
135                ),
136                array(
137                    'a' => array(
138                        'href'   => array(),
139                        'rel'    => array(),
140                        'target' => array(),
141                    ),
142                )
143            )
144        );
145    }
146
147    /**
148     * Render the screen.
149     */
150    public static function render(): void {
151        ?>
152        <div class="wrap">
153            <h1><?php esc_html_e( 'Sharing Settings', 'jetpack-sharing-likes' ); ?></h1>
154            <?php
155            self::render_multibyte_warning();
156            self::render_saved_notice();
157
158            /**
159             * Fires at the top of the admin sharing settings screen.
160             *
161             * @module sharedaddy
162             *
163             * @since jetpack-1.6.0
164             */
165            do_action( 'pre_admin_screen_sharing' );
166
167            self::render_sections();
168            ?>
169        </div>
170        <?php
171    }
172}