PluginProbe ʕ •ᴥ•ʔ
Post Views Counter / 1.4.7
Post Views Counter v1.4.7
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 2 years ago class-columns.php 2 years ago class-counter.php 2 years ago class-crawler-detect.php 2 years ago class-cron.php 2 years ago class-dashboard.php 2 years ago class-frontend.php 2 years ago class-functions.php 2 years ago class-query.php 2 years ago class-settings-api.php 2 years ago class-settings.php 2 years ago class-update.php 2 years ago class-widgets.php 2 years ago functions.php 2 years ago
class-settings-api.php
823 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 $short = '';
22 private $plugin = '';
23 private $plugin_url = '';
24 private $object;
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
36 // empty slug?
37 if ( empty( $args['slug'] ) )
38 $this->slug = $args['domain'];
39 else
40 $this->slug = $args['slug'];
41
42 // empty short name?
43 if ( empty( $args['short'] ) ) {
44 $short = '';
45
46 // prepare short name based on prefix
47 $parts = explode( '_', $this->prefix );
48
49 foreach ( $parts as $string ) {
50 $short .= substr( $string, 0, 1 );
51 }
52
53 // set short name
54 $this->short = $short;
55 } else
56 $this->short = $args['short'];
57
58 $this->object = $args['object'];
59 $this->plugin = $args['plugin'];
60 $this->plugin_url = $args['plugin_url'];
61
62 // actions
63 add_action( 'admin_menu', [ $this, 'admin_menu_options' ], 11 );
64 add_action( 'admin_init', [ $this, 'register_settings' ], 11 );
65 add_action( 'admin_enqueue_scripts', [ $this, 'admin_enqueue_scripts' ] );
66 }
67
68 /**
69 * Get prefix.
70 *
71 * @return string
72 */
73 public function get_prefix() {
74 return $this->prefix;
75 }
76
77 /**
78 * Get pages.
79 *
80 * @return array
81 */
82 public function get_pages() {
83 return $this->pages;
84 }
85
86 /**
87 * Get settings.
88 *
89 * @return array
90 */
91 public function get_settings() {
92 return $this->settings;
93 }
94
95 /**
96 * Get current input settings during saving.
97 *
98 * @return array
99 */
100 public function get_input_settings() {
101 return $this->input_settings;
102 }
103
104 /**
105 * Get already validated setting fields during saving.
106 *
107 * @return array
108 */
109 public function get_validated_settings() {
110 return $this->validated_settings;
111 }
112
113 /**
114 * Load default scripts and styles.
115 *
116 * @return void
117 */
118 public function admin_enqueue_scripts() {
119 $handler = $this->short . '-settings-api-style';
120
121 // register and enqueue styles
122 wp_register_style( $handler, false );
123 wp_enqueue_style( $handler );
124
125 // add styles
126 wp_add_inline_style( $handler, '.nav-tab-wrapper span.nav-span-disabled {
127 cursor: not-allowed;
128 float: left;
129 }
130 body.rtl .nav-tab-wrapper span.nav-span-disabled {
131 float: right;
132 }
133 .nav-tab-wrapper a.nav-tab.nav-tab-disabled {
134 pointer-events: none;
135 }
136 .nav-tab-wrapper a.nav-tab.nav-tab-disabled:hover {
137 cursor: not-allowed;
138 }' );
139 }
140
141 /**
142 * Add menu pages.
143 *
144 * @return void
145 */
146 public function admin_menu_options() {
147 $this->pages = apply_filters( $this->prefix . '_settings_pages', [] );
148 $types = [
149 'page' => [],
150 'subpage' => [],
151 'settings_page' => []
152 ];
153
154 foreach ( $this->pages as $page => $data ) {
155 // skip invalid page types
156 if ( empty( $data['type'] ) || ! array_key_exists( $data['type'], $types ) )
157 continue;
158
159 if ( $data['type'] === 'page' ) {
160 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'] );
161
162 // add page type
163 $types['page'][$data['menu_slug']] = $page;
164 // menu subpage?
165 } elseif ( $data['type'] === 'subpage' ) {
166 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' ] );
167
168 // add subpage type
169 $types['subpage'][$data['menu_slug']] = $page;
170 // menu settings page?
171 } elseif ( $data['type'] === 'settings_page' ) {
172 add_options_page( $data['page_title'], $data['menu_title'], $data['capability'], $data['menu_slug'], ! empty( $data['callback'] ) ? $data['callback'] : [ $this, 'options_page' ] );
173
174 // add settings type
175 $types['settings_page'][$data['menu_slug']] = $page;
176 }
177 }
178
179 // set page types
180 $this->page_types = $types;
181 }
182
183 /**
184 * Render settings.
185 *
186 * @global string $pagenow
187 *
188 * @return void
189 */
190 public function options_page() {
191 global $pagenow;
192
193 $valid_page = false;
194
195 // get current screen
196 $screen = get_current_screen();
197
198 // display top level settings page?
199 if ( $pagenow === 'admin.php' && preg_match( '/^toplevel_page_(' . implode( '|', $this->page_types['page'] ) . ')$/', $screen->base, $matches ) === 1 && ! empty( $matches[1] ) ) {
200 $valid_page = true;
201 $page_type = 'page';
202 $url_page = 'admin.php';
203 }
204
205 // display sub level settings page?
206 if ( ! $valid_page && $pagenow === 'admin.php' && preg_match( '/^(?:toplevel|' . $this->prefix . ')_page_' . $this->prefix . '-(' . implode( '|', $this->page_types['subpage'] ) . ')-settings$/', $screen->base, $matches ) === 1 && ! empty( $matches[1] ) ) {
207 $valid_page = true;
208 $page_type = 'subpage';
209 $url_page = 'admin.php';
210 }
211
212 // display settings page?
213 if ( ! $valid_page && $pagenow === 'options-general.php' && preg_match( '/^(?:settings_page_)(' . implode( '|', array_keys( $this->page_types['settings_page'] ) ) . ')$/', $screen->base, $matches ) === 1 ) {
214 $valid_page = true;
215 $page_type = 'settings_page';
216 $url_page = 'options-general.php';
217 }
218
219 // skip invalid pages
220 if ( ! $valid_page )
221 return;
222
223 echo '
224 <div class="wrap">
225 <h2>' . esc_html( $this->settings[$matches[1]]['label'] ) . '</h2>';
226
227 $tab_key = '';
228
229 // any tabs?
230 if ( array_key_exists( 'tabs', $this->pages[$this->page_types[$page_type][$matches[1]]] ) ) {
231 // get tabs
232 $tabs = $this->pages[$this->page_types[$page_type][$matches[1]]]['tabs'];
233
234 // reset tabs
235 reset( $tabs );
236
237 // get first default tab
238 $first_tab = key( $tabs );
239
240 // get current tab
241 $tab_key = ! empty( $_GET['tab'] ) && array_key_exists( $_GET['tab'], $tabs ) ? $_GET['tab'] : $first_tab;
242
243 // check current tab
244 if ( ! empty( $_GET['tab'] ) )
245 $tab_key = sanitize_key( $_GET['tab'] );
246
247 // invalid tab?
248 if ( ! array_key_exists( $tab_key, $tabs ) )
249 $tab_key = $first_tab;
250
251 echo '
252 <h2 class="nav-tab-wrapper">';
253
254 foreach ( $tabs as $key => $tab ) {
255 if ( ! empty( $tab['disabled'] ) )
256 $url = '';
257 else
258 $url = admin_url( $url_page . '?page=' . $matches[1] . '&tab=' . $key );
259
260 if ( ! empty( $tab['disabled'] ) )
261 echo '<span class="nav-span-disabled">';
262
263 echo '
264 <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>';
265
266 if ( ! empty( $tab['disabled'] ) )
267 echo '</span>';
268 }
269
270 echo '
271 </h2>';
272 }
273
274 // skip for internal options page
275 if ( $page_type !== 'settings_page' )
276 settings_errors();
277
278 // get settings page classes
279 $settings_class = apply_filters( $this->prefix . '_settings_page_class', [ $this->slug . '-settings', $tab_key . '-settings' ] );
280
281 // sanitize settings page classes
282 $settings_class = array_unique( array_filter( array_map( 'sanitize_html_class', $settings_class ) ) );
283
284 echo '
285 <div class="' . implode( ' ', array_map( 'esc_attr', $settings_class ) ) . '">';
286
287 $display_form = true;
288
289 // check form attribute
290 if ( ! empty( $this->settings[$matches[1]]['form'] ) && ! empty( $tab_key ) && ! empty( $this->settings[$matches[1]]['form'][$tab_key] ) ) {
291 $form = $this->settings[$matches[1]]['form'][$tab_key];
292
293 if ( isset( $form['buttons'] ) && ! $form['buttons'] )
294 $display_form = false;
295 }
296
297 // any tabs?
298 if ( ! empty( $tab_key ) ) {
299 if ( ! empty( $tabs[$tab_key]['option_name'] ) )
300 $setting = $tabs[$tab_key]['option_name'];
301 else
302 $setting = $this->prefix . '_' . $tab_key . '_settings';
303 } else
304 $setting = $this->prefix . '_' . $matches[1] . '_settings';
305
306 do_action( $this->short . '_settings_sidebar', $setting, $page_type, $url_page, $tab_key );
307
308 if ( $display_form ) {
309 echo '
310 <form action="options.php" method="post">';
311 }
312
313 settings_fields( $setting );
314
315 if ( $display_form )
316 do_action( $this->short . '_settings_form', $setting, $page_type, $url_page, $tab_key );
317
318 do_settings_sections( $setting );
319
320 if ( $display_form ) {
321 echo '
322 <p class="submit">';
323
324 submit_button( '', 'primary', 'save_' . $setting, false );
325
326 echo ' ';
327
328 submit_button( __( 'Reset to defaults', $this->domain ), 'secondary reset_' . $setting . ' reset_' . $this->short . '_settings', 'reset_' . $setting, false );
329
330 echo '
331 </p>
332 </form>';
333 }
334
335 echo '
336 </div>
337 <div class="clear"></div>
338 </div>';
339 }
340
341 /**
342 * Register settings.
343 *
344 * @return void
345 */
346 public function register_settings() {
347 $this->settings = apply_filters( $this->prefix . '_settings_data', [] );
348
349 // check settings
350 foreach ( $this->settings as $setting_id => $setting ) {
351 // tabs?
352 if ( is_array( $setting['option_name'] ) ) {
353 foreach ( $setting['option_name'] as $tab => $option_name ) {
354 $this->register_setting_fields( $tab, $setting, $option_name );
355 }
356 } else
357 $this->register_setting_fields( $setting_id, $setting );
358 }
359 }
360
361 /**
362 * Register setting with sections and fields.
363 *
364 * @return void
365 */
366 public function register_setting_fields( $setting_id, $setting, $option_name = '' ) {
367 if ( empty( $option_name ) )
368 $option_name = $setting['option_name'];
369
370 // register setting
371 register_setting( $option_name, $option_name, ! empty( $setting['validate'] ) ? $setting['validate'] : [ $this, 'validate_settings' ] );
372
373 // register setting sections
374 if ( ! empty( $setting['sections'] ) ) {
375 foreach ( $setting['sections'] as $section_id => $section ) {
376 // skip unwanted sections
377 if ( ! empty( $section['tab'] ) && $section['tab'] !== $setting_id )
378 continue;
379
380 add_settings_section(
381 $section_id,
382 ! empty( $section['title'] ) ? esc_html( $section['title'] ) : '',
383 ! empty( $section['callback'] ) ? $section['callback'] : null,
384 ! empty( $section['page'] ) ? $section['page'] : $option_name
385 );
386 }
387 }
388
389 // register setting fields
390 if ( ! empty( $setting['fields'] ) ) {
391 foreach ( $setting['fields'] as $field_key => $field ) {
392 // skip unwanted fields
393 if ( ! empty( $field['tab'] ) && $field['tab'] !== $setting_id )
394 continue;
395
396 // set field ID
397 $field_id = implode( '_', [ $this->prefix, $setting_id, $field_key ] );
398
399 // skip rendering this field?
400 if ( ! empty( $field['skip_rendering'] ) )
401 continue;
402
403 add_settings_field(
404 $field_id,
405 ! empty( $field['title'] ) ? esc_html( $field['title'] ) : '',
406 [ $this, 'render_field' ],
407 $option_name,
408 ! empty( $field['section'] ) ? esc_attr( $field['section'] ) : '',
409 array_merge( $this->prepare_field_args( $field, $field_id, $field_key, $setting_id, $option_name ), $field )
410 );
411 }
412 }
413 }
414
415 /**
416 * Prepare field arguments.
417 *
418 * @param array $args
419 * @return array
420 */
421 public function prepare_field_args( $field, $field_id, $field_key, $setting_id, $setting_name ) {
422 // get field type
423 $field_type = ! empty( $field['type'] ) ? $field['type'] : '';
424
425 return [
426 'id' => $field_id,
427 'name' => $setting_name . '[' . $field_key . ']',
428 'class' => ! empty( $field['class'] ) ? $field['class'] : '',
429 'type' => $field_type,
430 'label' => ! empty( $field['label'] ) ? $field['label'] : '',
431 'description' => ! empty( $field['description'] ) ? $field['description'] : '',
432 'text' => ! empty( $field['text'] ) ? $field['text'] : '',
433 'min' => ! empty( $field['min'] ) ? (int) $field['min'] : 0,
434 'max' => ! empty( $field['max'] ) ? (int) $field['max'] : 0,
435 'options' => ! empty( $field['options'] ) ? $field['options'] : [],
436 'callback' => ! empty( $field['callback'] ) ? $field['callback'] : null,
437 'validate' => ! empty( $field['validate'] ) ? $field['validate'] : null,
438 'callback_args' => ! empty( $field['callback_args'] ) ? $field['callback_args'] : [],
439 'default' => $field_type !== 'custom' ? $this->object->defaults[$setting_id][$field_key] : null,
440 'value' => $field_type !== 'custom' ? $this->object->options[$setting_id][$field_key] : null
441 /*
442 after_field
443 before_field
444 */
445 ];
446 }
447
448 /**
449 * Render settings field.
450 *
451 * @param array $args
452 * @return void|string
453 */
454 public function render_field( $args ) {
455 if ( empty( $args ) || ! is_array( $args ) )
456 return;
457
458 $html = '<div id="' . esc_attr( $args['id'] ) . '_setting"' . ( ! empty( $args['class'] ) ? ' class="' . esc_attr( $args['class'] ) . '"' : '' ) . '>';
459
460 if ( ! empty ( $args['before_field'] ) )
461 $html .= $args['before_field'];
462
463 switch ( $args['type'] ) {
464 case 'boolean':
465 if ( empty( $args['disabled'] ) )
466 $html .= '<input type="hidden" name="' . esc_attr( $args['name'] ) . '" value="false" />';
467
468 $html .= '<label><input id="' . esc_attr( $args['id'] ) . '" type="checkbox" name="' . esc_attr( $args['name'] ) . '" value="true" ' . checked( (bool) $args['value'], true, false ) . ' ' . disabled( empty( $args['disabled'] ), false, false ) . ' />' . esc_html( $args['label'] ) . '</label>';
469 break;
470
471 case 'radio':
472 foreach ( $args['options'] as $key => $name ) {
473 $html .= '<label for="' . esc_attr( $args['id'] . '_' . $key ) . '"><input id="' . esc_attr( $args['id'] . '_' . $key ) . '" type="radio" name="' . esc_attr( $args['name'] ) . '" value="' . esc_attr( $key ) . '" ' . checked( $key, $args['value'], false ) . ' ' . disabled( ! empty( $args['disabled'] ) && in_array ( $key, $args['disabled'], true ), true, false ) . ' />' . esc_html( $name ) . '</label> ';
474 }
475 break;
476
477 case 'checkbox':
478 // possible "empty" value
479 if ( $args['value'] === 'empty' )
480 $args['value'] = [];
481
482 $display_type = ! empty( $args['display_type'] ) && in_array( $args['display_type'], [ 'horizontal', 'vertical' ], true ) ? $args['display_type'] : 'horizontal';
483
484 $html .= '<input type="hidden" name="' . esc_attr( $args['name'] ) . '" value="empty" />';
485
486 foreach ( $args['options'] as $key => $name ) {
487 $html .= '<label><input id="' . esc_attr( $args['id'] . '_' . $key ) . '" type="checkbox" name="' . esc_attr( $args['name'] ) . '[]" value="' . esc_attr( $key ) . '" ' . checked( in_array( $key, $args['value'] ), true, false ) . ' ' . disabled( ! empty( $args['disabled'] ) && in_array ( $key, $args['disabled'], true ), true, false ) . ' />' . esc_html( $name ) . '</label>' . ( $display_type === 'horizontal' ? ' ' : '<br />' );
488 }
489 break;
490
491 case 'select':
492 $html .= '<select id="' . esc_attr( $args['id'] ) . '" name="' . esc_attr( $args['name'] ) . '" ' . disabled( empty( $args['disabled'] ), false, false ) . '/>';
493
494 foreach ( $args['options'] as $key => $name ) {
495 $html .= '<option value="' . esc_attr( $key ) . '" ' . selected( $args['value'], $key, false ) . '>' . esc_html( $name ) . '</option>';
496 }
497
498 $html .= '</select>';
499 break;
500
501 case 'range':
502 $html .= '<input id="' . esc_attr( $args['id'] . '_slider' ) . '" type="range" name="' . esc_attr( $args['name'] ) . '" value="' . esc_attr( $args['value'] ) . '" min="' . esc_attr( $args['min'] ) . '" max="' . esc_attr( $args['max'] ) . '" oninput="this.form.' . esc_attr( $args['id'] ) . '_range.value = this.value" /><output class="' . esc_attr( $this->slug ) . '-range" name="' . esc_attr( $args['id'] ) . '_range">' . ( (int) $args['value'] ) . '</output>';
503 break;
504
505 case 'number':
506 $html .= ( ! empty( $args['prepend'] ) ? wp_kses_post( $args['prepend'] ) : '' );
507 $html .= '<input id="' . $args['id'] . '" type="text" value="' . esc_attr( $args['value'] ) . '" name="' . esc_attr( $args['name'] ) . '" />';
508 $html .= ( ! empty( $args['append'] ) ? wp_kses_post( $args['append'] ) : '' );
509 break;
510
511 case 'custom':
512 $html .= call_user_func( $args['callback'], $args );
513 break;
514
515 case 'info':
516 $html .= '<span' . ( ! empty( $args['subclass'] ) ? ' class="' . esc_attr( $args['subclass'] ) . '"' : '' ) . '>' . esc_html( $args['text'] ) . '</span>';
517 break;
518
519 case 'class':
520 case 'input':
521 default:
522 $empty_disabled = empty( $args['disabled'] );
523
524 $html .= ( ! empty( $args['prepend'] ) ? wp_kses_post( $args['prepend'] ) : '' );
525 $html .= '<input id="' . $args['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 ) . '/>';
526 $html .= ( ! empty( $args['append'] ) ? wp_kses_post( $args['append'] ) : '' );
527
528 if ( ! $empty_disabled )
529 $html .= '<input' . ( $empty_disabled ? '' : ' class="hidden"' ) . ' type="text" value="' . esc_attr( $args['value'] ) . '" name="' . esc_attr( $args['name'] ) . '">';
530 }
531
532 if ( ! empty ( $args['after_field'] ) )
533 $html .= $args['after_field'];
534
535 if ( ! empty ( $args['description'] ) )
536 $html .= '<p class="description">' . $args['description'] . '</p>';
537
538 $html .= '</div>';
539
540 if ( ! empty( $args['return'] ) )
541 return $html;
542 else
543 echo $html;
544 }
545
546 /**
547 * Validate settings field.
548 *
549 * @param mixed $value
550 * @param string $type
551 * @param array $args
552 * @return mixed
553 */
554 public function validate_field( $value = null, $type = '', $args = [] ) {
555 if ( is_null( $value ) )
556 return null;
557
558 switch ( $type ) {
559 case 'boolean':
560 // possible value: 'true' or 'false'
561 $value = ( $value === 'true' || $value === true );
562 break;
563
564 case 'radio':
565 $value = is_array( $value ) ? $args['default'] : sanitize_key( $value );
566
567 // disallow disabled radios
568 if ( ! empty( $args['disabled'] ) && in_array( $value, $args['disabled'], true ) )
569 $value = $args['default'];
570 break;
571
572 case 'checkbox':
573 // possible value: 'empty' or array
574 if ( $value === 'empty' )
575 $value = [];
576 else {
577 if ( is_array( $value ) && ! empty( $value ) ) {
578 $value = array_map( 'sanitize_key', $value );
579 $values = [];
580
581 foreach ( $value as $single_value ) {
582 if ( array_key_exists( $single_value, $args['options'] ) )
583 $values[] = $single_value;
584 }
585
586 $value = $values;
587 } else
588 $value = [];
589 }
590 break;
591
592 case 'number':
593 $value = (int) $value;
594
595 // is value lower than?
596 if ( isset( $args['min'] ) && $value < $args['min'] )
597 $value = $args['min'];
598
599 // is value greater than?
600 if ( isset( $args['max'] ) && $value > $args['max'] )
601 $value = $args['max'];
602 break;
603
604 case 'info':
605 $value = '';
606 break;
607
608 case 'custom':
609 // do nothing
610 break;
611
612 case 'class':
613 $value = trim( $value );
614
615 // more than 1 class?
616 if ( strpos( $value, ' ' ) !== false ) {
617 // get unique valid HTML classes
618 $value = array_unique( array_filter( array_map( 'sanitize_html_class', explode( ' ', $value ) ) ) );
619
620 if ( ! empty( $value ) )
621 $value = implode( ' ', $value );
622 else
623 $value = '';
624 // single class
625 } else
626 $value = sanitize_html_class( $value, $args['default'] );
627 break;
628
629 case 'input':
630 case 'select':
631 default:
632 $value = is_array( $value ) ? array_map( 'sanitize_text_field', $value ) : sanitize_text_field( $value );
633 break;
634 }
635
636 return stripslashes_deep( $value );
637 }
638
639 /**
640 * Validate settings.
641 *
642 * @param array $input
643 * @return array
644 */
645 public function validate_settings( $input ) {
646 // check capability
647 if ( ! current_user_can( 'manage_options' ) )
648 return $input;
649
650 // check option page
651 if ( empty( $_POST['option_page'] ) )
652 return $input;
653
654 // try to get setting name and ID
655 foreach ( $this->settings as $id => $setting ) {
656 // tabs?
657 if ( is_array( $setting['option_name'] ) ) {
658 foreach ( $setting['option_name'] as $tab => $option_name ) {
659 // found valid setting?
660 if ( $option_name === $_POST['option_page'] ) {
661 // assign setting ID
662 $setting_id = $tab;
663
664 // assign setting name
665 $setting_name = $option_name;
666
667 // assign setting key
668 $setting_key = $id;
669
670 // already found setting, no need to check the rest
671 break 2;
672 }
673 }
674 } else {
675 // found valid setting?
676 if ( $setting['option_name'] === $_POST['option_page'] ) {
677 // assign setting ID and key
678 $setting_key = $setting_id = $id;
679
680 // assign setting name
681 $setting_name = $setting['option_name'];
682
683 // already found setting, no need to check the rest
684 break;
685 }
686 }
687 }
688
689 // check setting id, no need to check $setting_name since it was at the same stage
690 if ( empty( $setting_id ) )
691 return $input;
692
693 // save settings
694 if ( isset( $_POST['save_' . $setting_name] ) ) {
695 $input = $this->validate_input_settings( $setting_id, $setting_key, $input );
696
697 add_settings_error( $setting_name, 'settings_saved', __( 'Settings saved.', $this->domain ), 'updated' );
698 // reset settings
699 } elseif ( isset( $_POST['reset_' . $setting_name] ) ) {
700 // get default values
701 $input = $this->object->defaults[$setting_id];
702
703 // check custom reset functions
704 if ( ! empty( $this->settings[$setting_key]['fields'] ) ) {
705 foreach ( $this->settings[$setting_key]['fields'] as $field_id => $field ) {
706 // skip invalid tab field if any
707 if ( ! empty( $field['tab'] ) && $field['tab'] !== $setting_id )
708 continue;
709
710 // custom reset function?
711 if ( ! empty( $field['reset'] ) ) {
712 // valid function? no need to check "else" since all default values are already set
713 if ( $this->callback_function_exists( $field['reset'] ) ) {
714 if ( $field['type'] === 'custom' )
715 $input = call_user_func( $field['reset'], $input, $field );
716 else
717 $input[$field_id] = call_user_func( $field['reset'], $input[$field_id], $field );
718 }
719 }
720 }
721 }
722
723 add_settings_error( $setting_name, 'settings_restored', __( 'Settings restored to defaults.', $this->domain ), 'updated' );
724 }
725
726 return $input;
727 }
728
729 /**
730 * Validate input settings.
731 *
732 * @param string $setting_id
733 * @param array $input
734 * @return array
735 */
736 public function validate_input_settings( $setting_id, $setting_key, $input ) {
737 if ( ! empty( $this->settings[$setting_key]['fields'] ) ) {
738 foreach ( $this->settings[$setting_key]['fields'] as $field_id => $field ) {
739 // skip saving this field?
740 if ( ! empty( $field['skip_saving'] ) )
741 continue;
742
743 // skip invalid tab field if any
744 if ( ! empty( $field['tab'] ) && $field['tab'] !== $setting_id )
745 continue;
746
747 // custom validate function?
748 if ( ! empty( $field['validate'] ) ) {
749 // valid function?
750 if ( $this->callback_function_exists( $field['validate'] ) ) {
751 if ( $field['type'] === 'custom' )
752 $input = call_user_func( $field['validate'], $input, $field );
753 else
754 $input[$field_id] = isset( $input[$field_id] ) ? call_user_func( $field['validate'], $input[$field_id], $field ) : $this->object->defaults[$setting_id][$field_id];
755 } else
756 $input[$field_id] = $this->object->defaults[$setting_id][$field_id];
757 } else {
758 // field data?
759 if ( isset( $input[$field_id] ) ) {
760 // make sure default value is available
761 if ( ! isset( $field['default'] ) )
762 $field['default'] = $this->object->defaults[$setting_id][$field_id];
763
764 $input[$field_id] = $this->validate_field( $input[$field_id], $field['type'], $field );
765 } else
766 $input[$field_id] = $this->object->defaults[$setting_id][$field_id];
767 }
768
769 // update input data
770 $this->input_settings = $input;
771
772 // add this field as validated
773 $this->validated_settings[] = $field_id;
774 }
775 }
776
777 return $input;
778 }
779
780 /**
781 * Check whether callback is a valid function.
782 *
783 * @param string|array $callback
784 * @return bool
785 */
786 public function callback_function_exists( $callback ) {
787 // function as array?
788 if ( is_array( $callback ) ) {
789 list( $object, $function ) = $callback;
790
791 // check function existence
792 $function_exists = method_exists( $object, $function );
793 // function as string?
794 } elseif ( is_string( $callback ) ) {
795 // check function existence
796 $function_exists = function_exists( $callback );
797 } else
798 $function_exists = false;
799
800 return $function_exists;
801 }
802
803 /**
804 * Get value based on minimum and maximum.
805 *
806 * @param array $data
807 * @param string $setting_name
808 * @param int $default
809 * @param int $min
810 * @param int $max
811 * @return void
812 */
813 public function get_int_value( $data, $setting_name, $default, $min, $max ) {
814 // check existence of value
815 $value = array_key_exists( $setting_name, $data ) ? (int) $data[$setting_name] : $default;
816
817 if ( $value > $max || $value < $min )
818 $value = $default;
819
820 return $value;
821 }
822 }
823