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