• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

wp-graphql / wp-graphql / 19508918426

19 Nov 2025 04:36PM UTC coverage: 83.612% (+0.4%) from 83.228%
19508918426

push

github

actions-user
release: merge develop into master for v2.5.2

16235 of 19417 relevant lines covered (83.61%)

257.96 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

21.81
/src/Admin/Settings/SettingsRegistry.php
1
<?php
2

3
namespace WPGraphQL\Admin\Settings;
4

5
use WPGraphQL\Utils\Utils;
6

7
/**
8
 * Class SettingsRegistry
9
 *
10
 * This settings class is based on the WordPress Settings API Class v1.3 from Tareq Hasan of WeDevs
11
 *
12
 * @see     https://github.com/tareq1988/wordpress-settings-api-class
13
 * @author  Tareq Hasan <tareq@weDevs.com>
14
 * @link    https://tareq.co Tareq Hasan
15
 *
16
 * @package WPGraphQL\Admin\Settings
17
 */
18
class SettingsRegistry {
19

20
        /**
21
         * Settings sections array
22
         *
23
         * @var array<string,array<string,mixed>>
24
         */
25
        protected $settings_sections = [];
26

27
        /**
28
         * Settings fields array
29
         *
30
         * @var array<string,array<string,mixed>[]>
31
         */
32
        protected $settings_fields = [];
33

34
        /**
35
         * Returns the settings sections.
36
         *
37
         * @return array<string,array<string,mixed>>
38
         */
39
        public function get_settings_sections() {
×
40
                return $this->settings_sections;
×
41
        }
42

43
        /**
44
         * Returns the settings fields.
45
         *
46
         * @return array<string,array<string,mixed>[]>
47
         */
48
        public function get_settings_fields() {
×
49
                return $this->settings_fields;
×
50
        }
51

52
        /**
53
         * Enqueue scripts and styles
54
         *
55
         * @param string $hook_suffix The current admin page.
56
         *
57
         * @return void
58
         */
59
        public function admin_enqueue_scripts( string $hook_suffix ) {
×
60

61
                // if the page is not the GraphQL Settings page, bail
62
                if ( 'graphql_page_graphql-settings' !== $hook_suffix && 'toplevel_page_graphql-settings' !== $hook_suffix ) {
×
63
                        return;
×
64
                }
65

66
                wp_enqueue_style( 'wp-color-picker' );
×
67
                wp_enqueue_media();
×
68
                wp_enqueue_script( 'wp-color-picker' );
×
69
                wp_enqueue_script( 'jquery' );
×
70

71
                // Action to enqueue scripts on the WPGraphQL Settings page.
72
                do_action( 'graphql_settings_enqueue_scripts' );
×
73
        }
74

75
        /**
76
         * Set settings sections
77
         *
78
         * @param string              $slug    Setting Section Slug
79
         * @param array<string,mixed> $section setting section config.
80
         *
81
         * @return \WPGraphQL\Admin\Settings\SettingsRegistry
82
         */
83
        public function register_section( string $slug, array $section ) {
2✔
84
                $section['id']                    = $slug;
2✔
85
                $this->settings_sections[ $slug ] = $section;
2✔
86

87
                return $this;
2✔
88
        }
89

90
        /**
91
         * Register fields to a section
92
         *
93
         * @param string                $section The slug of the section to register a field to
94
         * @param array<string,mixed>[] $fields  settings fields array
95
         *
96
         * @return \WPGraphQL\Admin\Settings\SettingsRegistry
97
         */
98
        public function register_fields( string $section, array $fields ) {
×
99
                foreach ( $fields as $field ) {
×
100
                        $this->register_field( $section, $field );
×
101
                }
102

103
                return $this;
×
104
        }
105

106
        /**
107
         * Register a field to a section
108
         *
109
         * @param string              $section The slug of the section to register a field to
110
         * @param array<string,mixed> $field   The config for the field being registered
111
         *
112
         * @return \WPGraphQL\Admin\Settings\SettingsRegistry
113
         */
114
        public function register_field( string $section, array $field ) {
1✔
115
                $defaults = [
1✔
116
                        'name'  => '',
1✔
117
                        'label' => '',
1✔
118
                        'desc'  => '',
1✔
119
                        'type'  => 'text',
1✔
120
                ];
1✔
121

122
                $field_config = wp_parse_args( $field, $defaults );
1✔
123

124
                // Get the field name before the filter is passed.
125
                $field_name = $field_config['name'];
1✔
126

127
                // Unset it, as we don't want it to be filterable
128
                unset( $field_config['name'] );
1✔
129

130
                /**
131
                 * Filter the setting field config
132
                 *
133
                 * @param array<string,mixed>  $field_config The field config for the setting
134
                 * @param string               $field_name   The name of the field (unfilterable in the config)
135
                 * @param string               $section      The slug of the section the field is registered to
136
                 */
137
                $field = apply_filters( 'graphql_setting_field_config', $field_config, $field_name, $section );
1✔
138

139
                // Add the field name back after the filter has been applied
140
                $field['name'] = $field_name;
1✔
141

142
                // Add the field to the section
143
                $this->settings_fields[ $section ][] = $field;
1✔
144

145
                return $this;
1✔
146
        }
147

148
        /**
149
         * Initialize and registers the settings sections and fields to WordPress
150
         *
151
         * Usually this should be called at `admin_init` hook.
152
         *
153
         * This function gets the initiated settings sections and fields. Then
154
         * registers them to WordPress and ready for use.
155
         *
156
         * @return void
157
         */
158
        public function admin_init() {
2✔
159
                // Action that fires when settings are being initialized
160
                do_action( 'graphql_init_settings', $this );
2✔
161

162
                /**
163
                 * Filter the settings sections
164
                 *
165
                 * @param array<string,array<string,mixed>> $setting_sections The registered settings sections
166
                 */
167
                $setting_sections = apply_filters( 'graphql_settings_sections', $this->settings_sections );
2✔
168

169
                foreach ( $setting_sections as $id => $section ) {
2✔
170
                        if ( false === get_option( $id ) ) {
2✔
171
                                add_option( $id );
2✔
172
                        }
173

174
                        if ( isset( $section['desc'] ) && ! empty( $section['desc'] ) ) {
2✔
175
                                $section['desc'] = '<div class="inside">' . $section['desc'] . '</div>';
×
176
                                $callback        = static function () use ( $section ) {
×
177
                                        echo wp_kses( str_replace( '"', '\"', $section['desc'] ), Utils::get_allowed_wp_kses_html() );
×
178
                                };
×
179
                        } elseif ( isset( $section['callback'] ) ) {
2✔
180
                                $callback = $section['callback'];
×
181
                        } else {
182
                                $callback = null;
2✔
183
                        }
184

185
                        add_settings_section( $id, $section['title'], $callback, $id );
2✔
186
                }
187

188
                // register settings fields
189
                foreach ( $this->settings_fields as $section => $field ) {
2✔
190
                        foreach ( $field as $option ) {
1✔
191
                                $name     = $option['name'];
1✔
192
                                $type     = isset( $option['type'] ) ? $option['type'] : 'text';
1✔
193
                                $label    = isset( $option['label'] ) ? $option['label'] : '';
1✔
194
                                $callback = isset( $option['callback'] ) ? $option['callback'] : [
1✔
195
                                        $this,
1✔
196
                                        'callback_' . $type,
1✔
197
                                ];
1✔
198

199
                                $args = [
1✔
200
                                        'id'                => $name,
1✔
201
                                        'class'             => isset( $option['class'] ) ? $option['class'] : $name,
1✔
202
                                        'label_for'         => "{$section}[{$name}]",
1✔
203
                                        'desc'              => isset( $option['desc'] ) ? $option['desc'] : '',
1✔
204
                                        'name'              => $label,
1✔
205
                                        'section'           => $section,
1✔
206
                                        'size'              => isset( $option['size'] ) ? $option['size'] : null,
1✔
207
                                        'options'           => isset( $option['options'] ) ? $option['options'] : '',
1✔
208
                                        'std'               => isset( $option['default'] ) ? $option['default'] : '',
1✔
209
                                        'sanitize_callback' => isset( $option['sanitize_callback'] ) ? $option['sanitize_callback'] : '',
1✔
210
                                        'type'              => $type,
1✔
211
                                        'placeholder'       => isset( $option['placeholder'] ) ? $option['placeholder'] : '',
1✔
212
                                        'min'               => isset( $option['min'] ) ? $option['min'] : '',
1✔
213
                                        'max'               => isset( $option['max'] ) ? $option['max'] : '',
1✔
214
                                        'step'              => isset( $option['step'] ) ? $option['step'] : '',
1✔
215
                                        'disabled'          => isset( $option['disabled'] ) ? (bool) $option['disabled'] : false,
1✔
216
                                        'value'             => isset( $option['value'] ) ? $option['value'] : null,
1✔
217
                                ];
1✔
218

219
                                add_settings_field( "{$section}[{$name}]", $label, $callback, $section, $section, $args );
1✔
220
                        }
221
                }
222

223
                // creates our settings in the options table
224
                foreach ( $this->settings_sections as $id => $section ) {
2✔
225
                        register_setting( $id, $id, [ $this, 'sanitize_options' ] );
2✔
226
                }
227
        }
228

229
        /**
230
         * Get field description for display
231
         *
232
         * @param array<string,string> $args settings field args
233
         */
234
        public function get_field_description( array $args ): string {
×
235
                if ( ! empty( $args['desc'] ) ) {
×
236
                        $desc = sprintf( '<p class="description">%s</p>', $args['desc'] );
×
237
                } else {
238
                        $desc = '';
×
239
                }
240

241
                return $desc;
×
242
        }
243

244
        /**
245
         * Displays a text field for a settings field
246
         *
247
         * @param array<string,mixed> $args settings field args
248
         *
249
         * @return void
250
         */
251
        public function callback_text( array $args ) {
×
252
                $value       = isset( $args['value'] ) && ! empty( $args['value'] ) ? esc_attr( $args['value'] ) : esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) );
