PluginProbe ʕ •ᴥ•ʔ
Post Views Counter / trunk
Post Views Counter vtrunk
1.7.13 1.7.12 1.7.11 trunk 1.0.0 1.0.1 1.0.10 1.0.11 1.0.12 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.2.0 1.2.1 1.2.10 1.2.11 1.2.12 1.2.13 1.2.14 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3 1.3.1 1.3.10 1.3.11 1.3.12 1.3.13 1.3.2 1.3.2.1 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.7.0 1.7.1 1.7.10 1.7.2 1.7.3 1.7.4 1.7.5 1.7.6 1.7.7 1.7.8 1.7.9
post-views-counter / includes / class-settings-api.php
post-views-counter / includes Last commit date
class-admin.php 3 months ago class-columns-modal.php 1 month ago class-columns.php 2 weeks ago class-counter.php 2 months ago class-crawler-detect.php 7 months ago class-cron.php 1 month ago class-dashboard.php 1 month ago class-emails-mailer.php 1 month ago class-emails-period.php 1 month ago class-emails-query.php 1 month ago class-emails-scheduler.php 1 month ago class-emails-template.php 1 month ago class-emails.php 1 month ago class-frontend.php 2 weeks ago class-functions.php 1 year ago class-import.php 2 months ago class-integration-gutenberg.php 6 months ago class-integrations.php 2 months ago class-query.php 2 months ago class-settings-api.php 1 month ago class-settings-display.php 4 months ago class-settings-emails.php 1 month ago class-settings-general.php 1 month ago class-settings-integrations.php 5 months ago class-settings-other.php 1 month ago class-settings-reports.php 1 month ago class-settings.php 1 month ago class-toolbar.php 3 months ago class-traffic-signals.php 2 months ago class-update.php 1 month ago class-widgets.php 1 month ago functions.php 1 month ago
class-settings-api.php
1279 lines
1 <?php
2 // exit if accessed directly
3 if ( ! defined( 'ABSPATH' ) )
4 exit;
5
6 /**
7 * Post_Views_Counter_Settings_API class.
8 *
9 * @class Post_Views_Counter_Settings_API
10 */
11 class Post_Views_Counter_Settings_API {
12
13 private $settings = [];
14 private $input_settings = [];
15 private $validated_settings = [];
16 private $pages = [];
17 private $page_types = [];
18 private $prefix = '';
19 private $slug = '';
20 private $domain = '';
21 private $plugin = '';
22 private $plugin_url = '';
23 private $object;
24 private $nested = false;
25
26 /**
27 * Class constructor.
28 *
29 * @return void
30 */
31 public function __construct( $args ) {
32 // set initial data
33 $this->prefix = $args['prefix'];
34 $this->domain = $args['domain'];
35 $this->nested = isset( $args['nested'] ) ? (bool) $args['nested'] : false;
36
37 // empty slug?
38 if ( empty( $args['slug'] ) )
39 $this->slug = $args['domain'];
40 else
41 $this->slug = $args['slug'];
42
43 $this->object = $args['object'];
44 $this->plugin = $args['plugin'];
45 $this->plugin_url = $args['plugin_url'];
46
47 // actions
48 add_action( 'admin_menu', [ $this, 'admin_menu_options' ], 11 );
49 add_action( 'admin_init', [ $this, 'register_settings' ], 11 );
50 add_action( 'admin_enqueue_scripts', [ $this, 'admin_enqueue_scripts' ] );
51 }
52
53 /**
54 * Get prefix.
55 *
56 * @return string
57 */
58 public function get_prefix() {
59 return $this->prefix;
60 }
61
62 /**
63 * Get pages.
64 *
65 * @return array
66 */
67 public function get_pages() {
68 return $this->pages;
69 }
70
71 /**
72 * Get settings.
73 *
74 * @return array
75 */
76 public function get_settings() {
77 return $this->settings;
78 }
79
80 /**
81 * Get current input settings during saving.
82 *
83 * @return array
84 */
85 public function get_input_settings() {
86 return $this->input_settings;
87 }
88
89 /**
90 * Get already validated setting fields during saving.
91 *
92 * @return array
93 */
94 public function get_validated_settings() {
95 return $this->validated_settings;
96 }
97
98 /**
99 * Get resolved defaults for a settings group.
100 *
101 * Allows settings objects to provide dynamic defaults for a group,
102 * such as the Emails recipient defaulting to the site admin email.
103 *
104 * @param string $setting_id
105 * @return array
106 */
107 private function get_setting_defaults( $setting_id ) {
108 $defaults = isset( $this->object->defaults[$setting_id] ) && is_array( $this->object->defaults[$setting_id] ) ? $this->object->defaults[$setting_id] : [];
109 $callback = 'get_default_' . str_replace( '-', '_', $setting_id ) . '_settings';
110
111 if ( is_object( $this->object ) && method_exists( $this->object, $callback ) ) {
112 $resolved_defaults = call_user_func( [ $this->object, $callback ] );
113
114 if ( is_array( $resolved_defaults ) )
115 return $resolved_defaults;
116 }
117
118 return $defaults;
119 }
120
121 /**
122 * Load default scripts and styles.
123 *
124 * @return void
125 */
126 public function admin_enqueue_scripts() {
127 // Legacy inline styles for disabled tabs
128 $handler = $this->prefix . '-settings-api-style';
129 wp_register_style( $handler, false );
130 wp_enqueue_style( $handler );
131
132 wp_add_inline_style( $handler, '.nav-tab-wrapper span.nav-span-disabled {
133 cursor: not-allowed;
134 float: left;
135 }
136 body.rtl .nav-tab-wrapper span.nav-span-disabled {
137 float: right;
138 }
139 .nav-tab-wrapper a.nav-tab.nav-tab-disabled {
140 pointer-events: none;
141 }
142 .nav-tab-wrapper a.nav-tab.nav-tab-disabled:hover {
143 cursor: not-allowed;
144 }' );
145
146 if ( $this->current_page_has_field_type( 'editor' ) )
147 wp_enqueue_editor();
148 }
149
150 /**
151 * Determine whether the current settings view contains a given field type.
152 *
153 * @param string $field_type
154 * @return bool
155 */
156 private function current_page_has_field_type( $field_type ) {
157 if ( empty( $this->settings ) || empty( $this->pages ) || empty( $_GET['page'] ) )
158 return false;
159
160 $field_type = sanitize_key( $field_type );
161 $page_slug = sanitize_key( wp_unslash( $_GET['page'] ) );
162
163 if ( $field_type === '' || $page_slug === '' )
164 return false;
165
166 foreach ( $this->pages as $page_key => $page ) {
167 if ( empty( $page['menu_slug'] ) || sanitize_key( $page['menu_slug'] ) !== $page_slug )
168 continue;
169
170 $active_tab = '';
171
172 if ( ! empty( $page['tabs'] ) && is_array( $page['tabs'] ) ) {
173 reset( $page['tabs'] );
174 $active_tab = key( $page['tabs'] );
175
176 if ( ! empty( $_GET['tab'] ) ) {
177 $requested_tab = sanitize_key( wp_unslash( $_GET['tab'] ) );
178
179 if ( array_key_exists( $requested_tab, $page['tabs'] ) )
180 $active_tab = $requested_tab;
181 }
182 }
183
184 if ( empty( $this->settings[$page_key]['fields'] ) || ! is_array( $this->settings[$page_key]['fields'] ) )
185 return false;
186
187 foreach ( $this->settings[$page_key]['fields'] as $field ) {
188 if ( empty( $field['type'] ) || sanitize_key( $field['type'] ) !== $field_type )
189 continue;
190
191 if ( ! empty( $field['tab'] ) && $active_tab !== '' && $field['tab'] !== $active_tab )
192 continue;
193
194 return true;
195 }
196
197 return false;
198 }
199
200 return false;
201 }
202
203 /**
204 * Add menu pages.
205 *
206 * @return void
207 */
208 public function admin_menu_options() {
209 $this->pages = apply_filters( $this->prefix . '_settings_pages', [] );
210 $types = [
211 'page' => [],
212 'subpage' => [],
213 'settings_page' => []
214 ];
215
216 foreach ( $this->pages as $page => $data ) {
217 // skip invalid page types
218 if ( empty( $data['type'] ) || ! array_key_exists( $data['type'], $types ) )
219 continue;
220
221 if ( $data['type'] === 'page' ) {
222 add_menu_page( $data['page_title'], $data['menu_title'], $data['capability'], $data['menu_slug'], ! empty( $data['callback'] ) ? $data['callback'] : [ $this, 'options_page' ], $data['icon'], $data['position'] );
223
224 // add page type
225 $types['page'][$data['menu_slug']] = $page;
226 // menu subpage?
227 } elseif ( $data['type'] === 'subpage' ) {
228 add_submenu_page( $data['parent_slug'], $data['page_title'], $data['menu_title'], $data['capability'], $data['menu_slug'], ! empty( $data['callback'] ) ? $data['callback'] : [ $this, 'options_page' ] );
229
230 // add subpage type
231 $types['subpage'][$data['menu_slug']] = $page;
232 // menu settings page?
233 } elseif ( $data['type'] === 'settings_page' ) {
234 add_options_page( $data['page_title'], $data['menu_title'], $data['capability'], $data['menu_slug'], ! empty( $data['callback'] ) ? $data['callback'] : [ $this, 'options_page' ] );
235
236 // add settings type
237 $types['settings_page'][$data['menu_slug']] = $page;
238 }
239 }
240
241 // set page types
242 $this->page_types = $types;
243 }
244
245 /**
246 * Render settings.
247 *
248 * @global string $pagenow
249 *
250 * @return void
251 */
252 public function options_page() {
253 global $pagenow;
254
255 $valid_page = false;
256
257 // get current screen
258 $screen = get_current_screen();
259
260 // display top level settings page?
261 if ( $pagenow === 'admin.php' && preg_match( '/^toplevel_page_(' . implode( '|', $this->page_types['page'] ) . ')$/', $screen->base, $matches ) === 1 && ! empty( $matches[1] ) ) {
262 $valid_page = true;
263 $page_type = 'page';
264 $url_page = 'admin.php';
265 }
266
267 // display settings page?
268 if ( ! $valid_page && $pagenow === 'options-general.php' && preg_match( '/^(?:settings_page_)(' . implode( '|', array_keys( $this->page_types['settings_page'] ) ) . ')$/', $screen->base, $matches ) === 1 ) {
269 $valid_page = true;
270 $page_type = 'settings_page';
271 $url_page = 'options-general.php';
272 }
273
274 // skip invalid pages
275 if ( ! $valid_page )
276 return;
277
278 $page_key = $this->page_types[$page_type][$matches[1]];
279 $tab_key = '';
280 $tabs = [];
281
282 // any tabs?
283 if ( array_key_exists( 'tabs', $this->pages[$page_key] ) ) {
284 // get tabs
285 $tabs = $this->pages[$page_key]['tabs'];
286
287 // reset tabs
288 reset( $tabs );
289
290 // get first default tab
291 $first_tab = key( $tabs );
292
293 // get current tab
294 $tab_key = ! empty( $_GET['tab'] ) && array_key_exists( $_GET['tab'], $tabs ) ? $_GET['tab'] : $first_tab;
295
296 // check current tab
297 if ( ! empty( $_GET['tab'] ) )
298 $tab_key = sanitize_key( $_GET['tab'] );
299
300 // invalid tab?
301 if ( ! array_key_exists( $tab_key, $tabs ) )
302 $tab_key = $first_tab;
303
304 $tab_label = ! empty( $tabs[$tab_key]['label'] ) ? $tabs[$tab_key]['label'] : '';
305 $tab_heading = ! empty( $tabs[$tab_key]['heading'] ) ? $tabs[$tab_key]['heading'] : '';
306 } else
307 $tab_label = '';
308
309 if ( empty( $tabs ) )
310 $tab_heading = '';
311
312 $heading = $this->plugin;
313
314 echo '
315 <div class="wrap ' . $this->prefix . '-settings-wrapper' . '" data-settings-prefix="' . esc_attr( $this->prefix ) . '">
316 <div class="header-wrapper">
317 <span class="header-title">' . esc_html( $heading ) . '</span>
318 </div>';
319
320 if ( ! empty( $tabs ) ) {
321 echo '
322 <nav class="nav-tab-wrapper">';
323
324 foreach ( $tabs as $key => $tab ) {
325 if ( ! empty( $tab['disabled'] ) )
326 $url = '';
327 else
328 $url = admin_url( $url_page . '?page=' . $matches[1] . '&tab=' . $key );
329
330 if ( ! empty( $tab['disabled'] ) )
331 echo '<span class="nav-span-disabled">';
332
333 echo '
334 <a class="nav-tab' . ( $tab_key === $key ? ' nav-tab-active' : '' ) . ( ! empty( $tab['disabled'] ) ? ' nav-tab-disabled' : '' ) . ( ! empty( $tab['class'] ) ? ' ' . esc_attr( $tab['class'] ) : '' ) . '" href="' . ( $url !== '' ? esc_url( $url ) : '#' ) . '">' . esc_html( $tab['label'] ) . '</a>';
335
336 if ( ! empty( $tab['disabled'] ) )
337 echo '</span>';
338 }
339
340 echo '
341 </nav>';
342 }
343
344 echo '
345 <div class="content-wrapper">
346 <h1 class="screen-reader-text">' . esc_html( $heading ) . '</h1>';
347
348 // skip for internal options page
349 if ( $page_type !== 'settings_page' )
350 settings_errors();
351
352 // get settings page classes
353 $settings_class = apply_filters( $this->prefix . '_settings_page_class', [ $this->slug . '-settings', $tab_key . '-settings', $this->prefix . '-settings' ] );
354
355 // sanitize settings page classes
356 $settings_class = array_unique( array_filter( array_map( 'sanitize_html_class', $settings_class ) ) );
357
358 // resolve setting group for sidebar/form
359 if ( ! empty( $tab_key ) ) {
360 if ( ! empty( $tabs[$tab_key]['option_name'] ) ) {
361 $setting = $tabs[$tab_key]['option_name'];
362 } else {
363 $setting = $this->prefix . '_' . $tab_key . '_settings';
364 }
365 } else {
366 $setting = $this->prefix . '_' . $matches[1] . '_settings';
367 }
368
369 // capture sidebar output
370 ob_start();
371 do_action( $this->prefix . '_settings_sidebar', $setting, $page_type, $url_page, $tab_key );
372 $sidebar_html = trim( ob_get_clean() );
373
374 // add has-sidebar class if sidebar has content
375 if ( ! empty( $sidebar_html ) ) {
376 $settings_class[] = 'has-sidebar';
377 }
378
379 echo '
380 <div class="' . implode( ' ', array_map( 'esc_attr', $settings_class ) ) . '">';
381
382 $display_form = true;
383
384 // check form attribute
385 if ( ! empty( $tab_key ) && ! empty( $tabs[$tab_key]['form'] ) ) {
386 $form = $tabs[$tab_key]['form'];
387
388 if ( isset( $form['buttons'] ) && ! $form['buttons'] )
389 $display_form = false;
390 } elseif ( ! empty( $tab_key ) && isset( $this->settings[$matches[1]]['form'][$tab_key] ) ) {
391 $form = $this->settings[$matches[1]]['form'][$tab_key];
392
393 if ( isset( $form['buttons'] ) && ! $form['buttons'] )
394 $display_form = false;
395 } elseif ( isset( $this->settings[$matches[1]]['form'] ) ) {
396 $form = $this->settings[$matches[1]]['form'];
397
398 if ( isset( $form['buttons'] ) && ! $form['buttons'] )
399 $display_form = false;
400 }
401
402 if ( $display_form ) {
403 echo '
404 <form action="options.php" method="post" novalidate class="' . $this->prefix . '-settings-form">';
405 }
406
407 settings_fields( $setting );
408
409 if ( $display_form )
410 do_action( $this->prefix . '_settings_form', $setting, $page_type, $url_page, $tab_key );
411
412 // filter sections by tab if tabs are present
413 global $wp_settings_sections;
414
415 $original_sections = $wp_settings_sections;
416
417 if ( ! empty( $tab_key ) && isset( $this->settings[$page_key]['sections'] ) ) {
418 $filtered_sections = [];
419
420 foreach ( $this->settings[$page_key]['sections'] as $section_id => $section ) {
421 // include sections without tab or matching current tab
422 if ( empty( $section['tab'] ) || $section['tab'] === $tab_key ) {
423 if ( isset( $wp_settings_sections[$setting][$section_id] ) ) {
424 $filtered_sections[$section_id] = $wp_settings_sections[$setting][$section_id];
425 }
426 }
427 }
428
429 // replace with filtered sections
430 if ( isset( $wp_settings_sections[$setting] ) ) {
431 $wp_settings_sections[$setting] = $filtered_sections;
432 }
433 }
434
435 do_settings_sections( $setting );
436
437 // restore original sections
438 $wp_settings_sections = $original_sections;
439
440 if ( $display_form ) {
441 $setting_hyphenated = str_replace( '_', '-', $setting );
442 $legacy_reset_class = 'reset_' . $setting;
443 echo '
444 <p class="submit">';
445
446 submit_button( '', 'primary save-' . $setting_hyphenated, 'save_' . $setting, false, [ 'id' => 'save-' . $setting_hyphenated ] );
447
448 submit_button( __( 'Reset to defaults', $this->domain ), 'outline reset_pvc_settings ' . $legacy_reset_class . ' reset-' . $setting_hyphenated, 'reset_' . $setting, false, [ 'id' => 'reset-' . $setting_hyphenated ] );
449
450 echo '
451 </p>
452 </form>';
453 }
454
455 // output sidebar if it has content
456 if ( ! empty( $sidebar_html ) ) {
457 echo '
458 <div class="' . $this->prefix . '-sidebar">' . $sidebar_html . '</div>';
459 }
460
461 echo '
462 </div>
463 </div>';
464
465 echo '
466 <div class="clear"></div>
467 </div>';
468 }
469
470 /**
471 * Register settings.
472 *
473 * @return void
474 */
475 public function register_settings() {
476 $this->settings = apply_filters( $this->prefix . '_settings_data', [] );
477
478 // check settings
479 foreach ( $this->settings as $setting_id => $setting ) {
480 // tabs?
481 if ( is_array( $setting['option_name'] ) ) {
482 foreach ( $setting['option_name'] as $tab => $option_name ) {
483 $this->register_setting_fields( $tab, $setting, $option_name );
484 }
485 } else
486 $this->register_setting_fields( $setting_id, $setting );
487 }
488 }
489
490 /**
491 * Register setting with sections and fields.
492 *
493 * @return void
494 */
495 public function register_setting_fields( $setting_id, $setting, $option_name = '' ) {
496 if ( empty( $option_name ) )
497 $option_name = $setting['option_name'];
498
499 // register setting
500 register_setting( $option_name, $option_name, ! empty( $setting['validate'] ) ? $setting['validate'] : [ $this, 'validate_settings' ] );
501
502 // register setting sections
503 if ( ! empty( $setting['sections'] ) ) {
504 foreach ( $setting['sections'] as $section_id => $section ) {
505 // skip unwanted sections
506 if ( ! empty( $section['tab'] ) && $section['tab'] !== $setting_id )
507 continue;
508
509 // Auto-generate section classes and wrapper
510 $base_slug = sanitize_html_class( str_replace( '_', '-', $section_id ) );
511 $section_prefix = apply_filters( $this->prefix . '_settings_section_prefix', $this->prefix );
512 $section_prefix = sanitize_html_class( $section_prefix );
513 $section_classes = $section_prefix . '-section ' . $section_prefix . '-section-' . $base_slug;
514 $section_args = [
515 'section_class' => $section_classes,
516 'before_section' => '<section id="' . $section_prefix . '-section-' . $base_slug . '" class="%s">',
517 'after_section' => '</section>',
518 ];
519
520 add_settings_section(
521 $section_id,
522 ! empty( $section['title'] ) ? esc_html( $section['title'] ) : '',
523 ! empty( $section['callback'] ) ? $section['callback'] : null,
524 ! empty( $section['page'] ) ? $section['page'] : $option_name,
525 $section_args
526 );
527 }
528 }
529
530 // register setting fields
531 if ( ! empty( $setting['fields'] ) ) {
532 foreach ( $setting['fields'] as $field_key => $field ) {
533 // skip unwanted fields
534 if ( ! empty( $field['tab'] ) && $field['tab'] !== $setting_id )
535 continue;
536
537 // set field ID
538 $field_id = implode( '_', [ $this->prefix, $setting_id, $field_key ] );
539
540 // skip rendering this field?
541 if ( ! empty( $field['skip_rendering'] ) )
542 continue;
543
544 // prepare field args
545 $args = array_merge( $this->prepare_field_args( $field, $field_id, $field_key, $setting_id, $option_name ), $field );
546 $args['setting_id'] = $setting_id;
547 $class = sanitize_html_class( str_replace( '_', '-', $field_id ) );
548 $classes = [ $class ];
549
550 if ( ! empty( $args['class'] ) ) {
551 $extra_classes = preg_split( '/\s+/', trim( $args['class'] ) );
552 $extra_classes = array_filter( $extra_classes );
553 $extra_classes = array_map( 'sanitize_html_class', $extra_classes );
554 $classes = array_merge( $classes, $extra_classes );
555 }
556
557 $classes = array_values( array_unique( array_filter( $classes ) ) );
558
559 $field_class = implode( ' ', $classes );
560 $wrapper_class = $class !== '' ? $class . '-row' : '';
561
562 // preserve user classes in wrapper
563 if ( ! empty( $field['class'] ) ) {
564 $wrapper_class .= ' ' . $field['class'];
565 }
566
567 $args['class'] = $wrapper_class;
568 $args['field_class'] = $field_class;
569 $args['css_id'] = $class;
570
571 add_settings_field(
572 $field_id,
573 ! empty( $field['title'] ) ? esc_html( $field['title'] ) : '',
574 [ $this, 'render_field' ],
575 $option_name,
576 ! empty( $field['section'] ) ? esc_attr( $field['section'] ) : '',
577 $args
578 );
579 }
580 }
581 }
582
583 /**
584 * Prepare field arguments.
585 *
586 * @param array $args
587 * @return array
588 */
589 public function prepare_field_args( $field, $field_id, $field_key, $setting_id, $setting_name ) {
590 // get field type
591 $field_type = ! empty( $field['type'] ) ? $field['type'] : '';
592
593 // default lookup path
594 $value = null;
595 $default = null;
596 $setting_defaults = $this->get_setting_defaults( $setting_id );
597 $name = $setting_name . '[' . $field_key . ']';
598
599 // check for parent
600 if ( ! empty( $field['parent'] ) ) {
601 $name = $setting_name . '[' . $field['parent'] . '][' . $field_key . ']';
602
603 // try with setting_id first
604 if ( isset( $this->object->options[$setting_id][$field['parent']][$field_key] ) ) {
605 $value = $this->object->options[$setting_id][$field['parent']][$field_key];
606 } elseif ( isset( $this->object->options[$field['parent']][$field_key] ) ) {
607 // try without setting_id
608 $value = $this->object->options[$field['parent']][$field_key];
609 }
610
611 // defaults
612 if ( isset( $setting_defaults[$field['parent']][$field_key] ) ) {
613 $default = $setting_defaults[$field['parent']][$field_key];
614 } elseif ( isset( $this->object->defaults[$field['parent']][$field_key] ) ) {
615 $default = $this->object->defaults[$field['parent']][$field_key];
616 }
617 } else {
618 // nested?
619 if ( $this->nested ) {
620 $name = $setting_name . '[' . $setting_id . '][' . $field_key . ']';
621
622 if ( isset( $this->object->options[$setting_id][$field_key] ) )
623 $value = $this->object->options[$setting_id][$field_key];
624
625 if ( isset( $setting_defaults[$field_key] ) )
626 $default = $setting_defaults[$field_key];
627 } else {
628 // flat
629 if ( isset( $this->object->options[$setting_id][$field_key] ) ) {
630 $value = $this->object->options[$setting_id][$field_key];
631 } elseif ( isset( $this->object->options[$field_key] ) ) {
632 $value = $this->object->options[$field_key];
633 }
634
635 // defaults
636 if ( isset( $setting_defaults[$field_key] ) ) {
637 $default = $setting_defaults[$field_key];
638 } elseif ( isset( $this->object->defaults[$field_key] ) ) {
639 $default = $this->object->defaults[$field_key];
640 }
641 }
642 }
643
644 if ( $field_type === 'custom' ) {
645 $value = null;
646 $default = null;
647 }
648
649 return [
650 'id' => $field_id,
651 'html_id' => sanitize_html_class( str_replace( '_', '-', $field_id ) ),
652 'name' => $name,
653 'class' => ! empty( $field['class'] ) ? $field['class'] : '',
654 'type' => $field_type,
655 'label' => ! empty( $field['label'] ) ? $field['label'] : '',
656 'description' => ! empty( $field['description'] ) ? $field['description'] : '',
657 'text' => ! empty( $field['text'] ) ? $field['text'] : '',
658 'min' => ! empty( $field['min'] ) ? (int) $field['min'] : 0,
659 'max' => ! empty( $field['max'] ) ? (int) $field['max'] : 0,
660 'options' => ! empty( $field['options'] ) ? $field['options'] : [],
661 'callback' => ! empty( $field['callback'] ) ? $field['callback'] : null,
662 'validate' => ! empty( $field['validate'] ) ? $field['validate'] : null,
663 'callback_args' => ! empty( $field['callback_args'] ) ? $field['callback_args'] : [],
664 'default' => $default,
665 'value' => $value,
666 'setting_id' => $setting_id,
667 'animation' => ! empty( $field['animation'] ) ? $field['animation'] : '',
668 'logic' => ! empty( $field['logic'] ) ? $field['logic'] : null,
669 'fallback_option' => ! empty( $field['fallback_option'] ) ? sanitize_key( $field['fallback_option'] ) : '',
670 'rows' => ! empty( $field['rows'] ) ? (int) $field['rows'] : 6,
671 'cols' => ! empty( $field['cols'] ) ? (int) $field['cols'] : 50
672 /*
673 after_field
674 before_field
675 */
676 ];
677 }
678
679 /**
680 * Render settings field.
681 *
682 * @param array $args
683 * @return void|string
684 */
685 public function render_field( $args ) {
686 if ( empty( $args ) || ! is_array( $args ) )
687 return;
688
689 // build wrapper classes
690 $wrapper_classes = [ $this->prefix . '-field', $this->prefix . '-field-type-' . $args['type'] ];
691 if ( ! empty( $args['class'] ) )
692 $wrapper_classes[] = $args['class'];
693
694 // add disabled class if field is disabled (but not if feature is available)
695 if ( ! empty( $args['disabled'] ) && $args['disabled'] === true && empty( $args['available'] ) )
696 $wrapper_classes[] = $this->prefix . '-disabled';
697
698 // build wrapper attributes
699 $wrapper_attrs = ' id="' . esc_attr( str_replace( '_', '-', $args['id'] ) ) . '-setting" class="' . esc_attr( implode( ' ', $wrapper_classes ) ) . '"';
700
701 // add conditional data attributes
702 $data_attrs = '';
703 $conditions = [];
704 $fallback_option = ! empty( $args['fallback_option'] ) ? $args['fallback_option'] : '';
705
706 if ( ! empty( $args['logic'] ) && is_array( $args['logic'] ) ) {
707 if ( isset( $args['logic']['field'] ) ) {
708 $conditions = [ $args['logic'] ];
709 } else {
710 $conditions = $args['logic'];
711 }
712 }
713
714 if ( ! empty( $conditions ) ) {
715 $data_attr_prefix = sanitize_html_class( $this->prefix );
716 $normalized_conditions = [];
717
718 foreach ( $conditions as $condition ) {
719 if ( empty( $condition['field'] ) || empty( $condition['operator'] ) ) {
720 continue;
721 }
722
723 $field = $condition['field'];
724
725 if ( strpos( $field, '-' ) === false && ! empty( $args['setting_id'] ) ) {
726 $field_id = implode( '_', [ $this->prefix, $args['setting_id'], $field ] );
727 $field = sanitize_html_class( str_replace( '_', '-', $field_id ) );
728 }
729
730 $normalized_conditions[] = [
731 'field' => $field,
732 'operator' => $condition['operator'],
733 'value' => isset( $condition['value'] ) ? $condition['value'] : '',
734 'scope' => ! empty( $condition['scope'] ) ? sanitize_key( $condition['scope'] ) : '',
735 'action' => ! empty( $condition['action'] ) ? sanitize_key( $condition['action'] ) : '',
736 'target' => ! empty( $condition['target'] ) ? sanitize_text_field( $condition['target'] ) : '',
737 'container' => ! empty( $condition['container'] ) ? sanitize_text_field( $condition['container'] ) : '',
738 ];
739 }
740
741 if ( ! empty( $normalized_conditions ) && $data_attr_prefix !== '' ) {
742 if ( ! empty( $args['animation'] ) && in_array( $args['animation'], [ 'fade', 'slide' ], true ) ) {
743 $data_attrs .= ' data-' . $data_attr_prefix . '-animation="' . esc_attr( $args['animation'] ) . '"';
744 }
745 $data_attrs .= ' data-' . $data_attr_prefix . '-logic="' . esc_attr( wp_json_encode( $normalized_conditions ) ) . '"';
746 }
747 }
748
749 if ( $fallback_option !== '' ) {
750 $data_attrs .= ' data-' . $this->prefix . '-fallback-option="' . esc_attr( $fallback_option ) . '"';
751 }
752
753 $wrapper_attrs .= $data_attrs;
754
755 $html = '<div' . $wrapper_attrs . '>';
756
757 if ( ! empty ( $args['before_field'] ) )
758 $html .= $args['before_field'];
759
760 switch ( $args['type'] ) {
761 case 'boolean':
762 if ( empty( $args['disabled'] ) )
763 $html .= '<input type="hidden" name="' . esc_attr( $args['name'] ) . '" value="false" />';
764
765 $html .= '<label><input id="' . esc_attr( $args['html_id'] ) . '" type="checkbox" role="switch" name="' . esc_attr( $args['name'] ) . '" value="true" ' . checked( (bool) $args['value'], true, false ) . ' ' . disabled( empty( $args['disabled'] ), false, false ) . ' />' . wp_kses_post( $args['label'] ) . '</label>';
766 break;
767
768 case 'radio':
769 if ( empty( $args['options'] ) || ! is_array( $args['options'] ) )
770 break;
771
772 $display_type = ! empty( $args['display_type'] ) && in_array( $args['display_type'], [ 'horizontal', 'vertical' ], true ) ? $args['display_type'] : 'vertical';
773
774 if ( count( $args['options'] ) > 1 )
775 $html .= '<div class="' . esc_attr( $this->prefix ) . '-field-group ' . esc_attr( $this->prefix ) . '-radio-group ' . $display_type . '">';
776 foreach ( $args['options'] as $key => $name ) {
777 $is_disabled = ! empty( $args['disabled'] ) && ( is_array( $args['disabled'] ) && in_array( $key, $args['disabled'], true ) || $args['disabled'] === true );
778 $label_classes = [];
779
780 if ( $is_disabled && is_array( $args['disabled'] ) )
781 $label_classes[] = $this->prefix . '-disabled';
782
783 // add disabled-state class for disabled options in extended fields
784 if ( $is_disabled && ! empty( $args['class'] ) && strpos( $args['class'], 'pvc-pro-extended' ) !== false ) {
785 $label_classes[] = $this->prefix . '-pro';
786 }
787
788 $label_class = ! empty( $label_classes ) ? ' class="' . implode( ' ', $label_classes ) . '"' : '';
789
790 $display_name = esc_html( $name );
791
792 $html .= '<label for="' . esc_attr( $args['html_id'] . '-' . $key ) . '"' . $label_class . '><input id="' . esc_attr( $args['html_id'] . '-' . $key ) . '" type="radio" name="' . esc_attr( $args['name'] ) . '" value="' . esc_attr( $key ) . '" ' . checked( $key, $args['value'], false ) . ' ' . disabled( $is_disabled, true, false ) . ' />' . $display_name . '</label> ';
793 }
794 if ( count( $args['options'] ) > 1 )
795 $html .= '</div>';
796 break;
797
798 case 'checkbox':
799 // possible "empty" value
800 if ( $args['value'] === 'empty' )
801 $args['value'] = [];
802
803 // ensure value is an array
804 if ( ! is_array( $args['value'] ) )
805 $args['value'] = [];
806
807 $display_type = ! empty( $args['display_type'] ) && in_array( $args['display_type'], [ 'horizontal', 'vertical' ], true ) ? $args['display_type'] : 'vertical';
808
809 $html .= '<input type="hidden" name="' . esc_attr( $args['name'] ) . '" value="empty" />';
810
811 if ( empty( $args['options'] ) || ! is_array( $args['options'] ) )
812 break;
813 if ( count( $args['options'] ) > 1 )
814 $html .= '<div class="' . esc_attr( $this->prefix ) . '-field-group ' . esc_attr( $this->prefix ) . '-checkbox-group ' . $display_type . '">';
815 foreach ( $args['options'] as $key => $name ) {
816 $is_disabled = ! empty( $args['disabled'] ) && ( is_array( $args['disabled'] ) && in_array( $key, $args['disabled'], true ) || $args['disabled'] === true );
817 $label_classes = [];
818
819 if ( $is_disabled && is_array( $args['disabled'] ) )
820 $label_classes[] = $this->prefix . '-disabled';
821
822 // add disabled-state styling for disabled options in extended fields
823 if ( $is_disabled && ! empty( $args['class'] ) && strpos( $args['class'], 'pvc-pro-extended' ) !== false )
824 $label_classes[] = $this->prefix . '-pro';
825
826 $label_class = ! empty( $label_classes ) ? ' class="' . implode( ' ', $label_classes ) . '"' : '';
827
828 $display_name = esc_html( $name );
829
830 $html .= '<label' . $label_class . '><input id="' . esc_attr( $args['html_id'] . '-' . $key ) . '" type="checkbox" name="' . esc_attr( $args['name'] ) . '[]" value="' . esc_attr( $key ) . '" ' . checked( in_array( $key, $args['value'] ), true, false ) . ' ' . disabled( $is_disabled, true, false ) . ' />' . $display_name . '</label>';
831 }
832 if ( count( $args['options'] ) > 1 )
833 $html .= '</div>';
834 break;
835
836 case 'select':
837 $html .= '<select id="' . esc_attr( $args['html_id'] ) . '" name="' . esc_attr( $args['name'] ) . '" ' . disabled( empty( $args['disabled'] ), false, false ) . '/>';
838
839 foreach ( $args['options'] as $key => $name ) {
840 $html .= '<option value="' . esc_attr( $key ) . '" ' . selected( $args['value'], $key, false ) . '>' . esc_html( $name ) . '</option>';
841 }
842
843 $html .= '</select>';
844 break;
845
846 case 'range':
847 $html .= '<input id="' . esc_attr( $args['html_id'] ) . '-slider" type="range" name="' . esc_attr( $args['name'] ) . '" value="' . esc_attr( $args['value'] ) . '" min="' . esc_attr( $args['min'] ) . '" max="' . esc_attr( $args['max'] ) . '" data-range-output="' . esc_attr( $args['html_id'] ) . '-output" /><output id="' . esc_attr( $args['html_id'] ) . '-output" class="' . esc_attr( $this->slug ) . '-range">' . ( (int) $args['value'] ) . '</output>';
848 break;
849
850 case 'number':
851 $html .= ( ! empty( $args['prepend'] ) ? wp_kses_post( $args['prepend'] ) : '' );
852 $html .= '<input id="' . esc_attr( $args['html_id'] ) . '" type="text" value="' . esc_attr( $args['value'] ) . '" name="' . esc_attr( $args['name'] ) . '" />';
853 $html .= ( ! empty( $args['append'] ) ? wp_kses_post( $args['append'] ) : '' );
854 break;
855
856 case 'color':
857 $color_value = esc_attr( $args['value'] );
858 $color_name = esc_attr( $args['name'] );
859 $input_id = esc_attr( $args['html_id'] );
860 $input_class = $this->prefix . '-color-input';
861
862 if ( ! empty( $args['subclass'] ) ) {
863 $input_class .= ' ' . esc_attr( $args['subclass'] );
864 }
865
866 $swatch_style = ' style="background-color: ' . $color_value . ';"';
867
868 $html .= '<div class="' . $this->prefix . '-color-control">';
869 // Text input for the hex color value.
870 $html .= '<input id="' . $input_id . '" type="text" name="' . $color_name . '" value="' . $color_value . '" class="' . $input_class . '" />';
871 // Swatch button to toggle the picker.
872 $html .= '<button type="button" class="' . $this->prefix . '-color-swatch"' . $swatch_style . ' aria-label="' . esc_attr__( 'Open color picker', $this->domain ) . '" aria-expanded="false"></button>';
873 // Vanilla-colorful picker (hidden by default).
874 $html .= '<div class="' . $this->prefix . '-color-popover" aria-hidden="true"><hex-color-picker class="' . $this->prefix . '-hex-color-picker" color="' . $color_value . '"></hex-color-picker></div>';
875 $html .= '</div>';
876 break;
877
878 case 'custom':
879 $html .= call_user_func( $args['callback'], $args );
880 break;
881
882 case 'textarea':
883 $empty_disabled = empty( $args['disabled'] );
884 $rows = max( 2, (int) $args['rows'] );
885 $cols = max( 20, (int) $args['cols'] );
886
887 $html .= '<textarea id="' . esc_attr( $args['html_id'] ) . '"' . ( ! empty( $args['subclass'] ) ? ' class="' . esc_attr( $args['subclass'] ) . '"' : '' ) . ' name="' . esc_attr( $args['name'] ) . '" rows="' . esc_attr( $rows ) . '" cols="' . esc_attr( $cols ) . '" ' . disabled( $empty_disabled, false, false ) . '>' . esc_textarea( $args['value'] ) . '</textarea>';
888 break;
889
890 case 'editor':
891 $rows = max( 2, (int) $args['rows'] );
892 $editor_settings = ! empty( $args['editor_settings'] ) && is_array( $args['editor_settings'] ) ? $args['editor_settings'] : [];
893 $editor_settings = array_merge(
894 [
895 'textarea_name' => $args['name'],
896 'textarea_rows' => $rows,
897 'teeny' => true,
898 'media_buttons' => false,
899 'tinymce' => true,
900 'quicktags' => true
901 ],
902 $editor_settings
903 );
904
905 $html .= ! empty( $args['prepend'] ) ? wp_kses_post( $args['prepend'] ) : '';
906
907 ob_start();
908 wp_editor( (string) $args['value'], $args['html_id'], $editor_settings );
909 $html .= ob_get_clean();
910
911 $html .= ! empty( $args['append'] ) ? wp_kses_post( $args['append'] ) : '';
912 break;
913
914 case 'info':
915 $html .= '<span' . ( ! empty( $args['subclass'] ) ? ' class="' . esc_attr( $args['subclass'] ) . '"' : '' ) . '>' . esc_html( $args['text'] ) . '</span>';
916 break;
917
918 case 'class':
919 case 'input':
920 default:
921 $empty_disabled = empty( $args['disabled'] );
922
923 $html .= ( ! empty( $args['prepend'] ) ? wp_kses_post( $args['prepend'] ) : '' );
924 $html .= '<input id="' . esc_attr( $args['html_id'] ) . '"' . ( ! empty( $args['subclass'] ) ? ' class="' . esc_attr( $args['subclass'] ) . '"' : '' ) . ' type="text" value="' . esc_attr( $args['value'] ) . '" name="' . esc_attr( $args['name'] ) . '" ' . disabled( $empty_disabled, false, false ) . '/>';
925 $html .= ( ! empty( $args['append'] ) ? wp_kses_post( $args['append'] ) : '' );
926
927 if ( ! $empty_disabled )
928 $html .= '<input' . ( $empty_disabled ? '' : ' class="hidden"' ) . ' type="text" value="' . esc_attr( $args['value'] ) . '" name="' . esc_attr( $args['name'] ) . '">';
929 }
930
931 if ( ! empty ( $args['after_field'] ) )
932 $html .= $args['after_field'];
933
934 if ( ! empty ( $args['description'] ) )
935 $html .= '<p class="description">' . $args['description'] . '</p>';
936
937 $html .= '</div>';
938
939 if ( ! empty( $args['return'] ) )
940 return $html;
941 else
942 echo $html;
943 }
944
945 /**
946 * Validate settings field.
947 *
948 * @param mixed $value
949 * @param string $type
950 * @param array $args
951 * @return mixed
952 */
953 public function validate_field( $value = null, $type = '', $args = [] ) {
954 if ( is_null( $value ) )
955 return null;
956
957 switch ( $type ) {
958 case 'boolean':
959 // possible value: 'true' or 'false'
960 $value = ( $value === 'true' || $value === true );
961 break;
962
963 case 'radio':
964 $value = is_array( $value ) ? $args['default'] : sanitize_key( $value );
965
966 // disallow disabled radios
967 if ( ! empty( $args['disabled'] ) && in_array( $value, $args['disabled'], true ) )
968 $value = $args['default'];
969 break;
970
971 case 'checkbox':
972 // possible value: 'empty' or array
973 if ( $value === 'empty' )
974 $value = [];
975 else {
976 if ( is_array( $value ) && ! empty( $value ) ) {
977 $value = array_map( 'sanitize_key', $value );
978 $values = [];
979
980 foreach ( $value as $single_value ) {
981 if ( array_key_exists( $single_value, $args['options'] ) )
982 $values[] = $single_value;
983 }
984
985 $value = $values;
986 } else
987 $value = [];
988 }
989 break;
990
991 case 'number':
992 $value = (int) $value;
993
994 // is value lower than?
995 if ( isset( $args['min'] ) && $value < $args['min'] )
996 $value = $args['min'];
997
998 // is value greater than?
999 if ( isset( $args['max'] ) && $value > $args['max'] )
1000 $value = $args['max'];
1001 break;
1002
1003 case 'color':
1004 $value = sanitize_text_field( $value );
1005 if ( ! preg_match( '/^#[a-f0-9]{3,6}$/i', $value ) ) {
1006 $value = $args['default'] ?? '#000000';
1007 }
1008 break;
1009
1010 case 'info':
1011 $value = '';
1012 break;
1013
1014 case 'custom':
1015 // do nothing
1016 break;
1017
1018 case 'textarea':
1019 $value = is_array( $value ) ? implode( "\n", array_map( 'sanitize_textarea_field', $value ) ) : sanitize_textarea_field( $value );
1020 break;
1021
1022 case 'editor':
1023 $value = is_array( $value ) ? '' : wp_kses_post( $value );
1024 break;
1025
1026 case 'class':
1027 $value = trim( $value );
1028
1029 // more than 1 class?
1030 if ( strpos( $value, ' ' ) !== false ) {
1031 // get unique valid HTML classes
1032 $value = array_unique( array_filter( array_map( 'sanitize_html_class', explode( ' ', $value ) ) ) );
1033
1034 if ( ! empty( $value ) )
1035 $value = implode( ' ', $value );
1036 else
1037 $value = '';
1038 // single class
1039 } else
1040 $value = sanitize_html_class( $value, $args['default'] );
1041 break;
1042
1043 case 'input':
1044 case 'select':
1045 default:
1046 $value = is_array( $value ) ? array_map( 'sanitize_text_field', $value ) : sanitize_text_field( $value );
1047 break;
1048 }
1049
1050 return stripslashes_deep( $value );
1051 }
1052
1053 /**
1054 * Validate settings.
1055 *
1056 * @param array $input
1057 * @return array
1058 */
1059 public function validate_settings( $input ) {
1060 // check capability
1061 $capability = apply_filters( 'pvc_settings_capability', 'manage_options' );
1062
1063 if ( ! current_user_can( $capability ) )
1064 return $input;
1065
1066 // check option page
1067 if ( empty( $_POST['option_page'] ) )
1068 return $input;
1069
1070 // try to get setting name and ID
1071 foreach ( $this->settings as $id => $setting ) {
1072 // tabs?
1073 if ( is_array( $setting['option_name'] ) ) {
1074 foreach ( $setting['option_name'] as $tab => $option_name ) {
1075 // found valid setting?
1076 if ( $option_name === $_POST['option_page'] ) {
1077 // assign setting ID
1078 $setting_id = $tab;
1079
1080 // assign setting name
1081 $setting_name = $option_name;
1082
1083 // assign setting key
1084 $setting_key = $id;
1085
1086 // already found setting, no need to check the rest
1087 break 2;
1088 }
1089 }
1090 } else {
1091 // found valid setting?
1092 if ( $setting['option_name'] === $_POST['option_page'] ) {
1093 // assign setting ID and key
1094 $setting_key = $setting_id = $id;
1095
1096 // assign setting name
1097 $setting_name = $setting['option_name'];
1098
1099 // already found setting, no need to check the rest
1100 break;
1101 }
1102 }
1103 }
1104
1105 // check setting id, no need to check $setting_name since it was at the same stage
1106 if ( empty( $setting_id ) )
1107 return $input;
1108
1109 $is_update_request = isset( $_POST['action'] ) && sanitize_key( wp_unslash( $_POST['action'] ) ) === 'update';
1110 $has_custom_submit_action = isset( $_POST['post_views_counter_import_views'] )
1111 || isset( $_POST['post_views_counter_analyse_views'] )
1112 || isset( $_POST['post_views_counter_reset_views'] );
1113
1114 // save settings
1115 if ( isset( $_POST['save_' . $setting_name] ) || ( $is_update_request && ! $has_custom_submit_action && ! isset( $_POST['reset_' . $setting_name] ) ) ) {
1116 $input = $this->validate_input_settings( $setting_id, $setting_key, $input );
1117
1118 add_settings_error( $setting_name, 'settings_saved', __( 'Settings saved.', $this->domain ), 'updated' );
1119 // reset settings
1120 } elseif ( isset( $_POST['reset_' . $setting_name] ) ) {
1121 // get default values
1122 $input = $this->get_setting_defaults( $setting_id );
1123
1124 // check custom reset functions
1125 if ( ! empty( $this->settings[$setting_key]['fields'] ) ) {
1126 foreach ( $this->settings[$setting_key]['fields'] as $field_id => $field ) {
1127 // skip invalid tab field if any
1128 if ( ! empty( $field['tab'] ) && $field['tab'] !== $setting_id )
1129 continue;
1130
1131 // custom reset function?
1132 if ( ! empty( $field['reset'] ) ) {
1133 // valid function? no need to check "else" since all default values are already set
1134 if ( $this->callback_function_exists( $field['reset'] ) ) {
1135 if ( $field['type'] === 'custom' )
1136 $input = call_user_func( $field['reset'], $input, $field );
1137 else
1138 $input[$field_id] = call_user_func( $field['reset'], $input[$field_id], $field );
1139 }
1140 }
1141 }
1142 }
1143
1144 add_settings_error( $setting_name, 'settings_restored', __( 'Settings restored to defaults.', $this->domain ), 'updated' );
1145 }
1146
1147 do_action( $this->prefix . '_configuration_updated', 'settings', $input );
1148
1149 return $input;
1150 }
1151
1152 /**
1153 * Validate input settings.
1154 *
1155 * @param string $setting_id
1156 * @param array $input
1157 * @return array
1158 */
1159 public function validate_input_settings( $setting_id, $setting_key, $input ) {
1160 $setting_defaults = $this->get_setting_defaults( $setting_id );
1161 $current_settings = $this->get_current_setting_values( $setting_id, $setting_key );
1162
1163 if ( ! empty( $this->settings[$setting_key]['fields'] ) ) {
1164 foreach ( $this->settings[$setting_key]['fields'] as $field_id => $field ) {
1165 // skip saving this field?
1166 if ( ! empty( $field['skip_saving'] ) ) {
1167 if ( array_key_exists( $field_id, $current_settings ) )
1168 $input[$field_id] = $current_settings[$field_id];
1169 else
1170 unset( $input[$field_id] );
1171
1172 continue;
1173 }
1174
1175 // skip invalid tab field if any
1176 if ( ! empty( $field['tab'] ) && $field['tab'] !== $setting_id )
1177 continue;
1178
1179 // custom validate function?
1180 if ( ! empty( $field['validate'] ) ) {
1181 // valid function?
1182 if ( $this->callback_function_exists( $field['validate'] ) ) {
1183 if ( $field['type'] === 'custom' )
1184 $input = call_user_func( $field['validate'], $input, $field );
1185 else
1186 $input[$field_id] = isset( $input[$field_id] ) ? call_user_func( $field['validate'], $input[$field_id], $field ) : $setting_defaults[$field_id];
1187 } else
1188 $input[$field_id] = $setting_defaults[$field_id];
1189 } else {
1190 // field data?
1191 if ( isset( $input[$field_id] ) ) {
1192 // make sure default value is available
1193 if ( ! isset( $field['default'] ) )
1194 $field['default'] = $setting_defaults[$field_id];
1195
1196 $input[$field_id] = $this->validate_field( $input[$field_id], $field['type'], $field );
1197 } else
1198 $input[$field_id] = $setting_defaults[$field_id];
1199 }
1200
1201 // update input data
1202 $this->input_settings = $input;
1203
1204 // add this field as validated
1205 $this->validated_settings[] = $field_id;
1206 }
1207 }
1208
1209 return $input;
1210 }
1211
1212 /**
1213 * Get the currently stored values for a settings group.
1214 *
1215 * @param string $setting_id
1216 * @param string $setting_key
1217 * @return array
1218 */
1219 private function get_current_setting_values( $setting_id, $setting_key ) {
1220 if ( empty( $this->settings[$setting_key]['option_name'] ) )
1221 return [];
1222
1223 $option_name = $this->settings[$setting_key]['option_name'];
1224
1225 if ( is_array( $option_name ) )
1226 $option_name = isset( $option_name[$setting_id] ) ? $option_name[$setting_id] : '';
1227
1228 if ( ! is_string( $option_name ) || $option_name === '' )
1229 return [];
1230
1231 $current_values = get_option( $option_name, [] );
1232
1233 return is_array( $current_values ) ? $current_values : [];
1234 }
1235
1236 /**
1237 * Check whether callback is a valid function.
1238 *
1239 * @param string|array $callback
1240 * @return bool
1241 */
1242 public function callback_function_exists( $callback ) {
1243 // function as array?
1244 if ( is_array( $callback ) ) {
1245 list( $object, $function ) = $callback;
1246
1247 // check function existence
1248 $function_exists = method_exists( $object, $function );
1249 // function as string?
1250 } elseif ( is_string( $callback ) ) {
1251 // check function existence
1252 $function_exists = function_exists( $callback );
1253 } else
1254 $function_exists = false;
1255
1256 return $function_exists;
1257 }
1258
1259 /**
1260 * Get value based on minimum and maximum.
1261 *
1262 * @param array $data
1263 * @param string $setting_name
1264 * @param int $default
1265 * @param int $min
1266 * @param int $max
1267 * @return void
1268 */
1269 public function get_int_value( $data, $setting_name, $default, $min, $max ) {
1270 // check existence of value
1271 $value = array_key_exists( $setting_name, $data ) ? (int) $data[$setting_name] : $default;
1272
1273 if ( $value > $max || $value < $min )
1274 $value = $default;
1275
1276 return $value;
1277 }
1278 }
1279