Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
11.49% covered (danger)
11.49%
20 / 174
18.18% covered (danger)
18.18%
2 / 11
CRAP
0.00% covered (danger)
0.00%
0 / 1
Admin_Color_Schemes
11.49% covered (danger)
11.49%
20 / 174
18.18% covered (danger)
18.18%
2 / 11
217.36
0.00% covered (danger)
0.00%
0 / 1
 __construct
75.00% covered (warning)
75.00%
6 / 8
0.00% covered (danger)
0.00%
0 / 1
3.14
 register_admin_color_meta
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
1
 update_admin_color_permissions_check
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 get_admin_color_scheme_url
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 get_admin_color_scheme_names
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
2
 get_admin_color_scheme_name
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 register_admin_color_schemes
0.00% covered (danger)
0.00%
0 / 108
0.00% covered (danger)
0.00%
0 / 1
6
 show_deprecated_admin_color_scheme_notice
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
6
 move_admin_color_schemes_last
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
2
 enqueue_color_scheme_for_sidebar_notice
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
6
 disable_css_concat_for_color_schemes
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2/**
3 * Unifies admin color scheme selection across WP.com sites.
4 *
5 * @package automattic/jetpack-masterbar
6 */
7
8namespace Automattic\Jetpack\Masterbar;
9
10use Automattic\Jetpack\Status\Host;
11
12/**
13 * Unifies admin color scheme selection across WP.com sites.
14 *
15 * @phan-constructor-used-for-side-effects
16 */
17class Admin_Color_Schemes {
18
19    /**
20     * A list of core color schemes to override.
21     *
22     * @var array
23     */
24    const CORE_COLOR_SCHEMES = array( 'blue', 'coffee', 'ectoplasm', 'fresh', 'light', 'midnight', 'modern', 'ocean', 'sunrise' );
25
26    /**
27     * A list of WP.com color schemes that are now deprecated.
28     *
29     * @var array
30     */
31    const WPCOM_COLOR_SCHEMES = array( 'aquatic', 'classic-blue', 'classic-bright', 'classic-dark', 'contrast', 'nightfall', 'powder-snow', 'sakura', 'sunset' );
32
33    /**
34     * Admin_Color_Schemes constructor.
35     */
36    public function __construct() {
37        // We want to register the admin color schemes across all environments.
38        add_action( 'admin_init', array( $this, 'register_admin_color_schemes' ) );
39        add_action( 'admin_notices', array( $this, 'show_deprecated_admin_color_scheme_notice' ) );
40        add_action( 'admin_color_scheme_picker', array( $this, 'move_admin_color_schemes_last' ), 11 );
41        // We don't want to make the admin_color available in users REST API endpoint for Simple sites.
42        if ( false === ( new Host() )->is_wpcom_simple() ) {
43            add_action( 'rest_api_init', array( $this, 'register_admin_color_meta' ) );
44        }
45
46        if ( ( new Host() )->is_wpcom_platform() ) { // Simple and Atomic sites.
47            add_filter( 'css_do_concat', array( $this, 'disable_css_concat_for_color_schemes' ), 10, 2 );
48            add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_color_scheme_for_sidebar_notice' ) );
49        }
50    }
51
52    /**
53     * Makes admin_color available in users REST API endpoint.
54     */
55    public function register_admin_color_meta() {
56        register_meta(
57            'user',
58            'admin_color',
59            array(
60                'auth_callback' => array( $this, 'update_admin_color_permissions_check' ),
61                'description'   => __( 'Slug of the admin color scheme.', 'jetpack-masterbar' ),
62                'single'        => true,
63                'show_in_rest'  => array(
64                    'schema' => array( 'default' => 'fresh' ),
65                ),
66                'type'          => 'string',
67            )
68        );
69    }
70
71    /**
72     * Permission callback to edit the `admin_color` user meta.
73     *
74     * @param bool   $allowed   Whether the given user is allowed to edit this meta value.
75     * @param string $meta_key  Meta key. In this case `admin_color`.
76     * @param int    $object_id Queried user ID.
77     * @return bool
78     */
79    public function update_admin_color_permissions_check( $allowed, $meta_key, $object_id ) {
80        return current_user_can( 'edit_user', $object_id );
81    }
82
83    /**
84     * Get the admin color scheme URL based on the environment
85     *
86     * @param string $color_scheme  The color scheme to get the URL for.
87     * @param string $file          The file name (optional, default: colors.css).
88     * @return string
89     */
90    public function get_admin_color_scheme_url( $color_scheme, $file = 'colors.css' ) {
91        return plugins_url( '../../dist/admin-color-schemes/colors/' . $color_scheme . '/' . $file, __FILE__ );
92    }
93
94    /**
95     * Gets the translated names of the color schemes, keyed by slug.
96     *
97     * @return array
98     */
99    private function get_admin_color_scheme_names() {
100        return array(
101            'aquatic'        => __( 'Aquatic', 'jetpack-masterbar' ),
102            'classic-blue'   => __( 'Classic Blue', 'jetpack-masterbar' ),
103            'classic-bright' => __( 'Classic Bright', 'jetpack-masterbar' ),
104            'classic-dark'   => __( 'Classic Dark', 'jetpack-masterbar' ),
105            'contrast'       => __( 'Contrast', 'jetpack-masterbar' ),
106            'nightfall'      => __( 'Nightfall', 'jetpack-masterbar' ),
107            'powder-snow'    => __( 'Powder Snow', 'jetpack-masterbar' ),
108            'sakura'         => __( 'Sakura', 'jetpack-masterbar' ),
109            'sunset'         => __( 'Sunset', 'jetpack-masterbar' ),
110        );
111    }
112
113    /**
114     * Gets a color scheme's name, marked as deprecated.
115     *
116     * @param string $color_scheme The color scheme slug.
117     * @return string
118     */
119    private function get_admin_color_scheme_name( $color_scheme ) {
120        /* translators: %s: Admin color scheme name, e.g. "Aquatic". */
121        return sprintf( __( '%s (Deprecated)', 'jetpack-masterbar' ), $this->get_admin_color_scheme_names()[ $color_scheme ] );
122    }
123
124    /**
125     * Registers new admin color schemes
126     */
127    public function register_admin_color_schemes() {
128        global $_wp_admin_css_colors;
129
130        // Adds custom CSS overrides for Fresh
131        if ( isset( $_wp_admin_css_colors['fresh'] ) ) {
132            $fresh = $_wp_admin_css_colors['fresh'];
133            wp_admin_css_color(
134                'fresh',
135                $fresh->name,
136                $this->get_admin_color_scheme_url( 'fresh' ),
137                $fresh->colors,
138                $fresh->icon_colors
139            );
140        }
141
142        wp_admin_css_color(
143            'aquatic',
144            $this->get_admin_color_scheme_name( 'aquatic' ),
145            $this->get_admin_color_scheme_url( 'aquatic' ),
146            array( '#135e96', '#007e65', '#043959', '#c5d9ed' ),
147            array(
148                'base'    => '#c5d9ed',
149                'focus'   => '#fff',
150                'current' => '#01263a',
151            )
152        );
153
154        wp_admin_css_color(
155            'classic-blue',
156            $this->get_admin_color_scheme_name( 'classic-blue' ),
157            $this->get_admin_color_scheme_url( 'classic-blue' ),
158            array( '#135e96', '#b26200', '#dcdcde', '#646970' ),
159            array(
160                'base'    => '#646970',
161                'focus'   => '#2271b1',
162                'current' => '#fff',
163            )
164        );
165
166        wp_admin_css_color(
167            'classic-bright',
168            $this->get_admin_color_scheme_name( 'classic-bright' ),
169            $this->get_admin_color_scheme_url( 'classic-bright' ),
170            array( '#135e96', '#c9256e', '#ffffff', '#e9eff5' ),
171            array(
172                'base'    => '#646970',
173                'focus'   => '#1d2327',
174                'current' => '#0a4b78',
175            )
176        );
177
178        wp_admin_css_color(
179            'classic-dark',
180            $this->get_admin_color_scheme_name( 'classic-dark' ),
181            $this->get_admin_color_scheme_url( 'classic-dark' ),
182            array( '#101517', '#c9356e', '#32373c', '#0073aa' ),
183            array(
184                'base'    => '#a2aab2',
185                'focus'   => '#00b9eb',
186                'current' => '#fff',
187            )
188        );
189
190        wp_admin_css_color(
191            'contrast',
192            $this->get_admin_color_scheme_name( 'contrast' ),
193            $this->get_admin_color_scheme_url( 'contrast' ),
194            array( '#101517', '#ffffff', '#32373c', '#b4b9be' ),
195            array(
196                'base'    => '#1d2327',
197                'focus'   => '#fff',
198                'current' => '#fff',
199            )
200        );
201
202        wp_admin_css_color(
203            'nightfall',
204            $this->get_admin_color_scheme_name( 'nightfall' ),
205            $this->get_admin_color_scheme_url( 'nightfall' ),
206            array( '#00131c', '#043959', '#2271b1', '#9ec2e6' ),
207            array(
208                'base'    => '#9ec2e6',
209                'focus'   => '#fff',
210                'current' => '#fff',
211            )
212        );
213
214        wp_admin_css_color(
215            'powder-snow',
216            $this->get_admin_color_scheme_name( 'powder-snow' ),
217            $this->get_admin_color_scheme_url( 'powder-snow' ),
218            array( '#101517', '#2271b1', '#dcdcde', '#646970' ),
219            array(
220                'base'    => '#646970',
221                'focus'   => '#135e96',
222                'current' => '#fff',
223            )
224        );
225
226        wp_admin_css_color(
227            'sakura',
228            $this->get_admin_color_scheme_name( 'sakura' ),
229            $this->get_admin_color_scheme_url( 'sakura' ),
230            array( '#005042', '#f2ceda', '#2271b1', '#8c1749' ),
231            array(
232                'base'    => '#8c1749',
233                'focus'   => '#4f092a',
234                'current' => '#fff',
235            )
236        );
237
238        wp_admin_css_color(
239            'sunset',
240            $this->get_admin_color_scheme_name( 'sunset' ),
241            $this->get_admin_color_scheme_url( 'sunset' ),
242            array( '#691c1c', '#b26200', '#f0c930', '#facfd2' ),
243            array(
244                'base'    => '#facfd2',
245                'focus'   => '#fff',
246                'current' => '#4f3500',
247            )
248        );
249    }
250
251    /**
252     * Asks users who still use a deprecated color scheme to switch to another one.
253     */
254    public function show_deprecated_admin_color_scheme_notice() {
255        $color_scheme = get_user_option( 'admin_color' );
256        if ( ! in_array( $color_scheme, static::WPCOM_COLOR_SCHEMES, true ) ) {
257            return;
258        }
259
260        wp_admin_notice(
261            sprintf(
262                /* translators: 1: Admin color scheme name, e.g. "Aquatic". 2: URL of the user profile page. */
263                __( 'Your current <strong>%1$s</strong> admin color scheme is now deprecated and will be removed soon. <a href="%2$s">Choose a different color scheme</a>.', 'jetpack-masterbar' ),
264                esc_html( $this->get_admin_color_scheme_names()[ $color_scheme ] ),
265                esc_url( admin_url( 'profile.php#color-picker' ) )
266            ),
267            array(
268                'type' => 'warning',
269            )
270        );
271    }
272
273    /**
274     * Moves the admin color schemes to the end of the color scheme picker.
275     */
276    public function move_admin_color_schemes_last() {
277        wp_print_inline_script_tag(
278            sprintf(
279                'document.addEventListener( "DOMContentLoaded", function () {
280                    var picker = document.getElementById( "color-picker" );
281                    if ( ! picker ) {
282                        return;
283                    }
284                    %s.forEach( function ( slug ) {
285                        var input = document.getElementById( "admin_color_" + slug );
286                        if ( input ) {
287                            picker.appendChild( input.parentNode );
288                        }
289                    } );
290                } );',
291                wp_json_encode( static::WPCOM_COLOR_SCHEMES, JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP )
292            )
293        );
294    }
295
296    /**
297     * Enqueues current color-scheme sidebar notice overrides for core color schemes
298     */
299    public function enqueue_color_scheme_for_sidebar_notice() {
300        $color_scheme = get_user_option( 'admin_color' );
301        if ( in_array( $color_scheme, static::CORE_COLOR_SCHEMES, true ) ) {
302            wp_enqueue_style(
303                'jetpack-core-color-schemes-overrides-sidebar-notice',
304                $this->get_admin_color_scheme_url( $color_scheme, 'sidebar-notice.css' ),
305                array(),
306                Main::PACKAGE_VERSION
307            );
308        }
309    }
310
311    /**
312     * Currently, the selected color scheme CSS (with id = "colors") is concatenated (by Jetpack Boost / Page Optimize),
313     * and is output before the default color scheme CSS, making it lose in specificity.
314     *
315     * To prevent this, we disable CSS concatenation for color schemes.
316
317     * @param boolean $do_concat  Whether to concat the CSS file.
318     * @param string  $handle     The file handle.
319     * @return boolean
320     */
321    public function disable_css_concat_for_color_schemes( $do_concat, $handle ) {
322        if ( $handle === 'colors' ) {
323            return false;
324        }
325        return $do_concat;
326    }
327}