×
253
                $size        = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular';
×
254
                $type        = isset( $args['type'] ) ? $args['type'] : 'text';
×
255
                $placeholder = empty( $args['placeholder'] ) ? '' : ' placeholder="' . $args['placeholder'] . '"';
×
256
                $disabled    = isset( $args['disabled'] ) && true === $args['disabled'] ? 'disabled' : null;
×
257
                $html        = sprintf( '<input type="%1$s" class="%2$s-text" id="%3$s[%4$s]" name="%3$s[%4$s]" value="%5$s"%6$s %7$s>', $type, $size, $args['section'], $args['id'], $value, $placeholder, $disabled );
×
258
                $html       .= $this->get_field_description( $args );
×
259

260
                echo wp_kses( $html, Utils::get_allowed_wp_kses_html() );
×
261
        }
262

263
        /**
264
         * Displays a url field for a settings field
265
         *
266
         * @param array<string,mixed> $args settings field args
267
         *
268
         * @return void
269
         */
270
        public function callback_url( array $args ) {
×
271
                $this->callback_text( $args );
×
272
        }
273

274
        /**
275
         * Displays a number field for a settings field
276
         *
277
         * @param array<string,mixed> $args settings field args
278
         *
279
         * @return void
280
         */
281
        public function callback_number( array $args ) {
×
282
                $value       = esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) );
