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