Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
79.25% covered (warning)
79.25%
42 / 53
40.00% covered (danger)
40.00%
2 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
PlayerStyle
79.25% covered (warning)
79.25%
42 / 53
40.00% covered (danger)
40.00%
2 / 5
15.75
0.00% covered (danger)
0.00%
0 / 1
 init
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
3
 element
100.00% covered (success)
100.00%
24 / 24
100.00% covered (success)
100.00%
1 / 1
2
 save
78.57% covered (warning)
78.57%
11 / 14
0.00% covered (danger)
0.00%
0 / 1
7.48
 restApiInit
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 playerStylesRestApiResponse
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3declare(strict_types=1);
4
5/**
6 * BeyondWords Component: Player style
7 *
8 * @package Beyondwords\Wordpress
9 * @author  Stuart McAlpine <stu@beyondwords.io>
10 * @since   4.1.0
11 */
12
13namespace Beyondwords\Wordpress\Component\Post\PlayerStyle;
14
15use Beyondwords\Wordpress\Component\Post\PostMetaUtils;
16use Beyondwords\Wordpress\Component\Settings\Fields\PlayerStyle\PlayerStyle as PlayerStyleSetting;
17use Beyondwords\Wordpress\Component\Settings\SettingsUtils;
18
19/**
20 * PlayerStyle
21 *
22 * @since 4.1.0
23 */
24class PlayerStyle
25{
26    /**
27     * Player styles.
28     *
29     * @var array Arry of player styles.
30     */
31    public const PLAYER_STYLES = [
32        'small',
33        'standard',
34        'large',
35        'screen',
36        'video',
37    ];
38
39    /**
40     * Constructor
41     *
42     * @since 6.0.0 Make static.
43     */
44    public static function init()
45    {
46        add_action('rest_api_init', [self::class, 'restApiInit']);
47
48        add_action('wp_loaded', function (): void {
49            $postTypes = SettingsUtils::getCompatiblePostTypes();
50
51            if (is_array($postTypes)) {
52                foreach ($postTypes as $postType) {
53                    add_action("save_post_{$postType}", [self::class, 'save'], 10);
54                }
55            }
56        });
57    }
58
59    /**
60     * HTML output for this component.
61     *
62     * @since 4.1.0
63     * @since 4.5.1 Hide element if no language data exists.
64     * @since 6.0.0 Make static.
65     *
66     * @param \WP_Post $post The post object.
67     *
68     * @return string|null
69     */
70    public static function element($post)
71    {
72        $playerStyle     = PostMetaUtils::getPlayerStyle($post->ID);
73        $allPlayerStyles = PlayerStyleSetting::getOptions();
74
75        wp_nonce_field('beyondwords_player_style', 'beyondwords_player_style_nonce');
76        ?>
77        <p
78            id="beyondwords-metabox-player-style"
79            class="post-attributes-label-wrapper page-template-label-wrapper"
80        >
81            <label class="post-attributes-label" for="beyondwords_player_style">
82                <?php esc_html_e('Player style', 'speechkit'); ?>
83            </label>
84        </p>
85        <select id="beyondwords_player_style" name="beyondwords_player_style" style="width: 100%;">
86            <option value=""></option>
87            <?php
88            foreach ($allPlayerStyles as $item) {
89                printf(
90                    '<option value="%s" %s %s>%s</option>',
91                    esc_attr($item['value']),
92                    selected(strval($item['value']), $playerStyle),
93                    disabled($item['disabled'] ?? false, true),
94                    esc_html($item['label'])
95                );
96            }
97            ?>
98        </select>
99        <?php
100    }
101
102    /**
103     * Save the meta when the post is saved.
104     *
105     * @since 4.1.0
106     * @since 6.0.0 Make static.
107     *
108     * @param int $postId The ID of the post being saved.
109     */
110    public static function save($postId)
111    {
112        if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
113            return $postId;
114        }
115
116        // "save_post" can be triggered at other times, so verify this request came from the our component
117        if (! isset($_POST['beyondwords_player_style']) || ! isset($_POST['beyondwords_player_style_nonce'])) {
118            return $postId;
119        }
120
121        // "save_post" can be triggered at other times, so verify this request came from the our component
122        if (
123            ! wp_verify_nonce(
124                sanitize_key($_POST['beyondwords_player_style_nonce']),
125                'beyondwords_player_style'
126            )
127        ) {
128            return $postId;
129        }
130
131        $playerStyle = sanitize_text_field(wp_unslash($_POST['beyondwords_player_style']));
132
133        if (! empty($playerStyle)) {
134            update_post_meta($postId, 'beyondwords_player_style', $playerStyle);
135        } else {
136            delete_post_meta($postId, 'beyondwords_player_style');
137        }
138
139        return $postId;
140    }
141
142    /**
143     * Register WP REST API route
144     *
145     * @since 4.1.0
146     * @since 6.0.0 Make static.
147     *
148     * @return void
149     */
150    public static function restApiInit()
151    {
152        // Player styles endpoint
153        register_rest_route('beyondwords/v1', '/projects/(?P<projectId>[0-9]+)/player-styles', [
154            'methods'  => \WP_REST_Server::READABLE,
155            'callback' => [self::class, 'playerStylesRestApiResponse'],
156            'permission_callback' => fn() => current_user_can('edit_posts'),
157        ]);
158    }
159
160    /**
161     * "Player styles" WP REST API response (required for the Gutenberg editor).
162     *
163     * @since 4.1.0
164     * @since 5.0.0 Stop saving a dedicated player styles transient for each project ID.
165     * @since 6.0.0 Make static.
166     */
167    public static function playerStylesRestApiResponse()
168    {
169        $response = PlayerStyleSetting::getOptions();
170
171        // Convert from object to array so we can use find() in Block Editor JS.
172        $response = array_values($response);
173
174        return new \WP_REST_Response($response);
175    }
176}