×
283
                $size        = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular';
×
284
                $type        = isset( $args['type'] ) ? $args['type'] : 'number';
×
285
                $placeholder = empty( $args['placeholder'] ) ? '' : ' placeholder="' . $args['placeholder'] . '"';
×
286
                $min         = ( '' === $args['min'] ) ? '' : ' min="' . $args['min'] . '"';
×
287
                $max         = ( '' === $args['max'] ) ? '' : ' max="' . $args['max'] . '"';
×
288
                $step        = ( '' === $args['step'] ) ? '' : ' step="' . $args['step'] . '"';
×
289

290
                $html  = sprintf( '<input type="%1$s" class="%2$s-number" id="%3$s[%4$s]" name="%3$s[%4$s]" value="%5$s"%6$s%7$s%8$s%9$s>', $type, $size, $args['section'], $args['id'], $value, $placeholder, $min, $max, $step );
×
291
                $html .= $this->get_field_description( $args );
×
292

293
                echo wp_kses( $html, Utils::get_allowed_wp_kses_html() );
×
294
        }
295

296
        /**
297
         * Displays a checkbox for a settings field
298
         *
299
         * @param array<string,mixed> $args settings field args
300
         *
301
         * @return void
302
         */
303
        public function callback_checkbox( array $args ) {
×
304
                $value    = isset( $args['value'] ) && ! empty( $args['value'] ) ? esc_attr( $args['value'] ) : esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) );
