PluginProbe
BeyondWords – AI audio for publishers / 4.7.0
BeyondWords – AI audio for publishers v4.7.0
7.1.0 trunk 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.0.5 4.0.6 4.1.0 4.1.1 4.1.2 4.2.0 4.2.1 4.2.2 4.2.3 4.2.4 4.3.0 4.4.0 4.5.0 4.5.1 4.6.0 4.6.1 4.6.2 4.7.0 All 43 releases
speechkit / src / Component / Post / SelectVoice / SelectVoice.php

SelectVoice.php in BeyondWords – AI audio for publishers 4.7.0, at src/Component/Post/SelectVoice/SelectVoice.php

351 lines 9.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 declare(strict_types=1);
4
5 /**
6 * BeyondWords Component: Select Voice
7 *
8 * @package Beyondwords\Wordpress
9 * @author Stuart McAlpine <stu@beyondwords.io>
10 * @since 4.0.0
11 */
12
13 namespace Beyondwords\Wordpress\Component\Post\SelectVoice;
14
15 use Beyondwords\Wordpress\Core\CoreUtils;
16 use Beyondwords\Wordpress\Component\Settings\Languages\Languages;
17 use Beyondwords\Wordpress\Component\Settings\SettingsUtils;
18
19 /**
20 * SelectVoice setup
21 *
22 * @since 4.0.0
23 */
24 class SelectVoice
25 {
26 /**
27 * API Client.
28 *
29 * @since 3.0.0
30 */
31 private $apiClient;
32
33 /**
34 * Constructor.
35 *
36 * @since 3.0.0
37 */
38 public function __construct($apiClient)
39 {
40 $this->apiClient = $apiClient;
41 }
42
43 /**
44 * Init.
45 *
46 * @since 4.0.0
47 */
48 public function init()
49 {
50 add_action('rest_api_init', array($this, 'restApiInit'));
51 add_action('admin_enqueue_scripts', array($this, 'adminEnqueueScripts'));
52
53 add_action('wp_loaded', function () {
54 $postTypes = SettingsUtils::getCompatiblePostTypes();
55
56 if (is_array($postTypes)) {
57 foreach ($postTypes as $postType) {
58 add_action("save_post_{$postType}", array($this, 'save'), 10);
59 }
60 }
61 });
62 }
63
64 /**
65 * HTML output for this component.
66 *
67 * @since 4.0.0
68 * @since 4.5.1 Hide element if no language data exists.
69 *
70 * @param WP_Post $post The post object.
71 *
72 * @return string|null
73 */
74 public function element($post)
75 {
76 if (! get_option('beyondwords_languages')) {
77 return;
78 }
79
80 $languages = $this->getFilteredLanguages();
81 $currentLanguageId = get_post_meta($post->ID, 'beyondwords_language_id', true);
82
83 $voices = $this->apiClient->getVoices($currentLanguageId);
84 $currentVoiceId = get_post_meta($post->ID, 'beyondwords_body_voice_id', true);
85
86 if (! is_array($voices)) {
87 $voices = [];
88 }
89
90 wp_nonce_field('beyondwords_select_voice', 'beyondwords_select_voice_nonce');
91 ?>
92 <p
93 id="beyondwords-metabox-select-voice--language-id"
94 class="post-attributes-label-wrapper page-template-label-wrapper"
95 >
96 <label class="post-attributes-label" for="beyondwords_language_id">
97 Language
98 </label>
99 </p>
100 <select id="beyondwords_language_id" name="beyondwords_language_id" style="width: 100%;">
101 <option value="">Project default</option>
102 <?php
103 foreach ($languages as $language) {
104 printf(
105 '<option value="%s" %s>%s</option>',
106 esc_attr($language['id']),
107 selected(strval($language['id']), $currentLanguageId),
108 esc_html($language['name'])
109 );
110 }
111 ?>
112 </select>
113 <p
114 id="beyondwords-metabox-select-voice--voice-id"
115 class="post-attributes-label-wrapper page-template-label-wrapper"
116 >
117 <label class="post-attributes-label" for="beyondwords_voice_id">
118 Voice
119 </label>
120 </p>
121 <select
122 id="beyondwords_voice_id"
123 name="beyondwords_voice_id"
124 style="width: 100%;"
125 <?php echo disabled(!strval($currentLanguageId)) ?>
126 >
127 <option value=""></option>
128 <?php
129 foreach ($voices as $voice) {
130 printf(
131 '<option value="%s" %s>%s</option>',
132 esc_attr($voice['id']),
133 selected(strval($voice['id']), $currentVoiceId),
134 esc_html($voice['name'])
135 );
136 }
137 ?>
138 </select>
139 <?php
140 }
141
142 /**
143 * Save the meta when the post is saved.
144 *
145 * @since 4.0.0
146 *
147 * @param int $postId The ID of the post being saved.
148 */
149 public function save($postId)
150 {
151 if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
152 return $postId;
153 }
154
155 // "save_post" can be triggered at other times, so verify this request came from the our component
156 if (
157 ! isset($_POST['beyondwords_language_id']) ||
158 ! isset($_POST['beyondwords_voice_id']) ||
159 ! isset($_POST['beyondwords_select_voice_nonce'])
160 ) {
161 return $postId;
162 }
163
164 // "save_post" can be triggered at other times, so verify this request came from the our component
165 if (
166 ! wp_verify_nonce(
167 sanitize_text_field($_POST['beyondwords_select_voice_nonce']),
168 'beyondwords_select_voice'
169 )
170 ) {
171 return $postId;
172 }
173
174 $languageId = sanitize_text_field($_POST['beyondwords_language_id']);
175
176 if (! empty($languageId)) {
177 update_post_meta($postId, 'beyondwords_language_id', $languageId);
178 } else {
179 delete_post_meta($postId, 'beyondwords_language_id');
180 }
181
182 $voiceId = sanitize_text_field($_POST['beyondwords_voice_id']);
183
184 if (! empty($voiceId)) {
185 update_post_meta($postId, 'beyondwords_body_voice_id', $voiceId);
186 update_post_meta($postId, 'beyondwords_title_voice_id', $voiceId);
187 update_post_meta($postId, 'beyondwords_summary_voice_id', $voiceId);
188 } else {
189 delete_post_meta($postId, 'beyondwords_body_voice_id');
190 delete_post_meta($postId, 'beyondwords_title_voice_id');
191 delete_post_meta($postId, 'beyondwords_summary_voice_id');
192 }
193
194 return $postId;
195 }
196
197 /**
198 * Register WP REST API route
199 *
200 * @since 4.0.0
201 *
202 * @return void
203 */
204 public function restApiInit()
205 {
206 // Languages endpoint
207 register_rest_route('beyondwords/v1', '/languages', array(
208 'methods' => \WP_REST_Server::READABLE,
209 'callback' => array($this, 'languagesRestApiResponse'),
210 'permission_callback' => function () {
211 return current_user_can('edit_posts');
212 },
213 ));
214
215 // Voices endpoint
216 register_rest_route('beyondwords/v1', '/languages/(?P<languageId>[0-9]+)/voices', array(
217 'methods' => \WP_REST_Server::READABLE,
218 'callback' => array($this, 'voicesRestApiResponse'),
219 'permission_callback' => function () {
220 return current_user_can('edit_posts');
221 },
222 ));
223 }
224
225 /**
226 * Get languages from BeyondWords API and filter by "Languages" plugin setting.
227 *
228 * @since 4.0.0
229 * @since 4.5.1 Exit early with an empty array if language API call fails.
230 *
231 * @return array Array of languages
232 */
233 public function getFilteredLanguages()
234 {
235 $languages = $this->apiClient->getLanguages();
236
237 if (! is_array($languages)) {
238 return [];
239 }
240
241 $languagesSetting = get_option('beyondwords_languages', Languages::DEFAULT_LANGUAGES);
242
243 // Filter languages according to "Languages" plugin setting
244 if (is_array($languages) && is_array($languagesSetting)) {
245 $languages = array_values(array_filter($languages, function ($language) {
246 return $this->languageIsInSettings($language);
247 }));
248 }
249
250 return $languages;
251 }
252
253 /**
254 * Get languages from BeyondWords API and filter by "Languages" plugin setting.
255 *
256 * @since 4.0.0
257 *
258 * @return array Array of languages
259 */
260 public function languageIsInSettings($language)
261 {
262 if (! is_array($language)) {
263 return false;
264 }
265
266 if (! array_key_exists('id', $language)) {
267 return false;
268 }
269
270 $languagesSetting = get_option('beyondwords_languages', Languages::DEFAULT_LANGUAGES);
271
272 if (! is_array($languagesSetting)) {
273 return false;
274 }
275
276 if (! in_array(strval($language['id']), $languagesSetting)) {
277 return false;
278 }
279
280 return true;
281 }
282
283 /**
284 * "Languages" WP REST API response (required for the Gutenberg editor).
285 *
286 * @since 4.0.0
287 *
288 * @return \WP_REST_Response
289 */
290 public function languagesRestApiResponse()
291 {
292 $languages = $this->getFilteredLanguages();
293
294 return new \WP_REST_Response($languages);
295 }
296
297 /**
298 * "Voices" WP REST API response (required for the Gutenberg editor
299 * and Block Editor).
300 *
301 * @since 4.0.0
302 *
303 * @return \WP_REST_Response
304 */
305 public function voicesRestApiResponse(\WP_REST_Request $data)
306 {
307 $params = $data->get_url_params();
308
309 $voices = $this->apiClient->getVoices($params['languageId']);
310
311 return new \WP_REST_Response($voices);
312 }
313
314
315 /**
316 * Register the component scripts.
317 *
318 * @since 4.0.0
319 *
320 * @param string $hook Page hook
321 *
322 * @return void
323 */
324 public function adminEnqueueScripts($hook)
325 {
326 if (! CoreUtils::isGutenbergPage() && ( $hook === 'post.php' || $hook === 'post-new.php')) {
327 wp_register_script(
328 'beyondwords-metabox--select-voice',
329 BEYONDWORDS__PLUGIN_URI . 'src/Component/Post/SelectVoice/classic-metabox.js',
330 ['jquery', 'underscore'],
331 BEYONDWORDS__PLUGIN_VERSION,
332 true
333 );
334
335 /**
336 * Localize the script to handle ajax requests
337 */
338 wp_localize_script(
339 'beyondwords-metabox--select-voice',
340 'beyondwordsData',
341 array(
342 'nonce' => wp_create_nonce('wp_rest'),
343 'root' => esc_url_raw(rest_url()),
344 )
345 );
346
347 wp_enqueue_script('beyondwords-metabox--select-voice');
348 }
349 }
350 }
351