PluginProbe
Faust.js / trunk
Faust.js vtrunk
1.8.12 1.8.11 1.4.1 1.8.0 1.8.8 1.8.9 trunk 0.7.0 0.7.1 0.7.10 0.7.11 0.7.3 0.7.4 0.7.5 0.7.6 0.7.7 0.7.8 0.7.9 0.8.0 0.8.1 0.8.3 0.8.4 0.8.5 0.8.6 0.8.7 All 40 releases
faustwp / includes / settings / callbacks.php

callbacks.php in Faust.js trunk, at includes/settings/callbacks.php

571 lines 16.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Settings related callbacks.
4 *
5 * @package FaustWP
6 */
7
8 namespace WPE\FaustWP\Settings;
9
10 use function WPE\FaustWP\Telemetry\get_telemetry_client_id;
11 use function WPE\FaustWP\Utilities\{
12 plugin_version,
13 };
14
15 if ( ! defined( 'ABSPATH' ) ) {
16 exit;
17 }
18
19 add_action( 'admin_notices', __NAMESPACE__ . '\\frontend_url_notice' );
20 /**
21 * Callback for WordPress 'admin_notices' action.
22 *
23 * Show frontend_url missing error if it doesn't exist.
24 *
25 * @return void
26 */
27 function frontend_url_notice() {
28 $screen = get_current_screen();
29
30 // Exit if not this plugin's settings page.
31 if ( 'settings_page_faustwp-settings' !== $screen->id ) {
32 return;
33 }
34
35 $frontend_url_setting = faustwp_get_setting( 'frontend_uri' );
36
37 if ( empty( $frontend_url_setting ) ) {
38 ?>
39 <div class="notice notice-error is-dismissible" style="background-color: #FFEAE9;">
40 <p><?php esc_html_e( 'Front-end site URL is required to utilize url rewrites and previews.', 'faustwp' ); ?></p>
41 <p><?php esc_html_e( 'It is highly recommended that you update it below to avoid unexpected behavior.', 'faustwp' ); ?></p>
42 <p>
43 <?php
44 printf(
45 /* translators: Link text */
46 esc_html__( 'See the %1$s Getting Started Documentation%2$s for more details.', 'faustwp' ),
47 '<a href="https://faustjs.org/docs/how-to/basic-setup" target="_blank" rel="noopener noreferrer">',
48 '</a>'
49 );
50 ?>
51 </p>
52 </div>
53 <?php
54 }
55 }
56
57 add_action( 'admin_menu', __NAMESPACE__ . '\\register_settings_menu' );
58 /**
59 * Callback for WordPress 'admin_menu' action.
60 *
61 * Register the sub-menu.
62 *
63 * @uses add_submenu_page()
64 * @link https://developer.wordpress.org/reference/functions/add_submenu_page/
65 *
66 * @return void
67 */
68 function register_settings_menu() {
69 add_submenu_page(
70 'options-general.php',
71 __( 'Faust', 'faustwp' ),
72 __( 'Faust', 'faustwp' ),
73 'manage_options',
74 'faustwp-settings',
75 __NAMESPACE__ . '\\display_settings_page'
76 );
77 }
78
79 add_action( 'admin_init', __NAMESPACE__ . '\\register_settings' );
80 /**
81 * Callback for WordPress 'admin_init' action.
82 *
83 * Register settings with WordPress.
84 *
85 * @uses register_setting()
86 * @link https://developer.wordpress.org/reference/functions/register_setting/
87 *
88 * @return void
89 */
90 function register_settings() {
91 register_setting( 'faustwp_settings', 'faustwp_settings' );
92 }
93
94 add_action( 'admin_init', __NAMESPACE__ . '\\register_settings_section' );
95 /**
96 * Callback for WordPress 'admin_init' action.
97 *
98 * Register settings form sections.
99 *
100 * @uses add_settings_section()
101 * @link https://developer.wordpress.org/reference/functions/add_settings_section/
102 *
103 * @return void
104 */
105 function register_settings_section() {
106 add_settings_section(
107 'settings_section',
108 null,
109 null,
110 'faustwp-settings'
111 );
112 }
113
114 add_action( 'admin_init', __NAMESPACE__ . '\\register_settings_fields' );
115 /**
116 * Callback for WordPress 'admin_init' action.
117 *
118 * Add the settings fields.
119 *
120 * @uses add_settings_field()
121 * @link https://developer.wordpress.org/reference/functions/add_settings_field/
122 *
123 * @return void
124 */
125 function register_settings_fields() {
126 add_settings_field(
127 'frontend_uri',
128 __( 'Front-end site URL', 'faustwp' ),
129 __NAMESPACE__ . '\\display_frontend_uri_field',
130 'faustwp-settings',
131 'settings_section',
132 array(
133 'class' => 'align-middle',
134 'label_for' => 'frontend_uri',
135 )
136 );
137
138 add_settings_field(
139 'secret_key',
140 __( 'Secret Key', 'faustwp' ),
141 __NAMESPACE__ . '\\display_secret_key_field',
142 'faustwp-settings',
143 'settings_section',
144 array(
145 'class' => 'align-middle',
146 'label_for' => 'secret_key',
147 )
148 );
149
150 add_settings_field(
151 'menu_locations',
152 __( 'Menu Locations', 'faustwp' ),
153 __NAMESPACE__ . '\\display_menu_locations_field',
154 'faustwp-settings',
155 'settings_section',
156 array(
157 'class' => 'align-middle',
158 'label_for' => 'menu_locations',
159 )
160 );
161
162 add_settings_field(
163 'remove_additional_menu_locations',
164 __( 'Remove Additional Nav Menu Locations', 'faustwp' ),
165 __NAMESPACE__ . '\\display_remove_additional_menu_locations_field',
166 'faustwp-settings',
167 'settings_section'
168 );
169
170 add_settings_field(
171 'enable_disable',
172 __( 'Features', 'faustwp' ),
173 __NAMESPACE__ . '\\display_enable_disable_fields',
174 'faustwp-settings',
175 'settings_section'
176 );
177 }
178
179 add_filter( 'sanitize_option_faustwp_settings', __NAMESPACE__ . '\\sanitize_faustwp_settings', 10, 2 );
180 /**
181 * Validates and sanitizes Faust settings.
182 *
183 * The plugin settings page will display any relevant errors when
184 * rejecting invalid settings values. Updates to Faust settings that
185 * are not initiated from the plugin settings page will not return or
186 * display errors, but will still reject invalid values.
187 *
188 * Once settings are validated, the sanitized values are returned.
189 *
190 * @param array $settings Faust settings array to validate and sanitize.
191 * @param string $option WP option name where settings are saved.
192 * @return array Sanitized settings.
193 */
194 function sanitize_faustwp_settings( $settings, $option ) {
195 $errors = null;
196 $protocols = array( 'http', 'https' );
197 foreach ( $settings as $name => $value ) {
198 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verified elsewhere.
199 if ( ! isset( $settings['enable_telemetry'] ) && ! empty( $_POST['option_page'] ) && 'faustwp_settings' === $_POST['option_page'] ) {
200 $reminder_time = new \DateTime( '+90 days', new \DateTimeZone( 'UTC' ) );
201 $settings['telemetry_reminder'] = $reminder_time->getTimestamp();
202 }
203
204 switch ( $name ) {
205 case 'frontend_uri':
206 if ( '' === $value || preg_match( '#http(s?)://(.+)#i', $value ) ) {
207 $settings[ $name ] = esc_url_raw( $value, $protocols );
208 } else {
209 $errors[ $name ] = __( 'The Front-end site URL you entered did not appear to be a valid URL. Please enter a valid URL.', 'faustwp' );
210 $settings[ $name ] = faustwp_get_setting( $name );
211 }
212 break;
213
214 case 'secret_key':
215 if ( ! wp_is_uuid( $value, 4 ) ) {
216 $errors[ $name ] = __( 'The secret key you entered did not appear to be a valid UUID.', 'faustwp' );
217 $settings[ $name ] = get_secret_key();
218 }
219 break;
220
221 case 'menu_locations':
222 $settings[ $name ] = sanitize_text_field( $value );
223 break;
224
225 case 'remove_additional_menu_locations':
226 case 'enable_redirects':
227 case 'enable_rewrites':
228 case 'disable_theme':
229 case 'enable_image_source':
230 if ( $value ) {
231 $settings[ $name ] = '1';
232 } else {
233 unset( $settings[ $name ] );
234 }
235 break;
236
237 case 'enable_telemetry':
238 if ( $value ) {
239 $settings[ $name ] = sanitize_text_field( $value );
240 } else {
241 unset( $settings[ $name ] );
242 }
243 break;
244 case 'telemetry_reminder':
245 if ( $value ) {
246 $settings[ $name ] = (int) $value;
247 } else {
248 unset( $settings[ $name ] );
249 }
250 break;
251
252 case 'telemetry_client_id':
253 if ( $value ) {
254 $settings[ $name ] = sanitize_text_field( $value );
255 }
256 break;
257
258 default:
259 // Remove any settings we don't expect.
260 unset( $settings[ $name ] );
261 break;
262 }
263 }
264
265 if ( null !== $errors && is_array( $errors ) ) {
266 foreach ( $errors as $name => $error ) {
267 add_settings_error( $option, "faustwp_invalid_{$name}", $error );
268 }
269 }
270
271 return $settings;
272 }
273
274 add_action( 'load-settings_page_faustwp-settings', __NAMESPACE__ . '\\handle_regenerate_secret_key', 5 );
275 /**
276 * Callback for WordPress 'load-{$page_hook}' action.
277 *
278 * Nonce set in WPE\FaustWP\Settings\display_secret_key_field().
279 *
280 * Regenerate the secret key.
281 *
282 * @return void
283 */
284 function handle_regenerate_secret_key() {
285 $screen = get_current_screen();
286 if ( 'settings_page_faustwp-settings' !== $screen->id ) {
287 return;
288 }
289
290 if ( empty( $_GET['regenerate_nonce'] ) ) {
291 return;
292 }
293
294 if ( ! current_user_can( 'manage_options' ) ) {
295 return;
296 }
297
298 check_admin_referer( 'regenerate_secret', 'regenerate_nonce' );
299
300 faustwp_update_setting( 'secret_key', wp_generate_uuid4() );
301
302 wp_safe_redirect(
303 admin_url( '/options-general.php?page=faustwp-settings' )
304 );
305
306 exit;
307 }
308
309 /**
310 * Callback for add_submenu_page() function.
311 *
312 * Display the settings page.
313 *
314 * @return void
315 */
316 function display_settings_page() {
317 require FAUSTWP_DIR . '/includes/settings/views/headless-settings.php';
318 }
319
320 /**
321 * Callback for WordPress add_settings_field() method parameter.
322 *
323 * Display the "Menu Locations" text field.
324 *
325 * @return void
326 */
327 function display_menu_locations_field() {
328 $menu_locations = faustwp_get_setting( 'menu_locations', 'Primary, Footer' );
329
330 ?>
331 <input type="text" id="menu_locations" name="faustwp_settings[menu_locations]" value="<?php echo esc_attr( $menu_locations ); ?>" class="regular-text" />
332
333 <p class="description">
334 <?php esc_html_e( 'A comma-separated list of menu locations. Assign menus to locations at Appearance → Menus.', 'faustwp' ); ?>
335 </p>
336 <?php
337 }
338
339 /**
340 * Callback for WordPress add_settings_field() method parameter.
341 *
342 * Display the "Remove Additional Menu Locations" checkbox field.
343 *
344 * @return void
345 */
346 function display_remove_additional_menu_locations_field() {
347 $removed = faustwp_get_setting( 'remove_additional_menu_locations', false );
348 ?>
349 <label for="remove_additional_menu_locations">
350 <input type="checkbox" id="remove_additional_menu_locations" name="faustwp_settings[remove_additional_menu_locations]" value="1" <?php checked( $removed ); ?> /><?php esc_html_e( 'Remove all Nav Menu locations that are not registered on this screen.', 'faustwp' ); ?>
351 <p class="description"><?php esc_html_e( 'By checking this, the only Nav Menu locations will be the ones registered on this page. Leaving this un-checked will combine the menu locations on this page with menu locations registered by other plugins or themes. This has an impact on the nav menu manager in the WordPress admin and API access to menus.', 'faustwp' ); ?></p>
352 </label>
353 <?php
354 }
355
356 /**
357 * Callback for WordPress add_settings_field() method parameter.
358 *
359 * Display the "API Key" text field.
360 *
361 * Added hidden field to preserve value during settings save.
362 *
363 * @return void
364 */
365 function display_secret_key_field() {
366 $secret_key = get_secret_key();
367 $regenerate_url = wp_nonce_url(
368 admin_url( 'options-general.php?page=faustwp-settings' ),
369 'regenerate_secret',
370 'regenerate_nonce'
371 );
372
373 ?>
374 <input type="text" id="secret_key" value="<?php echo esc_attr( $secret_key ); ?>" class="regular-text code" readonly />
375 <input type="hidden" name="faustwp_settings[secret_key]" value="<?php echo esc_attr( $secret_key ); ?>" />
376
377 <a
378 href="<?php echo esc_url( $regenerate_url ); ?>"
379 title="<?php esc_attr_e( 'Regenerate Secret Key', 'faustwp' ); ?>"
380 onclick="confirm_regenerate_key( event )"
381 class="field-action"
382 >
383 <?php esc_html_e( 'Regenerate', 'faustwp' ); ?>
384 </a>
385
386 <script type="text/javascript">
387 function confirm_regenerate_key( event ) {
388 if ( ! confirm( 'Are you sure you want to regenerate your secret key?' ) ) {
389 event.preventDefault();
390 }
391 }
392 </script>
393
394 <p class="description">
395 <?php
396 printf(
397 /* translators: %s: Documentation URL. */
398 wp_kses_post( __( 'This key is used to enable <a href="%s" target="_blank" rel="noopener noreferrer">headless post previews</a> and make authenticated GraphQL requests for schema generation.', 'faustwp' ) ),
399 'https://faustjs.org/docs/how-to/post-previews'
400 );
401 ?>
402 </p>
403 <?php
404 }
405
406 /**
407 * Callback for WordPress add_settings_field() method parameter.
408 *
409 * Display the Preview Base Address (URL) field.
410 *
411 * @return void
412 */
413 function display_frontend_uri_field() {
414 $frontend_uri = faustwp_get_setting( 'frontend_uri', '' );
415
416 ?>
417 <input type="text" id="frontend_uri" name="faustwp_settings[frontend_uri]" value="<?php echo esc_attr( $frontend_uri ); ?>" class="regular-text" />
418 <p class="description">
419 <?php esc_html_e( 'The full URL to your headless front-end, including https:// or http://. This is used for authenticated post previews and for rewriting links to point to your front-end site.', 'faustwp' ); ?>
420 </p>
421 <?php
422 }
423
424 /**
425 * Callback for WordPress add_settings_field() method parameter.
426 *
427 * Display the enable/disable features section.
428 *
429 * @return void
430 */
431 function display_enable_disable_fields() {
432 $disable_theme = is_themes_disabled();
433 $enable_rewrites = is_rewrites_enabled();
434 $enable_redirects = is_redirects_enabled();
435 $enable_image_source = is_image_source_replacement_enabled();
436 $enable_telemetry = is_telemetry_enabled();
437 ?>
438 <fieldset>
439 <legend style="margin-bottom:5px;padding:0;">
440 <p class="description">
441 <?php
442 printf(
443 /* translators: %s: Documentation URL. */
444 wp_kses_post( __( 'Learn more about <a href="%s" target="_blank" rel="noopener noreferrer">features</a>.', 'faustwp' ) ),
445 'https://faustjs.org/docs/how-to/basic-setup'
446 );
447 ?>
448 </p>
449 </legend>
450 <label for="disable_theme">
451 <input type="checkbox" id="disable_theme" name="faustwp_settings[disable_theme]" value="1" <?php checked( $disable_theme ); ?> />
452 <?php esc_html_e( 'Disable WordPress theme admin pages', 'faustwp' ); ?>
453 </label>
454 <br />
455
456 <label for="enable_rewrites">
457 <input type="checkbox" id="enable_rewrites" name="faustwp_settings[enable_rewrites]" value="1" <?php checked( $enable_rewrites ); ?> />
458 <?php esc_html_e( 'Enable Post and Category URL rewrites', 'faustwp' ); ?>
459 </label>
460 <br />
461
462 <label for="enable_redirects">
463 <input type="checkbox" id="enable_redirects" name="faustwp_settings[enable_redirects]" value="1" <?php checked( $enable_redirects ); ?> />
464 <?php esc_html_e( 'Enable public route redirects', 'faustwp' ); ?>
465 </label>
466 <br />
467
468 <label for="enable_image_source">
469 <input type="checkbox" id="enable_image_source" name="faustwp_settings[enable_image_source]" value="1" <?php checked( $enable_image_source ); ?> />
470 <?php esc_html_e( 'Use the WordPress domain for media URLs in post content', 'faustwp' ); ?>
471 </label>
472 <br />
473
474 <label for="enable_telemetry">
475 <input type="checkbox" id="enable_telemetry" name="faustwp_settings[enable_telemetry]" value="1" <?php checked( $enable_telemetry ); ?> />
476 <?php esc_html_e( 'Enable anonymous telemetry', 'faustwp' ); ?>
477 </label>
478 <input type="hidden" id="telemetry_client_id" name="faustwp_settings[telemetry_client_id]" value="<?php echo esc_attr( get_telemetry_client_id() ); ?>" />
479 </fieldset>
480 <?php
481 }
482
483 add_action( 'load-settings_page_faustwp-settings', __NAMESPACE__ . '\\verify_graphql_dependency' );
484 /**
485 * Verifies the WP GraphQL dependency is met.
486 *
487 * If not, it adds an admin notice and related scripts
488 * for installing and activating the plugin.
489 *
490 * @return void
491 */
492 function verify_graphql_dependency() {
493 add_action( 'admin_enqueue_scripts', __NAMESPACE__ . '\\add_settings_assets' );
494 }
495
496 /**
497 * Enqueues the settings stylesheet and scripts at Settings → Headless.
498 *
499 * Callback for admin_enqueue_scripts.
500 */
501 function add_settings_assets() {
502 wp_enqueue_style(
503 'faustwp-settings',
504 FAUSTWP_URL . 'includes/settings/assets/style.css',
505 array(),
506 plugin_version()
507 );
508
509 if ( ! function_exists( 'graphql' ) ) {
510 wp_enqueue_script(
511 'faustwp-wpgraphql-install',
512 FAUSTWP_URL . 'includes/settings/assets/js/wpgraphql-install.js',
513 array( 'wp-a11y', 'wp-api-fetch' ),
514 plugin_version(),
515 true
516 );
517
518 $faustwp = array(
519 'wpgraphqlIsInstalled' => array_key_exists( 'wp-graphql/wp-graphql.php', get_plugins() ),
520 'icons' => array(
521 'checkSmall' => get_icon( 'check-small' ),
522 ),
523 'strings' => array(
524 'default' => esc_html__( 'Install and Activate', 'faustwp' ),
525 'installing' => esc_html__( 'Installing…', 'faustwp' ),
526 'active' => esc_html__( 'WPGraphQL is active', 'faustwp' ),
527 'failed' => esc_html__( 'Installation failed', 'faustwp' ),
528 ),
529 );
530
531 wp_localize_script(
532 'faustwp-wpgraphql-install',
533 'faustwp',
534 $faustwp
535 );
536 }
537 }
538
539 add_filter( 'plugin_action_links_faustwp/faustwp.php', __NAMESPACE__ . '\\add_action_link_settings' );
540 /**
541 * Adds a link to the Settings page on the Installed Plugins page.
542 *
543 * @param array $links The array of plugin action links.
544 */
545 function add_action_link_settings( $links ) {
546 $url = add_query_arg( 'page', 'faustwp-settings', admin_url( 'options-general.php' ) );
547 return array_merge(
548 array(
549 '<a href="' . esc_url( $url ) . '">' . esc_html__( 'Settings', 'faustwp' ) . '</a>',
550 ),
551 $links
552 );
553 }
554
555 add_filter( 'faustwp_get_setting', __NAMESPACE__ . '\\trim_frontend_uri_trailing_slash', 10, 2 );
556 /**
557 * Ensure that this plugin's frontend_uri setting does not have a trailing slash.
558 *
559 * @param mixed $value The setting value.
560 * @param string $name The setting name.
561 *
562 * @return string
563 */
564 function trim_frontend_uri_trailing_slash( $value, $name ) {
565 if ( 'frontend_uri' !== $name ) {
566 return $value;
567 }
568
569 return untrailingslashit( $value );
570 }
571