×
305
                $disabled = isset( $args['disabled'] ) && true === $args['disabled'] ? 'disabled' : null;
×
306

307
                $html  = '<fieldset>';
×
308
                $html .= sprintf( '<label for="wpuf-%1$s[%2$s]">', $args['section'], $args['id'] );
×
309
                $html .= sprintf( '<input type="hidden" name="%1$s[%2$s]" value="off">', $args['section'], $args['id'] );
×
310
                $html .= sprintf( '<input type="checkbox" class="checkbox" id="wpuf-%1$s[%2$s]" name="%1$s[%2$s]" value="on" %3$s %4$s>', $args['section'], $args['id'], checked( $value, 'on', false ), $disabled );
×
311
                $html .= sprintf( '%1$s</label>', $args['desc'] );
×
312
                $html .= '</fieldset>';
×
313

314
                echo wp_kses( $html, Utils::get_allowed_wp_kses_html() );
×
315
        }
316

317
        /**
318
         * Displays a multicheckbox for a settings field
319
         *
320
         * @param array<string,mixed> $args settings field args
321
         *
322
         * @return void
323
         */
324
        public function callback_multicheck( array $args ) {
×
325
                $value = $this->get_option( $args['id'], $args['section'], $args['std'] );
×
326
                $html  = '<fieldset>';
×
327
                $html .= sprintf( '<input type="hidden" name="%1$s[%2$s]" value="">', $args['section'], $args['id'] );
×
328
                foreach ( $args['options'] as $key => $label ) {
×
329
                        $checked = isset( $value[ $key ] ) ? $value[ $key ] : '0';
×
330
                        $html   .= sprintf( '<label for="wpuf-%1$s[%2$s][%3$s]">', $args['section'], $args['id'], $key );
×
331
                        $html   .= sprintf( '<input type="checkbox" class="checkbox" id="wpuf-%1$s[%2$s][%3$s]" name="%1$s[%2$s][%3$s]" value="%3$s" %4$s>', $args['section'], $args['id'], $key, checked( $checked, $key, false ) );
×
332
                        $html   .= sprintf( '%1$s</label><br>', $label );
×
333
                }
334

335
                $html .= $this->get_field_description( $args );
×
336
                $html .= '</fieldset>';
×
337

338
                echo wp_kses( $html, Utils::get_allowed_wp_kses_html() );
×
339
        }
340

341
        /**
342
         * Displays a radio button for a settings field
343
         *
344
         * @param array<string,mixed> $args settings field args
345
         *
346
         * @return void
347
         */
348
        public function callback_radio( array $args ) {
×
349
                $value = $this->get_option( $args['id'], $args['section'], $args['std'] );
×
350
                $html  = '<fieldset>';
×
351

352
                foreach ( $args['options'] as $key => $label ) {
×
353
                        $html .= sprintf( '<label for="wpuf-%1$s[%2$s][%3$s]">', $args['section'], $args['id'], $key );
×
354
                        $html .= sprintf( '<input type="radio" class="radio" id="wpuf-%1$s[%2$s][%3$s]" name="%1$s[%2$s]" value="%3$s" %4$s>', $args['section'], $args['id'], $key, checked( $value, $key, false ) );
×
355
                        $html .= sprintf( '%1$s</label><br>', $label );
×
356
                }
357

358
                $html .= $this->get_field_description( $args );
×
359
                $html .= '</fieldset>';
×
360

361
                echo wp_kses( $html, Utils::get_allowed_wp_kses_html() );
×
362
        }
363

