Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
95.00% covered (success)
95.00%
190 / 200
81.82% covered (success)
81.82%
9 / 11
CRAP
0.00% covered (danger)
0.00%
0 / 1
SiteHealth
95.00% covered (success)
95.00%
190 / 200
81.82% covered (success)
81.82%
9 / 11
34
0.00% covered (danger)
0.00%
0 / 1
 init
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 debugInformation
100.00% covered (success)
100.00%
31 / 31
100.00% covered (success)
100.00%
1 / 1
1
 addContentSettings
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
1 / 1
7
 addProjectSettings
100.00% covered (success)
100.00%
24 / 24
100.00% covered (success)
100.00%
1 / 1
1
 addPlayerSettings
100.00% covered (success)
100.00%
50 / 50
100.00% covered (success)
100.00%
1 / 1
5
 addPluginVersion
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
1 / 1
4
 addRestApiConnection
64.00% covered (warning)
64.00%
16 / 25
0.00% covered (danger)
0.00%
0 / 1
2.19
 addFilters
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
5
 addNoticeSettings
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
1
 addConstant
90.00% covered (success)
90.00%
9 / 10
0.00% covered (danger)
0.00%
0 / 1
4.02
 maskString
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2
3declare(strict_types=1);
4
5/**
6 * BeyondWords SiteHealth.
7 *
8 * @package Beyondwords\Wordpress
9 * @author  Stuart McAlpine <stu@beyondwords.io>
10 * @since   3.7.0
11 */
12
13namespace Beyondwords\Wordpress\Component\SiteHealth;
14
15use Beyondwords\Wordpress\Component\Settings\Fields\IntegrationMethod\IntegrationMethod;
16use Beyondwords\Wordpress\Component\Settings\SettingsUtils;
17use Beyondwords\Wordpress\Core\Environment;
18
19/**
20 * BeyondWords SiteHealth.
21 *
22 * @since 3.7.0
23 */
24defined('ABSPATH') || exit;
25
26class SiteHealth
27{
28    /**
29     * @var string[] List of current filters to check.
30     *
31     * @since  3.7.0 Introduced.
32     * @since  4.3.0 Filters refactoring - many were removed and renamed.
33     */
34    public const FILTERS = [
35        'beyondwords_content_params',
36        'beyondwords_player_script_onload',
37        'beyondwords_player_html',
38        'beyondwords_player_sdk_params',
39        'beyondwords_settings_player_styles',
40        'beyondwords_settings_post_types',
41        'beyondwords_settings_post_statuses',
42    ];
43
44    /**
45     * @var string[] List of deprecated filters to check.
46     *
47     * @since  3.7.0 Introduced.
48     * @since  4.3.0 Filters refactoring - many were removed and renamed.
49     */
50    public const DEPRECATED_FILTERS = [
51        'beyondwords_amp_player_html',
52        'beyondwords_body_params',
53        'beyondwords_content',
54        'beyondwords_content_id',
55        'beyondwords_js_player_html',
56        'beyondwords_js_player_params',
57        'beyondwords_player_styles',
58        'beyondwords_post_audio_enabled_blocks',
59        'beyondwords_post_metadata',
60        'beyondwords_post_player_enabled',
61        'beyondwords_post_statuses',
62        'beyondwords_post_types',
63        'beyondwords_project_id',
64        'sk_player_after',
65        'sk_player_before',
66        'sk_the_content',
67        'speechkit_amp_player_html',
68        'speechkit_content',
69        'speechkit_js_player_html',
70        'speechkit_js_player_params',
71        'speechkit_post_player_enabled',
72        'speechkit_post_statuses',
73        'speechkit_post_types',
74    ];
75
76    /**
77     * Init
78     *
79     * @since 4.0.0
80     * @since 6.0.0 Make static.
81     */
82    public static function init()
83    {
84        add_filter('debug_information', [self::class, 'debugInformation']);
85    }
86
87    /**
88     * Add "Site Health" navigation tab.
89     *
90     * @since 3.7.0
91     * @since 6.0.0 Make static.
92     *
93     *
94     */
95    public static function debugInformation($info)
96    {
97        $info['beyondwords']['label'] = __('BeyondWords - Text-to-Speech', 'speechkit');
98
99        self::addPluginVersion($info);
100        self::addRestApiConnection($info);
101
102        $info['beyondwords']['fields']['compatible-post-types'] = [
103            'label' => __('Compatible post types', 'speechkit'),
104            'value' => implode(', ', SettingsUtils::getCompatiblePostTypes()),
105        ];
106
107        $info['beyondwords']['fields']['incompatible-post-types'] = [
108            'label' => __('Incompatible post types', 'speechkit'),
109            'value' => implode(', ', SettingsUtils::getIncompatiblePostTypes()),
110        ];
111
112        $info['beyondwords']['fields']['integration-method'] = [
113            'label' => __('Integration method', 'speechkit'),
114            'value' => IntegrationMethod::getIntegrationMethod(),
115        ];
116
117        $info['beyondwords']['fields']['beyondwords_api_key'] = [
118            'label' => __('API Key', 'speechkit'),
119            'value' => SiteHealth::maskString(get_option('beyondwords_api_key')),
120        ];
121
122        $info['beyondwords']['fields']['beyondwords_project_id'] = [
123            'label' => __('Project ID', 'speechkit'),
124            'value' => get_option('beyondwords_project_id'),
125        ];
126
127        self::addContentSettings($info);
128        self::addProjectSettings($info);
129        self::addPlayerSettings($info);
130        self::addFilters($info);
131        self::addNoticeSettings($info);
132
133        self::addConstant($info, 'BEYONDWORDS_AUTO_SYNC_SETTINGS');
134        self::addConstant($info, 'BEYONDWORDS_AUTOREGENERATE');
135
136        return $info;
137    }
138
139    /**
140     * Add content settings to the info debugging array.
141     *
142     * @since 5.0.0
143     * @since 6.0.0 Make static.
144     *
145     * @param array $info Debugging info array
146     */
147    public static function addContentSettings(array &$info): void
148    {
149        $info['beyondwords']['fields']['beyondwords_project_title_enabled'] = [
150            'label' => __('Include title in audio', 'speechkit'),
151            'value' => get_option('beyondwords_project_title_enabled') ? __('Yes', 'speechkit') : __('No', 'speechkit'), // phpcs:ignore Generic.Files.LineLength.TooLong
152            'debug' => get_option('beyondwords_project_title_enabled') ? 'yes' : 'no',
153        ];
154
155        $info['beyondwords']['fields']['beyondwords_project_auto_publish_enabled'] = [
156            'label' => __('Auto-publish audio', 'speechkit'),
157            'value' => get_option('beyondwords_project_auto_publish_enabled') ? __('Yes', 'speechkit') : __('No', 'speechkit'), // phpcs:ignore Generic.Files.LineLength.TooLong
158            'debug' => get_option('beyondwords_project_auto_publish_enabled') ? 'yes' : 'no',
159        ];
160
161        $info['beyondwords']['fields']['beyondwords_prepend_excerpt'] = [
162            'label' => __('Include excerpts in audio', 'speechkit'),
163            'value' => get_option('beyondwords_prepend_excerpt') ? __('Yes', 'speechkit') : __('No', 'speechkit'), // phpcs:ignore Generic.Files.LineLength.TooLong
164            'debug' => get_option('beyondwords_prepend_excerpt') ? 'yes' : 'no',
165        ];
166
167        $info['beyondwords']['fields']['beyondwords_preselect'] = [
168            'label' => __('Preselect â€˜Generate audio’', 'speechkit'),
169            'value' => (string) wp_json_encode(get_option('beyondwords_preselect'), JSON_PRETTY_PRINT),
170        ];
171    }
172
173    /**
174     * Add project settings to the info debugging array.
175     *
176     * @since 5.0.0
177     * @since 6.0.0 Make static.
178     *
179     * @param array $info Debugging info array
180     */
181    public static function addProjectSettings(array &$info): void
182    {
183        $info['beyondwords']['fields']['beyondwords_project_language_code'] = [
184            'label' => __('Default language code', 'speechkit'),
185            'value' => get_option('beyondwords_project_language_code'),
186        ];
187
188        $info['beyondwords']['fields']['beyondwords_project_language_id'] = [
189            'label' => __('Default language ID', 'speechkit'),
190            'value' => get_option('beyondwords_project_language_id'),
191        ];
192
193        $info['beyondwords']['fields']['beyondwords_project_title_voice_id'] = [
194            'label' => __('Title voice ID', 'speechkit'),
195            'value' => get_option('beyondwords_project_title_voice_id'),
196        ];
197
198        $info['beyondwords']['fields']['beyondwords_project_title_voice_speaking_rate'] = [
199            'label' => __('Title voice speaking rate', 'speechkit'),
200            'value' => get_option('beyondwords_project_title_voice_speaking_rate'),
201        ];
202
203        $info['beyondwords']['fields']['beyondwords_project_body_voice_id'] = [
204            'label' => __('Body voice ID', 'speechkit'),
205            'value' => get_option('beyondwords_project_body_voice_id'),
206        ];
207
208        $info['beyondwords']['fields']['beyondwords_project_body_voice_speaking_rate'] = [
209            'label' => __('Body voice speaking rate', 'speechkit'),
210            'value' => get_option('beyondwords_project_body_voice_speaking_rate'),
211        ];
212    }
213
214    /**
215     * Add player settings to the info debugging array.
216     *
217     * @since 5.0.0
218     * @since 6.0.0 Make static.
219     *
220     * @param array $info Debugging info array
221     */
222    public static function addPlayerSettings(array &$info): void
223    {
224        $info['beyondwords']['fields']['beyondwords_player_ui'] = [
225            'label' => __('Player UI', 'speechkit'),
226            'value' => get_option('beyondwords_player_ui'),
227        ];
228
229        $info['beyondwords']['fields']['beyondwords_player_style'] = [
230            'label' => __('Player style', 'speechkit'),
231            'value' => get_option('beyondwords_player_style'),
232        ];
233
234        $info['beyondwords']['fields']['beyondwords_player_theme'] = [
235            'label' => __('Player theme', 'speechkit'),
236            'value' => get_option('beyondwords_player_theme'),
237        ];
238
239        $info['beyondwords']['fields']['beyondwords_player_theme_light'] = [
240            'label' => __('Light theme', 'speechkit'),
241            'value' => (string) wp_json_encode(get_option('beyondwords_player_theme_light'), JSON_PRETTY_PRINT),
242        ];
243
244        $info['beyondwords']['fields']['beyondwords_player_theme_dark'] = [
245            'label' => __('Dark theme', 'speechkit'),
246            'value' => (string) wp_json_encode(get_option('beyondwords_player_theme_dark'), JSON_PRETTY_PRINT),
247        ];
248
249        $info['beyondwords']['fields']['beyondwords_player_theme_video'] = [
250            'label' => __('Video theme', 'speechkit'),
251            'value' => (string) wp_json_encode(get_option('beyondwords_player_theme_video'), JSON_PRETTY_PRINT),
252        ];
253
254        $info['beyondwords']['fields']['beyondwords_player_call_to_action'] = [
255            'label' => __('Call-to-action', 'speechkit'),
256            'value' => get_option('beyondwords_player_call_to_action'),
257        ];
258
259        $info['beyondwords']['fields']['beyondwords_player_highlight_sections'] = [
260            'label' => __('Text highlighting', 'speechkit'),
261            'value' => get_option('beyondwords_player_highlight_sections') ? __('Yes', 'speechkit') : __('No', 'speechkit'), // phpcs:ignore Generic.Files.LineLength.TooLong
262            'debug' => get_option('beyondwords_player_highlight_sections') ? 'yes' : 'no',
263        ];
264
265        $info['beyondwords']['fields']['beyondwords_player_clickable_sections'] = [
266            'label' => __('Playback from segments', 'speechkit'),
267            'value' => get_option('beyondwords_player_clickable_sections') ? __('Yes', 'speechkit') : __('No', 'speechkit'), // phpcs:ignore Generic.Files.LineLength.TooLong
268            'debug' => get_option('beyondwords_player_clickable_sections') ? 'yes' : 'no',
269        ];
270
271        $info['beyondwords']['fields']['beyondwords_player_widget_style'] = [
272            'label' => __('Widget style', 'speechkit'),
273            'value' => get_option('beyondwords_player_widget_style'),
274        ];
275
276        $info['beyondwords']['fields']['beyondwords_player_widget_position'] = [
277            'label' => __('Widget position', 'speechkit'),
278            'value' => get_option('beyondwords_player_widget_position'),
279        ];
280
281        $info['beyondwords']['fields']['beyondwords_player_skip_button_style'] = [
282            'label' => __('Skip button style', 'speechkit'),
283            'value' => get_option('beyondwords_player_skip_button_style'),
284        ];
285    }
286
287    /**
288     * Add plugin version to the info debugging array.
289     *
290     * @since 3.7.0
291     * @since 6.0.0 Make static.
292     *
293     * @param array  $info Debugging info array
294     *
295     * @return array
296     */
297    public static function addPluginVersion(&$info)
298    {
299        $constVersion = defined('BEYONDWORDS__PLUGIN_VERSION') ? BEYONDWORDS__PLUGIN_VERSION : '';
300        $dbVersion    = get_option('beyondwords_version');
301
302        if ($constVersion && $constVersion === $dbVersion) {
303            $info['beyondwords']['fields']['plugin-version'] = [
304                'label' => __('Plugin version', 'speechkit'),
305                'value' => BEYONDWORDS__PLUGIN_VERSION,
306            ];
307        } else {
308            $info['beyondwords']['fields']['plugin-version'] = [
309                'label' => __('Plugin version', 'speechkit'),
310                'value' => sprintf(
311                    /* translators: 1: Current plugin version, 2: Database plugin version */
312                    __('Version mismatch: file: %1$s / db: %2$s', 'speechkit'),
313                    $constVersion,
314                    $dbVersion
315                ),
316            ];
317        }
318    }
319
320    /**
321     * Adds debugging data for the BeyondWords REST API connection.
322     *
323     * @since 3.7.0
324     * @since 5.2.2 Remove sslverify param for REST API calls.
325     * @since 6.0.0 Make static.
326     *
327     * @param array  $info Debugging info array
328     *
329     * @return array
330     */
331    public static function addRestApiConnection(&$info)
332    {
333        // translators: Tab heading for Site Health navigation.
334        $apiUrl = Environment::getApiUrl();
335
336        $info['beyondwords']['fields']['api-url'] = [
337            'label' => __('REST API URL', 'speechkit'),
338            'value' => $apiUrl,
339        ];
340
341        $response = wp_remote_request(Environment::getApiUrl(), [
342            'blocking'    => true,
343            'body'        => '',
344            'method'      => 'GET',
345        ]);
346
347        if (! is_wp_error($response)) {
348            $info['beyondwords']['fields']['api-communication'] = [
349                'label' => __('Communication with REST API', 'speechkit'),
350                'value' => __('BeyondWords API is reachable', 'speechkit'),
351                'debug' => 'true',
352            ];
353        } else {
354            $info['beyondwords']['fields']['api-communication'] = [
355                'label' => __('Communication with REST API', 'speechkit'),
356                'value' => sprintf(
357                    /* translators: 1: The IP address the REST API resolves to. 2: The error returned by the lookup. */
358                    __('Unable to reach BeyondWords API at %1$s: %2$s', 'speechkit'),
359                    gethostbyname(Environment::getApiUrl()),
360                    $response->get_error_message()
361                ),
362                'debug' => $response->get_error_message(),
363            ];
364        }
365    }
366
367    /**
368     * Adds filters.
369     *
370     * @since 5.0.0
371     * @since 6.0.0 Make static.
372     *
373     * @param array $info Debugging info array
374     */
375    public static function addFilters(array &$info): void
376    {
377        $registered = array_values(array_filter(SiteHealth::FILTERS, 'has_filter'));
378
379        $info['beyondwords']['fields']['registered-filters'] = [
380            'label' => __('Registered filters', 'speechkit'),
381            'value' => empty($registered) ? __('None', 'speechkit') : implode(', ', $registered),
382            'debug' => empty($registered) ? 'none' : implode(', ', $registered),
383        ];
384
385        $registered = array_values(array_filter(SiteHealth::DEPRECATED_FILTERS, 'has_filter'));
386
387        $info['beyondwords']['fields']['registered-deprecated-filters'] = [
388            'label' => __('Registered deprecated filters', 'speechkit'),
389            'value' => empty($registered) ? __('None', 'speechkit') : implode(', ', $registered),
390            'debug' => empty($registered) ? 'none' : implode(', ', $registered),
391        ];
392    }
393
394    /**
395     * Add notice settings to the info debugging array.
396     *
397     * @since 5.4.0
398     * @since 6.0.0 Make static.
399     *
400     * @param array $info Debugging info array
401     */
402    public static function addNoticeSettings(array &$info): void
403    {
404        $info['beyondwords']['fields']['beyondwords_date_activated'] = [
405            'label' => __('Date Activated', 'speechkit'),
406            'value' => get_option('beyondwords_date_activated', ''),
407        ];
408
409        $info['beyondwords']['fields']['beyondwords_notice_review_dismissed'] = [
410            'label' => __('Review Notice Dismissed', 'speechkit'),
411            'value' => get_option('beyondwords_notice_review_dismissed', ''),
412        ];
413    }
414
415    /**
416     * Add a single constant to the debugging info array.
417     *
418     * @since 3.7.0
419     * @since 5.0.0 Handle boolean values.
420     * @since 6.0.0 Make static.
421     *
422     * @param array  $info Debugging info array
423     * @param string $name Constant name
424     */
425    public static function addConstant(array &$info, string $name): void
426    {
427        $value = __('Undefined', 'speechkit');
428
429        if (defined($name)) {
430            $value = constant($name);
431
432            if (is_bool($value)) {
433                // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_var_export
434                $value = (true === $value) ? 'True' : 'False';
435            }
436        }
437
438        $info['beyondwords']['fields'][$name] = [
439            'label' => $name,
440            'value' => $value,
441            'debug' => $value,
442        ];
443    }
444
445    /**
446     * Mask a sensitive string for display in Site Health.
447     *
448     * @since  3.7.0
449     * @static
450     *
451     * @param string $string
452     *
453     */
454    public static function maskString(string|false $string, int $count = 4, string $char = 'X'): string
455    {
456        if (! is_string($string)) {
457            return '';
458        }
459
460        if (strlen($string) < 8) {
461            return str_repeat($char, strlen($string));
462        } else {
463            return str_repeat($char, strlen($string) - $count) . substr($string, (-$count));
464        }
465    }
466}