PluginProbe
BeyondWords – AI audio for publishers / trunk
BeyondWords – AI audio for publishers vtrunk
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 / settings / class-fields.php

class-fields.php in BeyondWords – AI audio for publishers trunk, at src/settings/class-fields.php

351 lines 10.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * BeyondWords settings fields.
4 *
5 * Compound fields (e.g. preselect) live in their own classes.
6 *
7 * @package BeyondWords\Settings
8 *
9 * @since 7.0.0 Refactored to BeyondWords namespace with snake_case methods.
10 */
11
12 declare( strict_types = 1 );
13
14 namespace BeyondWords\Settings;
15
16 defined( 'ABSPATH' ) || exit;
17
18 /**
19 * Settings fields.
20 *
21 * Option keys and value enums are class constants so the rest of the plugin
22 * can read them without going through the settings page.
23 *
24 * @since 7.0.0 Refactored to BeyondWords namespace with snake_case methods.
25 */
26 class Fields {
27
28 const OPTION_API_KEY = 'beyondwords_api_key';
29 const OPTION_PROJECT_ID = 'beyondwords_project_id';
30 const OPTION_INTEGRATION_METHOD = 'beyondwords_integration_method';
31 const OPTION_PREPEND_EXCERPT = 'beyondwords_prepend_excerpt';
32 const OPTION_PLAYER_UI = 'beyondwords_player_ui';
33
34 const INTEGRATION_REST_API = 'rest-api';
35 const INTEGRATION_CLIENT_SIDE = 'client-side';
36
37 const PLAYER_UI_ENABLED = 'enabled';
38 const PLAYER_UI_HEADLESS = 'headless';
39 const PLAYER_UI_DISABLED = 'disabled';
40
41 /**
42 * Register WordPress hooks.
43 */
44 public static function init(): void {
45 add_action( 'admin_init', [ self::class, 'register_authentication_fields' ] );
46 add_action( 'admin_init', [ self::class, 'register_integration_fields' ] );
47 add_action( 'admin_init', [ self::class, 'register_preferences_fields' ] );
48 }
49
50 /**
51 * Register API key + project ID for the Authentication tab.
52 */
53 public static function register_authentication_fields(): void {
54 register_setting(
55 Tabs::SETTINGS_GROUP_AUTHENTICATION,
56 self::OPTION_API_KEY,
57 [
58 'type' => 'string',
59 'default' => '',
60 'sanitize_callback' => [ self::class, 'sanitize_api_key' ],
61 ]
62 );
63
64 register_setting(
65 Tabs::SETTINGS_GROUP_AUTHENTICATION,
66 self::OPTION_PROJECT_ID,
67 [
68 'type' => 'string',
69 'default' => '',
70 'sanitize_callback' => [ self::class, 'sanitize_project_id' ],
71 ]
72 );
73
74 add_settings_field(
75 'beyondwords-api-key',
76 __( 'API key', 'speechkit' ),
77 [ self::class, 'render_api_key' ],
78 Tabs::PAGE_AUTHENTICATION,
79 Tabs::SECTION_AUTHENTICATION
80 );
81
82 add_settings_field(
83 'beyondwords-project-id',
84 __( 'Project ID', 'speechkit' ),
85 [ self::class, 'render_project_id' ],
86 Tabs::PAGE_AUTHENTICATION,
87 Tabs::SECTION_AUTHENTICATION
88 );
89 }
90
91 /**
92 * Register the integration method field for the Integration tab.
93 */
94 public static function register_integration_fields(): void {
95 register_setting(
96 Tabs::SETTINGS_GROUP_INTEGRATION,
97 self::OPTION_INTEGRATION_METHOD,
98 [
99 'type' => 'string',
100 'default' => self::INTEGRATION_REST_API,
101 'sanitize_callback' => [ self::class, 'sanitize_integration_method' ],
102 ]
103 );
104
105 add_settings_field(
106 'beyondwords-integration-method',
107 __( 'Integration method', 'speechkit' ),
108 [ self::class, 'render_integration_method' ],
109 Tabs::PAGE_INTEGRATION,
110 Tabs::SECTION_INTEGRATION
111 );
112 }
113
114 /**
115 * Register the per-site preferences (excerpt, player UI).
116 *
117 * Preselect lives in its own class: post-type-aware logic plus a JS asset.
118 */
119 public static function register_preferences_fields(): void {
120 register_setting(
121 Tabs::SETTINGS_GROUP_PREFERENCES,
122 self::OPTION_PREPEND_EXCERPT,
123 [
124 'type' => 'boolean',
125 'default' => false,
126 'sanitize_callback' => 'rest_sanitize_boolean',
127 ]
128 );
129 add_filter( 'option_' . self::OPTION_PREPEND_EXCERPT, 'rest_sanitize_boolean' );
130
131 register_setting(
132 Tabs::SETTINGS_GROUP_PREFERENCES,
133 self::OPTION_PLAYER_UI,
134 [
135 'type' => 'string',
136 'default' => self::PLAYER_UI_ENABLED,
137 'sanitize_callback' => [ self::class, 'sanitize_player_ui' ],
138 ]
139 );
140
141 add_settings_field(
142 'beyondwords-include-excerpt',
143 __( 'Excerpt', 'speechkit' ),
144 [ self::class, 'render_prepend_excerpt' ],
145 Tabs::PAGE_PREFERENCES,
146 Tabs::SECTION_PREFERENCES
147 );
148
149 add_settings_field(
150 'beyondwords-player-ui',
151 __( 'Player UI', 'speechkit' ),
152 [ self::class, 'render_player_ui' ],
153 Tabs::PAGE_PREFERENCES,
154 Tabs::SECTION_PREFERENCES
155 );
156 }
157
158 /**
159 * Sanitisers
160 * ------------------------------------------------------------------ */
161 public static function sanitize_api_key( $value ) {
162 $value = sanitize_text_field( (string) $value );
163
164 if ( '' === $value ) {
165 Utils::add_settings_error_message(
166 __( 'Please enter the BeyondWords API key. This can be found in your project settings.', 'speechkit' ),
167 'Settings/ApiKey'
168 );
169 }
170
171 return $value;
172 }
173
174 public static function sanitize_project_id( $value ) {
175 $value = sanitize_text_field( (string) $value );
176
177 if ( '' === $value ) {
178 Utils::add_settings_error_message(
179 __( 'Please enter your BeyondWords project ID. This can be found in your project settings.', 'speechkit' ),
180 'Settings/ProjectId'
181 );
182 }
183
184 return $value;
185 }
186
187 public static function sanitize_integration_method( $value ): string {
188 $value = is_string( $value ) ? $value : '';
189 return in_array( $value, [ self::INTEGRATION_REST_API, self::INTEGRATION_CLIENT_SIDE ], true )
190 ? $value
191 : self::INTEGRATION_REST_API;
192 }
193
194 public static function sanitize_player_ui( $value ): string {
195 $value = is_string( $value ) ? $value : '';
196 return in_array( $value, [ self::PLAYER_UI_ENABLED, self::PLAYER_UI_HEADLESS, self::PLAYER_UI_DISABLED ], true )
197 ? $value
198 : self::PLAYER_UI_ENABLED;
199 }
200
201 /**
202 * Renderers
203 * ------------------------------------------------------------------ */
204 public static function render_api_key(): void {
205 $value = (string) get_option( self::OPTION_API_KEY, '' );
206 ?>
207 <input
208 type="text"
209 id="<?php echo esc_attr( self::OPTION_API_KEY ); ?>"
210 name="<?php echo esc_attr( self::OPTION_API_KEY ); ?>"
211 value="<?php echo esc_attr( $value ); ?>"
212 size="50"
213 />
214 <?php
215 }
216
217 public static function render_project_id(): void {
218 $value = (string) get_option( self::OPTION_PROJECT_ID, '' );
219 ?>
220 <input
221 type="text"
222 id="<?php echo esc_attr( self::OPTION_PROJECT_ID ); ?>"
223 name="<?php echo esc_attr( self::OPTION_PROJECT_ID ); ?>"
224 value="<?php echo esc_attr( $value ); ?>"
225 size="10"
226 />
227 <?php
228 }
229
230 public static function render_integration_method(): void {
231 $current = self::get_integration_method();
232 ?>
233 <div class="beyondwords-setting__integration-method">
234 <select name="<?php echo esc_attr( self::OPTION_INTEGRATION_METHOD ); ?>" id="<?php echo esc_attr( self::OPTION_INTEGRATION_METHOD ); ?>">
235 <?php foreach ( self::get_integration_method_options() as $value => $label ) : ?>
236 <option value="<?php echo esc_attr( $value ); ?>" <?php selected( $value, $current ); ?>>
237 <?php echo esc_html( $label ); ?>
238 </option>
239 <?php endforeach; ?>
240 </select>
241 </div>
242 <p class="description">
243 <?php
244 printf(
245 /* translators: %s is the link text "Magic Embed" */
246 esc_html__( 'REST API is the default integration. Choose %s if your theme/plugins prevent BeyondWords from saving content via the REST API — for example on sites using a page builder.', 'speechkit' ),
247 sprintf(
248 '<a href="https://github.com/beyondwords-io/player/blob/main/doc/client-side-integration.md" target="_blank" rel="nofollow">%s</a>',
249 esc_html__( 'Magic Embed', 'speechkit' )
250 )
251 );
252 ?>
253 </p>
254 <?php
255 }
256
257 public static function render_prepend_excerpt(): void {
258 $value = (bool) get_option( self::OPTION_PREPEND_EXCERPT, false );
259 ?>
260 <div>
261 <label>
262 <input type="hidden" name="<?php echo esc_attr( self::OPTION_PREPEND_EXCERPT ); ?>" value="" />
263 <input
264 type="checkbox"
265 id="<?php echo esc_attr( self::OPTION_PREPEND_EXCERPT ); ?>"
266 name="<?php echo esc_attr( self::OPTION_PREPEND_EXCERPT ); ?>"
267 value="1"
268 <?php checked( $value ); ?>
269 />
270 <?php esc_html_e( 'Include the post excerpt at the start of generated audio and video.', 'speechkit' ); ?>
271 </label>
272 </div>
273 <?php
274 }
275
276 public static function render_player_ui(): void {
277 $current = (string) get_option( self::OPTION_PLAYER_UI, self::PLAYER_UI_ENABLED );
278 ?>
279 <div class="beyondwords-setting__player-ui">
280 <select name="<?php echo esc_attr( self::OPTION_PLAYER_UI ); ?>" id="<?php echo esc_attr( self::OPTION_PLAYER_UI ); ?>">
281 <?php foreach ( self::get_player_ui_options() as $value => $label ) : ?>
282 <option value="<?php echo esc_attr( $value ); ?>" <?php selected( $value, $current ); ?>>
283 <?php echo esc_html( $label ); ?>
284 </option>
285 <?php endforeach; ?>
286 </select>
287 </div>
288 <p class="description">
289 <?php
290 printf(
291 /* translators: %s is the link text "headless mode" */
292 esc_html__( 'Enable or disable the player, or set it to %s.', 'speechkit' ),
293 sprintf(
294 '<a href="https://github.com/beyondwords-io/player/blob/gh-pages/doc/building-your-own-ui.md" target="_blank" rel="nofollow">%s</a>',
295 esc_html__( 'headless mode', 'speechkit' )
296 )
297 );
298 ?>
299 </p>
300 <?php
301 }
302
303 /**
304 * Public accessors
305 * ------------------------------------------------------------------ */
306
307 /**
308 * Resolve the integration method for a post (or the site default).
309 *
310 * @param \WP_Post|false $post Post object, or false to get the site default.
311 */
312 public static function get_integration_method( $post = false ): string {
313 $method = '';
314
315 if ( $post instanceof \WP_Post ) {
316 $method = (string) get_post_meta( $post->ID, self::OPTION_INTEGRATION_METHOD, true );
317 }
318
319 if ( '' === $method ) {
320 $method = (string) get_option( self::OPTION_INTEGRATION_METHOD, self::INTEGRATION_REST_API );
321 }
322
323 return self::sanitize_integration_method( $method );
324 }
325
326 /**
327 * Available integration method choices.
328 *
329 * @return array<string,string>
330 */
331 public static function get_integration_method_options(): array {
332 return [
333 self::INTEGRATION_REST_API => __( 'REST API', 'speechkit' ),
334 self::INTEGRATION_CLIENT_SIDE => __( 'Magic Embed', 'speechkit' ),
335 ];
336 }
337
338 /**
339 * Available player UI choices.
340 *
341 * @return array<string,string>
342 */
343 public static function get_player_ui_options(): array {
344 return [
345 self::PLAYER_UI_ENABLED => __( 'Enabled', 'speechkit' ),
346 self::PLAYER_UI_HEADLESS => __( 'Headless', 'speechkit' ),
347 self::PLAYER_UI_DISABLED => __( 'Disabled', 'speechkit' ),
348 ];
349 }
350 }
351