364
        /**
365
         * Displays a selectbox for a settings field
366
         *
367
         * @param array<string,mixed> $args settings field args
368
         *
369
         * @return void
370
         */
371
        public function callback_select( array $args ) {
×
372
                $value = esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) );
×
373
                $size  = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular';
×
374
                $html  = sprintf( '<select class="%1$s" name="%2$s[%3$s]" id="%2$s[%3$s]">', $size, $args['section'], $args['id'] );
×
375

376
                foreach ( $args['options'] as $key => $label ) {
×
377
                        $html .= sprintf( '<option value="%s"%s>%s</option>', $key, selected( $value, $key, false ), $label );
×
378
                }
379

380
                $html .= sprintf( '</select>' );
×
381
                $html .= $this->get_field_description( $args );
×
382

383
                echo wp_kses( $html, Utils::get_allowed_wp_kses_html() );
×
384
        }
385

386
        /**
387
         * Displays a textarea for a settings field
388
         *
389
         * @param array<string,mixed> $args settings field args
390
         *
391
         * @return void
392
         */
393
        public function callback_textarea( array $args ) {
×
394
                $value       = esc_textarea( $this->get_option( $args['id'], $args['section'], $args['std'] ) );
×
395
                $size        = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular';
×
396
                $placeholder = empty( $args['placeholder'] ) ? '' : ' placeholder="' . $args['placeholder'] . '"';
×
397

398
                $html  = sprintf( '<textarea rows="5" cols="55" class="%1$s-text" id="%2$s[%3$s]" name="%2$s[%3$s]"%4$s>%5$s</textarea>', $size, $args['section'], $args['id'], $placeholder, $value );
×
399
                $html .= $this->get_field_description( $args );
×
400

401
                echo wp_kses( $html, Utils::get_allowed_wp_kses_html() );
×
402
        }
403

404
        /**
405
         * Displays the html for a settings field
406
         *
407
         * @param array<string,mixed> $args settings field args
408
         *
409
         * @return void
410
         */
411
        public function callback_html( array $args ) {
×
412
                echo wp_kses( $this->get_field_description( $args ), Utils::get_allowed_wp_kses_html() );
×
413
        }
414

415
        /**
416
         * Displays a rich text textarea for a settings field
417
         *
418
         * @param array<string,mixed> $args settings field args
419
         *
420
         * @return void
421
         */
422
        public function callback_wysiwyg( array $args ) {
×
423
                $value = $this->get_option( $args['id'], $args['section'], $args['std'] );
×
424
                $size  = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : '500px';
×
425

426
                echo '<div style="max-width: ' . esc_attr( $size ) . ';">';
×
427

428
                $editor_settings = [
×
429
                        'teeny'         => true,
×
430
                        'textarea_name' => $args['section'] . '[' . $args['id'] . ']',
×
431
                        'textarea_rows' => 10,
×
432
                ];
×
433

434
                if ( isset( $args['options'] ) && is_array( $args['options'] ) ) {
×
435
                        $editor_settings = array_merge( $editor_settings, $args['options'] );
×
436
                }
437

438
                wp_editor( $value, $args['section'] . '-' . $args['id'], $editor_settings );
×
439

440
                echo '</div>';
×
441

442
                echo wp_kses( $this->get_field_description( $args ), Utils::get_allowed_wp_kses_html() );
×
443
        }
444

445
        /**
446
         * Displays a file upload field for a settings field
447
         *
448
         * @param array<string,mixed> $args settings field args
449
         *
450
         * @return void
451
         */
452
        public function callback_file( array $args ) {
×
453
                $value = esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) );
×
454
                $size  = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular';
×
455
                $label = isset( $args['options']['button_label'] ) ? $args['options']['button_label'] : __( 'Choose File', 'wp-graphql' );
×
456

457
                $html  = sprintf( '<input type="text" class="%1$s-text wpsa-url" id="%2$s[%3$s]" name="%2$s[%3$s]" value="%4$s">', $size, $args['section'], $args['id'], $value );
×
458
                $html .= '<input type="button" class="button wpsa-browse" value="' . $label . '">';
×
459
                $html .= $this->get_field_description( $args );
×
460

