Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
95.15% covered (success)
95.15%
157 / 165
88.89% covered (success)
88.89%
8 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
PlayerColors
95.15% covered (success)
95.15%
157 / 165
88.89% covered (success)
88.89%
8 / 9
19
0.00% covered (danger)
0.00%
0 / 1
 init
55.56% covered (danger)
55.56%
10 / 18
0.00% covered (danger)
0.00%
0 / 1
1.09
 addPlayerThemeSetting
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
1
 addPlayerColorsSetting
100.00% covered (success)
100.00%
45 / 45
100.00% covered (success)
100.00%
1 / 1
1
 renderPlayerThemeSetting
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
2
 sanitizeColorsArray
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
6
 sanitizeColor
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 getPlayerThemeOptions
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
1
 renderPlayerColorsSetting
100.00% covered (success)
100.00%
18 / 18
100.00% covered (success)
100.00%
1 / 1
1
 playerColorsTable
100.00% covered (success)
100.00%
30 / 30
100.00% covered (success)
100.00%
1 / 1
4
1<?php
2
3declare(strict_types=1);
4
5/**
6 * Setting: Player colors
7 *
8 * @package Beyondwords\Wordpress
9 * @author  Stuart McAlpine <stu@beyondwords.io>
10 * @since   5.0.0
11 */
12
13namespace Beyondwords\Wordpress\Component\Settings\Fields\PlayerColors;
14
15use Beyondwords\Wordpress\Component\Settings\SettingsUtils;
16use Beyondwords\Wordpress\Component\Settings\Sync;
17
18/**
19 * PlayerColors
20 *
21 * @since 5.0.0
22 */
23class PlayerColors
24{
25    /**
26     * Option name.
27     */
28    public const OPTION_NAME_THEME = 'beyondwords_player_theme';
29
30    /**
31     * Option name.
32     */
33    public const OPTION_NAME_LIGHT_THEME = 'beyondwords_player_theme_light';
34
35    /**
36     * Option name.
37     */
38    public const OPTION_NAME_DARK_THEME = 'beyondwords_player_theme_dark';
39
40    /**
41     * Option name.
42     */
43    public const OPTION_NAME_VIDEO_THEME = 'beyondwords_player_theme_video';
44
45    /**
46     * Init.
47     *
48     * @since 5.0.0
49     * @since 6.0.0 Make static.
50     */
51    public static function init()
52    {
53        add_action('admin_init', [self::class, 'addPlayerThemeSetting']);
54        add_action('admin_init', [self::class, 'addPlayerColorsSetting']);
55        add_action('pre_update_option_' . self::OPTION_NAME_THEME, function ($value) {
56            Sync::syncOptionToDashboard(self::OPTION_NAME_THEME);
57            return $value;
58        });
59        add_action('pre_update_option_' . self::OPTION_NAME_LIGHT_THEME, function ($value) {
60            Sync::syncOptionToDashboard(self::OPTION_NAME_LIGHT_THEME);
61            return $value;
62        });
63        add_action('pre_update_option_' . self::OPTION_NAME_DARK_THEME, function ($value) {
64            Sync::syncOptionToDashboard(self::OPTION_NAME_DARK_THEME);
65            return $value;
66        });
67        add_action('pre_update_option_' . self::OPTION_NAME_VIDEO_THEME, function ($value) {
68            Sync::syncOptionToDashboard(self::OPTION_NAME_VIDEO_THEME);
69            return $value;
70        });
71    }
72
73    /**
74     * Init "Player color" setting.
75     *
76     * @since 5.0.0
77     * @since 6.0.0 Make static.
78     *
79     * @return void
80     */
81    public static function addPlayerThemeSetting()
82    {
83        register_setting(
84            'beyondwords_player_settings',
85            self::OPTION_NAME_THEME,
86            [
87                'default' => '',
88            ]
89        );
90
91        add_settings_field(
92            'beyondwords-player-theme',
93            __('Player theme', 'speechkit'),
94            [self::class, 'renderPlayerThemeSetting'],
95            'beyondwords_player',
96            'styling'
97        );
98    }
99
100    /**
101     * Init "Player colors" setting.
102     *
103     * @since 5.0.0
104     * @since 6.0.0 Make static.
105     *
106     * @return void
107     */
108    public static function addPlayerColorsSetting()
109    {
110        register_setting(
111            'beyondwords_player_settings',
112            self::OPTION_NAME_LIGHT_THEME,
113            [
114                'default' => [
115                    'background_color' => '#f5f5f5',
116                    'icon_color'       => '#000',
117                    'text_color'       => '#111',
118                    'highlight_color'  => '#eee',
119                ],
120                'sanitize_callback' => [self::class, 'sanitizeColorsArray'],
121            ]
122        );
123
124        register_setting(
125            'beyondwords_player_settings',
126            self::OPTION_NAME_DARK_THEME,
127            [
128                'default' => [
129                    'background_color' => '#f5f5f5',
130                    'icon_color'       => '#000',
131                    'text_color'       => '#111',
132                    'highlight_color'  => '#eee',
133                ],
134                'sanitize_callback' => [self::class, 'sanitizeColorsArray'],
135            ]
136        );
137
138        register_setting(
139            'beyondwords_player_settings',
140            self::OPTION_NAME_VIDEO_THEME,
141            [
142                'default' => [
143                    'background_color' => '#000',
144                    'icon_color'       => '#fff',
145                    'text_color'       => '#fff',
146                ],
147                'sanitize_callback' => [self::class, 'sanitizeColorsArray'],
148            ]
149        );
150
151        add_settings_field(
152            'beyondwords-player-colors',
153            __('Player colors', 'speechkit'),
154            [self::class, 'renderPlayerColorsSetting'],
155            'beyondwords_player',
156            'styling'
157        );
158    }
159
160    /**
161     * Render setting field.
162     *
163     * @since 5.0.0
164     * @since 6.0.0 Make static.
165     *
166     * @return string
167     **/
168    public static function renderPlayerThemeSetting()
169    {
170        $current = get_option(self::OPTION_NAME_THEME);
171        $themeOptions = self::getPlayerThemeOptions();
172        ?>
173        <div class="beyondwords-setting__player beyondwords-setting__player--player-colors">
174            <select name="<?php echo esc_attr(self::OPTION_NAME_THEME) ?>">
175                <?php
176                foreach ($themeOptions as $option) {
177                    printf(
178                        '<option value="%s" %s>%s</option>',
179                        esc_attr($option['value']),
180                        selected($option['value'], $current),
181                        esc_html($option['label'])
182                    );
183                }
184                ?>
185            </select>
186        </div>
187        <?php
188    }
189
190    /**
191     * Sanitise the colors array setting value.
192     *
193     * @since 5.0.0
194     * @since 6.0.0 Make static.
195     *
196     * @param array $value The submitted value.
197     *
198     * @return array The sanitized value.
199     **/
200    public static function sanitizeColorsArray($value)
201    {
202        if (!is_array($value)) {
203            return [];
204        }
205
206        $value['background_color'] = self::sanitizeColor($value['background_color'] ?: '');
207        $value['text_color']       = self::sanitizeColor($value['text_color']       ?: '');
208        $value['icon_color']       = self::sanitizeColor($value['icon_color']       ?: '');
209
210        // Highlight doesn't exist for video player
211        if (!empty($value['highlight_color'])) {
212            $value['highlight_color'] = self::sanitizeColor($value['highlight_color']);
213        }
214
215        return $value;
216    }
217
218    /**
219     * Sanitize an individual color value.
220     *
221     * @since 5.0.0
222     * @since 6.0.0 Make static.
223     *
224     * @param string $value The submitted individual color value.
225     *
226     * @return array The sanitized value.
227     **/
228    public static function sanitizeColor($value)
229    {
230        $value = strtolower(trim((string)$value));
231
232        // Prepend hash to hexidecimal values, if missing
233        if (preg_match("/^[0-9a-f]+$/", $value)) {
234            $value = '#' . $value;
235        }
236
237        return $value;
238    }
239
240    /**
241     * Get all options for the current component.
242     *
243     * @since 5.0.0
244     * @since 6.0.0 Make static.
245     *
246     * @return string[] Associative array of player theme options.
247     **/
248    public static function getPlayerThemeOptions()
249    {
250        return [
251            [
252                'value' => 'light',
253                'label' => 'Light (default)',
254            ],
255            [
256                'value' => 'dark',
257                'label' => 'Dark',
258            ],
259            [
260                'value' => 'auto',
261                'label' => 'Auto',
262            ],
263        ];
264    }
265
266    /**
267     * Render setting field.
268     *
269     * @since 5.0.0
270     * @since 6.0.0 Make static.
271     *
272     * @return string
273     **/
274    public static function renderPlayerColorsSetting()
275    {
276        $lightTheme = get_option(self::OPTION_NAME_LIGHT_THEME);
277        $darkTheme  = get_option(self::OPTION_NAME_DARK_THEME);
278        $videoTheme = get_option(self::OPTION_NAME_VIDEO_THEME);
279
280        self::playerColorsTable(
281            __('Light theme settings', 'speechkit'),
282            self::OPTION_NAME_LIGHT_THEME,
283            $lightTheme,
284        );
285
286        self::playerColorsTable(
287            __('Dark theme settings', 'speechkit'),
288            self::OPTION_NAME_DARK_THEME,
289            $darkTheme,
290        );
291
292        self::playerColorsTable(
293            __('Video theme settings', 'speechkit'),
294            self::OPTION_NAME_VIDEO_THEME,
295            $videoTheme,
296        );
297    }
298
299    /**
300     * A player colors table.
301     *
302     * @since 5.0.0
303     * @since 6.0.0 Make static.
304     *
305     * @return string
306     **/
307    public static function playerColorsTable($title, $name, $value)
308    {
309        ?>
310        <h3 class="subheading">
311            <?php echo esc_html($title); ?>
312        </h3>
313        <div class="color-pickers">
314            <div class="row">
315                <?php
316                SettingsUtils::colorInput(
317                    __('Background', 'speechkit'),
318                    sprintf('%s[background_color]', $name),
319                    $value['background_color'] ?: ''
320                );
321                ?>
322            </div>
323            <div class="row">
324                <?php
325                SettingsUtils::colorInput(
326                    __('Icons', 'speechkit'),
327                    sprintf('%s[icon_color]', $name),
328                    $value['icon_color'] ?: ''
329                );
330                ?>
331            </div>
332            <div class="row">
333                <?php
334                SettingsUtils::colorInput(
335                    __('Text color', 'speechkit'),
336                    sprintf('%s[text_color]', $name),
337                    $value['text_color'] ?: ''
338                );
339                ?>
340            </div>
341        </div>
342        <?php
343    }
344}