PluginProbe
BeyondWords – AI audio for publishers / 4.5.0
BeyondWords – AI audio for publishers v4.5.0
7.2.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 All 44 releases
speechkit / src / Component / Settings / Settings.php

Settings.php in BeyondWords – AI audio for publishers 4.5.0, at src/Component/Settings/Settings.php

556 lines 16.9 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 settings.
7 *
8 * @package Beyondwords\Wordpress
9 * @author Stuart McAlpine <[email protected]>
10 * @since 3.0.0
11 */
12
13 namespace Beyondwords\Wordpress\Component\Settings;
14
15 use Beyondwords\Wordpress\Component\Settings\ApiKey\ApiKey;
16 use Beyondwords\Wordpress\Component\Settings\Languages\Languages;
17 use Beyondwords\Wordpress\Component\Settings\Preselect\Preselect;
18 use Beyondwords\Wordpress\Component\Settings\PrependExcerpt\PrependExcerpt;
19 use Beyondwords\Wordpress\Component\Settings\PlayerUI\PlayerUI;
20 use Beyondwords\Wordpress\Component\Settings\PlayerStyle\PlayerStyle;
21 use Beyondwords\Wordpress\Component\Settings\PlayerVersion\PlayerVersion;
22 use Beyondwords\Wordpress\Component\Settings\ProjectId\ProjectId;
23 use Beyondwords\Wordpress\Component\Settings\SettingsUpdated\SettingsUpdated;
24 use Beyondwords\Wordpress\Component\Settings\SettingsUtils;
25 use Beyondwords\Wordpress\Core\Environment;
26
27 /**
28 * Settings setup
29 *
30 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
31 *
32 * @since 3.0.0
33 */
34 class Settings
35 {
36 /**
37 * API Client.
38 *
39 * @since 3.0.0
40 */
41 private $apiClient;
42
43 /**
44 * Constructor.
45 *
46 * @since 3.0.0
47 */
48 public function __construct($apiClient)
49 {
50 $this->apiClient = $apiClient;
51 }
52
53 /**
54 * Init
55 */
56 public function init()
57 {
58 (new ApiKey())->init();
59 (new ProjectId())->init();
60 (new Preselect())->init();
61 (new PrependExcerpt())->init();
62 (new PlayerVersion($this->apiClient))->init();
63 (new PlayerUI())->init();
64 (new PlayerStyle($this->apiClient))->init();
65 (new Languages($this->apiClient))->init();
66 (new SettingsUpdated())->init();
67
68 add_action('admin_menu', array($this, 'addOptionsPage'));
69 add_action('admin_init', array($this, 'addSettingsSections'));
70 add_action('admin_notices', array($this, 'printPluginAdminNotices'));
71 add_action('rest_api_init', array($this, 'restApiInit'));
72
73 add_filter('plugin_action_links_speechkit/speechkit.php', array($this, 'addSettingsLinkToPluginPage'));
74
75 add_action('updated_option', array($this, 'updatedOption'), 99);
76 add_action('added_option', array($this, 'addedOption'), 99);
77 }
78
79 /**
80 * Add items to the WordPress admin menu.
81 *
82 * @since 3.0.0
83 *
84 * @return void
85 */
86 public function addOptionsPage()
87 {
88 // Settings > BeyondWords
89 add_options_page(
90 __('BeyondWords', 'speechkit'),
91 __('BeyondWords', 'speechkit'),
92 'manage_options',
93 'beyondwords',
94 array($this, 'createAdminInterface')
95 );
96 }
97
98 /**
99 * Add Settings sections.
100 *
101 * =====
102 * Basic
103 * =====
104 * 'api_key' => '',
105 * 'project_id' => '',
106 *
107 * ==============
108 * Player
109 * ==============
110 * 'version' => '0',
111 *
112 * ==============
113 * Generate audio
114 * ==============
115 * 'preselect' => array('post' => '1', 'page' => '1'),
116 *
117 * ========
118 * Advanced
119 * ========
120 * 'merge_excerpt' => false,
121 *
122 * @since 3.0.0
123 */
124 public function addSettingsSections()
125 {
126 // Add Settings Section: Basic
127 add_settings_section(
128 'basic',
129 __('Basic settings', 'speechkit'),
130 array($this, 'basicSectionCallback'),
131 'beyondwords'
132 );
133
134 if (SettingsUtils::hasApiSettings()) {
135 // Add Settings Section: Player
136 add_settings_section(
137 'player',
138 __('Player settings', 'speechkit'),
139 array($this, 'playerSectionCallback'),
140 'beyondwords'
141 );
142
143 // Add Settings Section: Content
144 add_settings_section(
145 'content',
146 __('Content settings', 'speechkit'),
147 array($this, 'contentSectionCallback'),
148 'beyondwords'
149 );
150
151 // Add Settings Section: Generate audio
152 add_settings_section(
153 'generate-audio',
154 __('‘Generate audio’ settings', 'speechkit'),
155 array($this, 'generateAudioSectionCallback'),
156 'beyondwords'
157 );
158 }
159 }
160
161 /**
162 * "Basic section" callback
163 *
164 * @since 3.0.0
165 *
166 * @return void
167 **/
168 public function basicSectionCallback()
169 {
170 delete_transient('beyondwords_settings_errors');
171 ?>
172 <p class="description">
173 <?php
174 _e(
175 'The details we need to authenticate your BeyondWords account. For more options, head to your BeyondWords dashboard.', // phpcs:ignore Generic.Files.LineLength.TooLong
176 'speechkit'
177 );
178 ?>
179 </p>
180 <?php
181 }
182
183 /**
184 * "Player section" callback
185 *
186 * @since 4.0.0
187 *
188 * @return void
189 **/
190 public function playerSectionCallback()
191 {
192 ?>
193 <p class="description">
194 <?php
195 _e(
196 'Upgrade to the latest player version for the newest features.', // phpcs:ignore Generic.Files.LineLength.TooLong
197 'speechkit'
198 );
199 ?>
200 </p>
201 <?php
202 }
203
204 /**
205 * "Content" section callback
206 *
207 * @since 3.0.0
208 *
209 * @return void
210 **/
211 public function contentSectionCallback()
212 {
213 ?>
214 <p class="description">
215 <?php
216 _e(
217 'By default, BeyondWords will process your titles and body content into audio.', // phpcs:ignore Generic.Files.LineLength.TooLong
218 'speechkit'
219 );
220 ?>
221 </p>
222 <?php
223 }
224
225 /**
226 * ‘Generate audio’ section callback.
227 *
228 * @since 3.0.0
229 *
230 * @return void
231 **/
232 public function generateAudioSectionCallback()
233 {
234 ?>
235 <p class="description">
236 <?php
237 _e(
238 'The ‘Generate audio’ checkbox in the BeyondWords sidebar will be automatically checked for selected post types. The default setting can be manually overridden.', // phpcs:ignore Generic.Files.LineLength.TooLong
239 'speechkit'
240 );
241 ?>
242 </p>
243 <p class="description">
244 <?php
245 _e(
246 'Uncheck a post type to view its Categories. You can then set defaults at a category level. Make sure to check all relevant boxes.', // phpcs:ignore Generic.Files.LineLength.TooLong
247 'speechkit'
248 );
249 ?>
250 </p>
251 <p class="description">
252 <em>
253 <?php
254 _e(
255 'The default WordPress ‘Categories’ taxonomy is currently the only taxonomy supported.',
256 'speechkit'
257 );
258 ?>
259 </em>
260 </p>
261 <?php
262 }
263
264 public function addSettingsLinkToPluginPage($links)
265 {
266 $links[] = '<a href="' .
267 esc_url(admin_url('options-general.php?page=beyondwords')) .
268 '">' . __('Settings', 'speechkit') . '</a>';
269 return $links;
270 }
271
272
273
274 public function createAdminInterface()
275 {
276 ?>
277 <div class="wrap">
278
279 <form
280 id="beyondwords-plugin-settings"
281 action="<?php echo esc_url(admin_url('options.php')); ?>"
282 method="post"
283 >
284
285 <h1><?php _e('BeyondWords settings', 'speechkit'); ?></h1>
286
287 <?php
288 $projectId = get_option('beyondwords_project_id');
289 $playerReverted = get_transient('beyondwords_player_reverted');
290
291 if ($projectId) :
292 ?>
293 <p>
294 <a
295 class="button button-secondary"
296 href="<?php echo esc_url(Environment::getDashboardUrl()); ?>"
297 target="_blank"
298 >
299 <?php _e('BeyondWords dashboard', 'speechkit'); ?>
300 </a>
301 </p>
302 <?php
303 endif;
304
305 if ($playerReverted) :
306 ?>
307 <div id="beyondwords-player-reverted-notice" class="notice notice-error">
308 <p>
309 <span class="dashicons dashicons-editor-help"></span>
310 <?php
311 printf(
312 /* translators: %s is replaced with a "let us know" link */
313 esc_html__('It looks like you tried the "Latest" player and switched back to the "Legacy" player. If you experienced any issues switching player please %s so we can help.', 'speechkit'), // phpcs:ignore Generic.Files.LineLength.TooLong
314 sprintf(
315 '<a href="mailto:[email protected]?subject=%s">%s</a>',
316 esc_attr__('WordPress support: Latest player', 'speechkit'),
317 esc_html__('let us know', 'speechkit')
318 )
319 );
320 ?>
321 </p>
322 </div>
323 <?php
324 endif;
325 if (SettingsUtils::hasApiSettings()) :
326 ?>
327 <div id="beyondwords-player-location-notice" class="notice notice-info">
328 <p>
329 <span class="dashicons dashicons-info"></span>
330 <?php _e(
331 'The player will appear before the first part of <code>the_content()</code> by default. You can change the location via the WordPress Editor.', // phpcs:ignore Generic.Files.LineLength.TooLong
332 'speechkit'
333 );
334 ?>
335 </p>
336 </div>
337 <?php
338 endif;
339
340 settings_fields('beyondwords');
341 do_settings_sections('beyondwords');
342
343 if (SettingsUtils::hasApiSettings()) {
344 submit_button('Save Settings');
345 } else {
346 submit_button('Continue setup');
347 }
348 ?>
349 </form>
350 </div>
351 <?php
352 }
353
354 /**
355 * Print Admin Notices.
356 *
357 * @since 3.0.0
358 *
359 * @return void
360 */
361 public function printPluginAdminNotices()
362 {
363 $hasApiSettings = SettingsUtils::hasApiSettings();
364 $settingsErrors = get_transient('beyondwords_settings_errors');
365
366 if (is_array($settingsErrors) && count($settingsErrors)) :
367 ?>
368 <div class="notice notice-error">
369 <p>
370 <strong>
371 <?php
372 printf(
373 /* translators: %s is replaced with a "plugin settings" link */
374 esc_html__('To use BeyondWords, please update the %s.', 'speechkit'),
375 sprintf(
376 '<a href="%s">%s</a>',
377 esc_url(admin_url('options-general.php?page=beyondwords')),
378 esc_html__('plugin settings', 'speechkit')
379 )
380 );
381 ?>
382 </strong>
383 </p>
384 <ul class="ul-disc">
385 <?php
386 foreach ($settingsErrors as $error) {
387 printf(
388 '<li>%s</li>',
389 // Only allow links with href and target attributes
390 wp_kses(
391 $error,
392 array(
393 'a' => array(
394 'href' => array(),
395 'target' => array(),
396 ),
397 'b' => array(),
398 'strong' => array(),
399 'i' => array(),
400 'em' => array(),
401 )
402 )
403 );
404 }
405 ?>
406 </ul>
407 </div>
408
409 <?php
410 elseif (false === $hasApiSettings) :
411 ?>
412 <div class="notice notice-info">
413 <p>
414 <strong>
415 <?php
416 printf(
417 esc_html__('To use BeyondWords, please update the %s.', 'speechkit'),
418 sprintf(
419 '<a href="%s">%s</a>',
420 esc_url(admin_url('options-general.php?page=beyondwords')),
421 esc_html__('plugin settings', 'speechkit')
422 )
423 );
424 ?>
425 </strong>
426 </p>
427 <p>
428 <?php _e('Don’t have a BeyondWords account yet?', 'speechkit'); ?>
429 </p>
430 <p>
431 <a
432 class="button button-secondary"
433 href="<?php echo esc_url(sprintf('%s/auth/signup', Environment::getDashboardUrl())); ?>"
434 target="_blank"
435 >
436 <?php _e('Sign up free', 'speechkit'); ?>
437 </a>
438 </p>
439 </div>
440 <?php
441 endif;
442 }
443
444 /**
445 * Register WP REST API route
446 *
447 * @return void
448 */
449 public function restApiInit()
450 {
451 // settings endpoint
452 register_rest_route('beyondwords/v1', '/settings', array(
453 'methods' => \WP_REST_Server::READABLE,
454 'callback' => array($this, 'restApiResponse'),
455 'permission_callback' => function () {
456 return current_user_can('edit_posts');
457 },
458 ));
459 }
460
461 /**
462 * WP REST API response (required for the Gutenberg editor).
463 *
464 * DO NOT expose ALL settings e.g. be sure to never expose the API key.
465 *
466 * @since 3.0.0
467 * @since 3.4.0 Add pluginVersion and wpVersion.
468 *
469 * @return \WP_REST_Response
470 */
471 public function restApiResponse()
472 {
473 global $wp_version;
474
475 return new \WP_REST_Response([
476 'apiKey' => get_option('beyondwords_api_key', ''),
477 'pluginVersion' => BEYONDWORDS__PLUGIN_VERSION,
478 'projectId' => get_option('beyondwords_project_id', ''),
479 'preselect' => get_option('beyondwords_preselect', Preselect::DEFAULT_PRESELECT),
480 'languages' => get_option('beyondwords_languages', Languages::DEFAULT_LANGUAGES),
481 'wpVersion' => $wp_version,
482 ]);
483 }
484
485 /**
486 * Check API creds are valid whenever any setting is added.
487 *
488 * @since 4.0.0
489 *
490 * @return void
491 */
492 public function addedOption($optionName)
493 {
494 if ($optionName === 'beyondwords_settings_updated') {
495 $this->checkApiCreds();
496 }
497 }
498
499 /**
500 * Check API creds are valid whenever the settings are updated.
501 *
502 * @since 4.0.0
503 *
504 * @return void
505 */
506 public function updatedOption($optionName)
507 {
508 if ($optionName === 'beyondwords_settings_updated') {
509 $this->checkApiCreds();
510 }
511 }
512
513 /**
514 * Check to see if user has valid BeyondWords API credentials by performing
515 * a GET request using the API Key and Project ID.
516 *
517 * @since 4.0.0
518 *
519 * @return void
520 */
521 public function checkApiCreds()
522 {
523 // Assume invalid connection
524 delete_option('beyondwords_valid_api_connection');
525
526 $apiKey = get_option('beyondwords_api_key');
527 $projectId = get_option('beyondwords_project_id');
528
529 if (empty($apiKey) || empty($projectId)) {
530 return;
531 }
532
533 $project = $this->apiClient->getProject();
534
535 $validConnection = (
536 is_array($project)
537 && array_key_exists('id', $project)
538 && strval($project['id']) === $projectId
539 );
540
541 if ($validConnection) {
542 // Store date of last check
543 update_option('beyondwords_valid_api_connection', gmdate(DATE_ISO8601));
544 } else {
545 $errors = get_transient('beyondwords_settings_errors', []);
546
547 $errors['Settings/ValidApiConnection'] = __(
548 'Please check and re-enter your BeyondWords API key and project ID. They appear to be invalid.',
549 'speechkit'
550 );
551
552 set_transient('beyondwords_settings_errors', $errors);
553 }
554 }
555 }
556