461
                echo wp_kses( $html, Utils::get_allowed_wp_kses_html() );
×
462
        }
463

464
        /**
465
         * Displays a password field for a settings field
466
         *
467
         * @param array<string,mixed> $args settings field args
468
         *
469
         * @return void
470
         */
471
        public function callback_password( array $args ) {
×
472
                $value = esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) );
×
473
                $size  = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular';
×
474

475
                $html  = sprintf( '<input type="password" class="%1$s-text" id="%2$s[%3$s]" name="%2$s[%3$s]" value="%4$s">', $size, $args['section'], $args['id'], $value );
×
476
                $html .= $this->get_field_description( $args );
×
477

478
                echo wp_kses( $html, Utils::get_allowed_wp_kses_html() );
×
479
        }
480

481
        /**
482
         * Displays a color picker field for a settings field
483
         *
484
         * @param array<string,mixed> $args settings field args
485
         *
486
         * @return void
487
         */
488
        public function callback_color( $args ) {
×
489
                $value = esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) );
×
490
                $size  = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular';
×
491

492
                $html  = sprintf( '<input type="text" class="%1$s-text wp-color-picker-field" id="%2$s[%3$s]" name="%2$s[%3$s]" value="%4$s" data-default-color="%5$s">', $size, $args['section'], $args['id'], $value, $args['std'] );
×
493
                $html .= $this->get_field_description( $args );
×
494

495
                echo wp_kses( $html, Utils::get_allowed_wp_kses_html() );
×
496
        }
497

498
        /**
499
         * Displays a select box for creating the pages select box
500
         *
501
         * @param array<string,mixed> $args settings field args
502
         *
503
         * @return void
504
         */
505
        public function callback_pages( array $args ) {
×
506
                $dropdown_args = array_merge(
×
507
                        [
×
508
                                'selected' => esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) ),
×
509
                                'name'     => $args['section'] . '[' . $args['id'] . ']',
×
510
                                'id'       => $args['section'] . '[' . $args['id'] . ']',
×
511
                                'echo'     => 0,
×
512
                        ],
×
513
                        $args
×
514
                );
×
515

516
                $clean_args = [];
×
517
                foreach ( $dropdown_args as $key => $arg ) {
×
518
                        $clean_args[ $key ] = wp_kses( $arg, Utils::get_allowed_wp_kses_html() );
×
519
                }
520

521
                // Ignore phpstan as this is providing an array as expected
522
                // @phpstan-ignore-next-line
523
                echo wp_dropdown_pages( $clean_args ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
×
524
        }
525

526
        /**
527
         * Displays a select box for user roles
528
         *
529
         * @param array<string,mixed> $args settings field args
530
         *
531
         * @return void
532
         */
533
        public function callback_user_role_select( array $args ) {
×
534
                $selected = esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) );
×
535

536
                if ( empty( $selected ) ) {
×
537
                        $selected = isset( $args['default'] ) ? $args['default'] : null;
×
538
                }
539

540
                $name = $args['section'] . '[' . $args['id'] . ']';
×
541
                $id   = $args['section'] . '[' . $args['id'] . ']';
×
542

543
                echo '<select id="' . esc_attr( $id ) . '" name="' . esc_attr( $name ) . '">';
×
544
                echo '<option value="any">Any</option>';
×
545
                wp_dropdown_roles( $selected );
×
546
                echo '</select>';
×
547
                echo wp_kses( $this->get_field_description( $args ), Utils::get_allowed_wp_kses_html() );
×
548
        }
549

550
        /**
551
         * Sanitize callback for Settings API
552
         *
553
         * @param mixed $options settings field args (can be array or other types when called via WordPress sanitize_option filter)
554
         *
555
         * @return mixed
556
         */
557
        public function sanitize_options( $options ) {
5✔
558
                // If not an array, return as-is (WordPress may pass non-array values via sanitize_option filter)
559
                if ( ! is_array( $options ) ) {
5✔
560
                        return $options;
2✔
561
                }
562

563
                if ( ! $options ) {
3✔
564
                        return $options;
1✔
565
                }
566

567
                foreach ( $options as $option_slug => $option_value ) {
2✔
568
                        $sanitize_callback = $this->get_sanitize_callback( $option_slug );
2✔
569

570
                        // If callback is set, call it
571
                        if ( $sanitize_callback ) {
2✔
572
                                $options[ $option_slug ] = call_user_func( $sanitize_callback, $option_value );
1✔
573
                                continue;
1✔
574
                        }
575
                }
576

577
                return $options;
2✔
578
        }
579

580
        /**
581
         * Get sanitization callback for given option slug
582
         *
583
         * @param string $slug option slug
584
         *
585
         * @return callable|false
586
         */
587
        public function get_sanitize_callback( $slug = '' ) {
2✔
588
                if ( empty( $slug ) ) {
2✔
589
                        return false;
×
590
                }
591

592
                // Iterate over registered fields and see if we can find proper callback
593
                foreach ( $this->settings_fields as $options ) {
2✔
594
                        foreach ( $options as $option ) {
1✔
595
                                if ( $slug !== $option['name'] ) {
1✔
596
                                        continue;
×
597
                                }
598

599
                                // Return the callback name
600
                                return isset( $option['sanitize_callback'] ) && is_callable( $option['sanitize_callback'] ) ? $option['sanitize_callback'] : false;
1✔
601
                        }
602
                }
603

604
                return false;
1✔
605
        }
606

607
        /**
608
         * Get the value of a settings field
609
         *
610
         * @param string $option  settings field name
611
         * @param string $section the section name this field belongs to
612
         * @param string $default_value default text if it's not found
613
         *
614
         * @return string
615
         */
616
        public function get_option( $option, $section, $default_value = '' ) {
×
617
                $options = get_option( $section );
×
618

619
                if ( isset( $options[ $option ] ) ) {
×
620
                        return $options[ $option ];
×
621
                }
622

623
                return $default_value;
×
624
        }
625

626
        /**
627
         * Show navigations as tab
628
         *
629
         * Shows all the settings section labels as tab
630
         *
631
         * @return void
632
         */
633
        public function show_navigation() {
×
634
                $html = '<h2 class="nav-tab-wrapper">';
×
635

636
                $count = count( $this->settings_sections );
×
637

638
                // don't show the navigation if only one section exists
639
                if ( 1 === $count ) {
×
640
                        return;
×
641
                }
642

643
                foreach ( $this->settings_sections as $tab ) {
×
644
                        $html .= sprintf( '<a href="#%1$s" class="nav-tab" id="%1$s-tab">%2$s</a>', $tab['id'], $tab['title'] );
×
645
                }
646

647
                $html .= '</h2>';
×
648

649
                echo wp_kses( $html, Utils::get_allowed_wp_kses_html() );
×
650
        }
651

652
        /**
653
         * Show the section settings forms
654
         *
655
         * This function displays every sections in a different form
656
         *
657
         * @return void
658
         */
659
        public function show_forms() {
×
660
                ?>
661
                <div class="metabox-holder">
×
662
                        <?php foreach ( $this->settings_sections as $id => $form ) { ?>
×
663
                                <div id="<?php echo esc_attr( $id ); ?>" class="group" style="display: none;">
×
664
                                        <form method="post" action="options.php">
665
                                                <?php
666
                                                do_action( 'graphql_settings_form_top', $form );
×
667
                                                settings_fields( $id );
×
668
                                                do_settings_sections( $id );
×
669
                                                do_action( 'graphql_settings_form_bottom', $form );
×
670
                                                if ( isset( $this->settings_fields[ $id ] ) ) :
×
671
                                                        ?>
672
                                                        <div style="padding-left: 10px">
×
673
                                                                <?php submit_button(); ?>
×
674
                                                        </div>
×
675
                                                <?php endif; ?>
×
676
                                        </form>
×
677
                                </div>
×
678
                        <?php } ?>
×
679
                </div>
×
680
                <?php
×
681
                $this->script();
×
682
        }
683

684
        /**
685
         * Tabbable JavaScript codes & Initiate Color Picker
686
         *
687
         * This code uses URL hash fragments and localStorage for displaying active tabs
688
         *
689
         * @return void
690
         */
691
        public function script() {
×
692
                ?>
693
                <script>
×
694
                        jQuery(document).ready(function ($) {
×
695
                                // Initiate Color Picker
×
696
                                $('.wp-color-picker-field').wpColorPicker();
×
697

698
                                // Switches option sections
×
699
                                $('.group').hide();
×
700
                                var activetab = '';
×
701
                                var urlHash = window.location.hash;
×
702

703
                                if (urlHash) {
×
704
                                        activetab = urlHash;
×
705
                                        if (typeof (localStorage) != 'undefined') {
×
706
                                                localStorage.setItem("activetab", activetab);
×
707
                                        }
×
708
                                } else if (typeof (localStorage) != 'undefined') {
×
709
                                        activetab = localStorage.getItem("activetab");
×
710
                                }
×
711

712
                                if (activetab != '' && $(activetab).length) {
×
713
                                        $(activetab).fadeIn();
×
714
                                } else {
×
715
                                        $('.group:first').fadeIn();
×
716
                                }
×
717

718
                                $('.group .collapsed').each(function () {
×
719
                                        $(this).find('input:checked').parent().parent().parent().nextAll().each(
×
720
                                                function () {
×
721
                                                        if ($(this).hasClass('last')) {
×
722
                                                                $(this).removeClass('hidden');
×
723
                                                                return false;
×
724
                                                        }
×
725
                                                        $(this).filter('.hidden').removeClass('hidden');
×
726
                                                });
×
727
                                });
×
728

729
                                if (activetab != '' && $(activetab + '-tab').length) {
×
730
                                        $(activetab + '-tab').addClass('nav-tab-active');
×
731
                                } else {
×
732
                                        $('.nav-tab-wrapper a:first').addClass('nav-tab-active');
×
733
                                }
×
734

735
                                $('.nav-tab-wrapper a').click(function (evt) {
×
736
                                        $('.nav-tab-wrapper a').removeClass('nav-tab-active');
×
737
                                        $(this).addClass('nav-tab-active').blur();
×
738
                                        var clicked_group = $(this).attr('href');
×
739
                                        if (typeof (localStorage) != 'undefined') {
×
740
                                                localStorage.setItem("activetab", clicked_group);
×
741
                                        }
×
742
                                        history.replaceState(null, '', clicked_group);
×
743
                                        $('.group').hide();
×
744
                                        $(clicked_group).fadeIn();
×
745
                                        evt.preventDefault();
×
746
                                });
×
747

748
                                $('.wpsa-browse').on('click', function (event) {
×
749
                                        event.preventDefault();
×
750

751
                                        var self = $(this);
×
752

753
                                        // Create the media frame.
×
754
                                        var file_frame = wp.media.frames.file_frame = wp.media({
×
755
                                                title: self.data('uploader_title'),
×
756
                                                button: {
×
757
                                                        text: self.data('uploader_button_text'),
×
758
                                                },
×
759
                                                multiple: false
×
760
                                        });
×
761

762
                                        file_frame.on('select', function () {
×
763
                                                attachment = file_frame.state().get('selection').first().toJSON();
×
764
                                                self.prev('.wpsa-url').val(attachment.url).change();
×
765
                                        });
×
766

767
                                        // Finally, open the modal
×
768
                                        file_frame.open();
×
769
                                });
×
770
                        });
×
771
                </script>
×
772
                <?php
×
773
                $this->_style_fix();
×
774
        }
775

776
        /**
777
         * Add styles to adjust some settings
778
         *
779
         * @return void
780
         */
781
        public function _style_fix() { // phpcs:ignore PSR2.Methods.MethodDeclaration.Underscore
×
782
                global $wp_version;
×
783

784
                if ( version_compare( $wp_version, '3.8', '<=' ) ) :
×
785
                        ?>
786
                        <style type="text/css">
×
787
                                /** WordPress 3.8 Fix **/
×
788
                                .form-table th {
×
789
                                        padding: 20px 10px;
×
790
                                }
×
791

792
                                #wpbody-content .metabox-holder {
×
793
                                        padding-top: 5px;
×
794
                                }
×
795
                        </style>
×
796
                        <?php
×
797
                endif;
798
        }
799
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc