PluginProbe ʕ •ᴥ•ʔ
Post Views Counter / 1.4.2
Post Views Counter v1.4.2
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
815 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 echo '
244 <h2 class="nav-tab-wrapper">';
245
246 foreach ( $tabs as $key => $tab ) {
247 if ( ! empty( $tab['disabled'] ) )
248 $url = '';
249 else
250 $url = admin_url( $url_page . '?page=' . $matches[1] . '&tab=' . $key );
251
252 if ( ! empty( $tab['disabled'] ) )
253 echo '<span class="nav-span-disabled">';
254
255 echo '
256 <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>';
257
258 if ( ! empty( $tab['disabled'] ) )
259 echo '</span>';
260 }
261
262 echo '
263 </h2>';
264 }
265
266 // skip for internal options page
267 if ( $page_type !== 'settings_page' )
268 settings_errors();
269
270 // get settings page classes
271 $settings_class = apply_filters( $this->prefix . '_settings_page_class', [ $this->slug . '-settings', $tab_key . '-settings' ] );
272
273 // sanitize settings page classes
274 $settings_class = array_unique( array_filter( array_map( 'sanitize_html_class', $settings_class ) ) );
275
276 echo '
277 <div class="' . implode( ' ', array_map( 'esc_attr', $settings_class ) ) . '">';
278
279 $display_form = true;
280
281 // check form attribute
282 if ( ! empty( $this->settings[$matches[1]]['form'] ) && ! empty( $tab_key ) && ! empty( $this->settings[$matches[1]]['form'][$tab_key] ) ) {
283 $form = $this->settings[$matches[1]]['form'][$tab_key];
284
285 if ( isset( $form['buttons'] ) && ! $form['buttons'] )
286 $display_form = false;
287 }
288
289 // any tabs?
290 if ( ! empty( $tab_key ) ) {
291 if ( ! empty( $tabs[$tab_key]['option_name'] ) )
292 $setting = $tabs[$tab_key]['option_name'];
293 else
294 $setting = $this->prefix . '_' . $tab_key . '_settings';
295 } else
296 $setting = $this->prefix . '_' . $matches[1] . '_settings';
297
298 do_action( $this->short . '_settings_sidebar', $setting, $page_type, $url_page, $tab_key );
299
300 if ( $display_form ) {
301 echo '
302 <form action="options.php" method="post">';
303 }
304
305 settings_fields( $setting );
306
307 if ( $display_form )
308 do_action( $this->short . '_settings_form', $setting, $page_type, $url_page, $tab_key );
309
310 do_settings_sections( $setting );
311
312 if ( $display_form ) {
313 echo '
314 <p class="submit">';
315
316 submit_button( '', 'primary', 'save_' . $setting, false );
317
318 echo ' ';
319
320 submit_button( __( 'Reset to defaults', $this->domain ), 'secondary reset_' . $setting . ' reset_' . $this->short . '_settings', 'reset_' . $setting, false );
321
322 echo '
323 </p>
324 </form>';
325 }
326
327 echo '
328 </div>
329 <div class="clear"></div>
330 </div>';
331 }
332
333 /**
334 * Register settings.
335 *
336 * @return void
337 */
338 public function register_settings() {
339 $this->settings = apply_filters( $this->prefix . '_settings_data', [] );
340
341 // check settings
342 foreach ( $this->settings as $setting_id => $setting ) {
343 // tabs?
344 if ( is_array( $setting['option_name'] ) ) {
345 foreach ( $setting['option_name'] as $tab => $option_name ) {
346 $this->register_setting_fields( $tab, $setting, $option_name );
347 }
348 } else
349 $this->register_setting_fields( $setting_id, $setting );
350 }
351 }
352
353 /**
354 * Register setting with sections and fields.
355 *
356 * @return void
357 */
358 public function register_setting_fields( $setting_id, $setting, $option_name = '' ) {
359 if ( empty( $option_name ) )
360 $option_name = $setting['option_name'];
361
362 // register setting
363 register_setting( $option_name, $option_name, ! empty( $setting['validate'] ) ? $setting['validate'] : [ $this, 'validate_settings' ] );
364
365 // register setting sections
366 if ( ! empty( $setting['sections'] ) ) {
367 foreach ( $setting['sections'] as $section_id => $section ) {
368 // skip unwanted sections
369 if ( ! empty( $section['tab'] ) && $section['tab'] !== $setting_id )
370 continue;
371
372 add_settings_section(
373 $section_id,
374 ! empty( $section['title'] ) ? esc_html( $section['title'] ) : '',
375 ! empty( $section['callback'] ) ? $section['callback'] : null,
376 ! empty( $section['page'] ) ? $section['page'] : $option_name
377 );
378 }
379 }
380
381 // register setting fields
382 if ( ! empty( $setting['fields'] ) ) {
383 foreach ( $setting['fields'] as $field_key => $field ) {
384 // skip unwanted fields
385 if ( ! empty( $field['tab'] ) && $field['tab'] !== $setting_id )
386 continue;
387
388 // set field ID
389 $field_id = implode( '_', [ $this->prefix, $setting_id, $field_key ] );
390
391 // skip rendering this field?
392 if ( ! empty( $field['skip_rendering'] ) )
393 continue;
394
395 add_settings_field(
396 $field_id,
397 ! empty( $field['title'] ) ? esc_html( $field['title'] ) : '',
398 [ $this, 'render_field' ],
399 $option_name,
400 ! empty( $field['section'] ) ? esc_attr( $field['section'] ) : '',
401 array_merge( $this->prepare_field_args( $field, $field_id, $field_key, $setting_id, $option_name ), $field )
402 );
403 }
404 }
405 }
406
407 /**
408 * Prepare field arguments.
409 *
410 * @param array $args
411 * @return array
412 */
413 public function prepare_field_args( $field, $field_id, $field_key, $setting_id, $setting_name ) {
414 // get field type
415 $field_type = ! empty( $field['type'] ) ? $field['type'] : '';
416
417 return [
418 'id' => $field_id,
419 'name' => $setting_name . '[' . $field_key . ']',
420 'class' => ! empty( $field['class'] ) ? $field['class'] : '',
421 'type' => $field_type,
422 'label' => ! empty( $field['label'] ) ? $field['label'] : '',
423 'description' => ! empty( $field['description'] ) ? $field['description'] : '',
424 'text' => ! empty( $field['text'] ) ? $field['text'] : '',
425 'min' => ! empty( $field['min'] ) ? (int) $field['min'] : 0,
426 'max' => ! empty( $field['max'] ) ? (int) $field['max'] : 0,
427 'options' => ! empty( $field['options'] ) ? $field['options'] : [],
428 'callback' => ! empty( $field['callback'] ) ? $field['callback'] : null,
429 'validate' => ! empty( $field['validate'] ) ? $field['validate'] : null,
430 'callback_args' => ! empty( $field['callback_args'] ) ? $field['callback_args'] : [],
431 'default' => $field_type !== 'custom' ? $this->object->defaults[$setting_id][$field_key] : null,
432 'value' => $field_type !== 'custom' ? $this->object->options[$setting_id][$field_key] : null
433 /*
434 after_field
435 before_field
436 */
437 ];
438 }
439
440 /**
441 * Render settings field.
442 *
443 * @param array $args
444 * @return void|string
445 */
446 public function render_field( $args ) {
447 if ( empty( $args ) || ! is_array( $args ) )
448 return;
449
450 $html = '<div id="' . esc_attr( $args['id'] ) . '_setting"' . ( ! empty( $args['class'] ) ? ' class="' . esc_attr( $args['class'] ) . '"' : '' ) . '>';
451
452 if ( ! empty ( $args['before_field'] ) )
453 $html .= $args['before_field'];
454
455 switch ( $args['type'] ) {
456 case 'boolean':
457 if ( empty( $args['disabled'] ) )
458 $html .= '<input type="hidden" name="' . esc_attr( $args['name'] ) . '" value="false" />';
459
460 $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>';
461 break;
462
463 case 'radio':
464 foreach ( $args['options'] as $key => $name ) {
465 $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> ';
466 }
467 break;
468
469 case 'checkbox':
470 // possible "empty" value
471 if ( $args['value'] === 'empty' )
472 $args['value'] = [];
473
474 $display_type = ! empty( $args['display_type'] ) && in_array( $args['display_type'], [ 'horizontal', 'vertical' ], true ) ? $args['display_type'] : 'horizontal';
475
476 $html .= '<input type="hidden" name="' . esc_attr( $args['name'] ) . '" value="empty" />';
477
478 foreach ( $args['options'] as $key => $name ) {
479 $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 />' );
480 }
481 break;
482
483 case 'select':
484 $html .= '<select id="' . esc_attr( $args['id'] ) . '" name="' . esc_attr( $args['name'] ) . '" />';
485
486 foreach ( $args['options'] as $key => $name ) {
487 $html .= '<option value="' . esc_attr( $key ) . '" ' . selected( $args['value'], $key, false ) . '>' . esc_html( $name ) . '</option>';
488 }
489
490 $html .= '</select>';
491 break;
492
493 case 'range':
494 $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>';
495 break;
496
497 case 'number':
498 $html .= ( ! empty( $args['prepend'] ) ? wp_kses_post( $args['prepend'] ) : '' );
499 $html .= '<input id="' . $args['id'] . '" type="text" value="' . esc_attr( $args['value'] ) . '" name="' . esc_attr( $args['name'] ) . '" />';
500 $html .= ( ! empty( $args['append'] ) ? wp_kses_post( $args['append'] ) : '' );
501 break;
502
503 case 'custom':
504 $html .= call_user_func( $args['callback'], $args );
505 break;
506
507 case 'info':
508 $html .= '<span' . ( ! empty( $args['subclass'] ) ? ' class="' . esc_attr( $args['subclass'] ) . '"' : '' ) . '>' . esc_html( $args['text'] ) . '</span>';
509 break;
510
511 case 'class':
512 case 'input':
513 default:
514 $empty_disabled = empty( $args['disabled'] );
515
516 $html .= ( ! empty( $args['prepend'] ) ? wp_kses_post( $args['prepend'] ) : '' );
517 $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 ) . '/>';
518 $html .= ( ! empty( $args['append'] ) ? wp_kses_post( $args['append'] ) : '' );
519
520 if ( ! $empty_disabled )
521 $html .= '<input' . ( $empty_disabled ? '' : ' class="hidden"' ) . ' type="text" value="' . esc_attr( $args['value'] ) . '" name="' . esc_attr( $args['name'] ) . '">';
522 }
523
524 if ( ! empty ( $args['after_field'] ) )
525 $html .= $args['after_field'];
526
527 if ( ! empty ( $args['description'] ) )
528 $html .= '<p class="description">' . $args['description'] . '</p>';
529
530 $html .= '</div>';
531
532 if ( ! empty( $args['return'] ) )
533 return $html;
534 else
535 echo $html;
536 }
537
538 /**
539 * Validate settings field.
540 *
541 * @param mixed $value
542 * @param string $type
543 * @param array $args
544 * @return mixed
545 */
546 public function validate_field( $value = null, $type = '', $args = [] ) {
547 if ( is_null( $value ) )
548 return null;
549
550 switch ( $type ) {
551 case 'boolean':
552 // possible value: 'true' or 'false'
553 $value = ( $value === 'true' || $value === true );
554 break;
555
556 case 'radio':
557 $value = is_array( $value ) ? $args['default'] : sanitize_key( $value );
558
559 // disallow disabled radios
560 if ( ! empty( $args['disabled'] ) && in_array( $value, $args['disabled'], true ) )
561 $value = $args['default'];
562 break;
563
564 case 'checkbox':
565 // possible value: 'empty' or array
566 if ( $value === 'empty' )
567 $value = [];
568 else {
569 if ( is_array( $value ) && ! empty( $value ) ) {
570 $value = array_map( 'sanitize_key', $value );
571 $values = [];
572
573 foreach ( $value as $single_value ) {
574 if ( array_key_exists( $single_value, $args['options'] ) )
575 $values[] = $single_value;
576 }
577
578 $value = $values;
579 } else
580 $value = [];
581 }
582 break;
583
584 case 'number':
585 $value = (int) $value;
586
587 // is value lower than?
588 if ( isset( $args['min'] ) && $value < $args['min'] )
589 $value = $args['min'];
590
591 // is value greater than?
592 if ( isset( $args['max'] ) && $value > $args['max'] )
593 $value = $args['max'];
594 break;
595
596 case 'info':
597 $value = '';
598 break;
599
600 case 'custom':
601 // do nothing
602 break;
603
604 case 'class':
605 $value = trim( $value );
606
607 // more than 1 class?
608 if ( strpos( $value, ' ' ) !== false ) {
609 // get unique valid HTML classes
610 $value = array_unique( array_filter( array_map( 'sanitize_html_class', explode( ' ', $value ) ) ) );
611
612 if ( ! empty( $value ) )
613 $value = implode( ' ', $value );
614 else
615 $value = '';
616 // single class
617 } else
618 $value = sanitize_html_class( $value, $args['default'] );
619 break;
620
621 case 'input':
622 case 'select':
623 default:
624 $value = is_array( $value ) ? array_map( 'sanitize_text_field', $value ) : sanitize_text_field( $value );
625 break;
626 }
627
628 return stripslashes_deep( $value );
629 }
630
631 /**
632 * Validate settings.
633 *
634 * @param array $input
635 * @return array
636 */
637 public function validate_settings( $input ) {
638 // check capability
639 if ( ! current_user_can( 'manage_options' ) )
640 return $input;
641
642 // check option page
643 if ( empty( $_POST['option_page'] ) )
644 return $input;
645
646 // try to get setting name and ID
647 foreach ( $this->settings as $id => $setting ) {
648 // tabs?
649 if ( is_array( $setting['option_name'] ) ) {
650 foreach ( $setting['option_name'] as $tab => $option_name ) {
651 // found valid setting?
652 if ( $option_name === $_POST['option_page'] ) {
653 // assign setting ID
654 $setting_id = $tab;
655
656 // assign setting name
657 $setting_name = $option_name;
658
659 // assign setting key
660 $setting_key = $id;
661
662 // already found setting, no need to check the rest
663 break 2;
664 }
665 }
666 } else {
667 // found valid setting?
668 if ( $setting['option_name'] === $_POST['option_page'] ) {
669 // assign setting ID and key
670 $setting_key = $setting_id = $id;
671
672 // assign setting name
673 $setting_name = $setting['option_name'];
674
675 // already found setting, no need to check the rest
676 break;
677 }
678 }
679 }
680
681 // check setting id, no need to check $setting_name since it was at the same stage
682 if ( empty( $setting_id ) )
683 return $input;
684
685 // save settings
686 if ( isset( $_POST['save_' . $setting_name] ) ) {
687 $input = $this->validate_input_settings( $setting_id, $setting_key, $input );
688
689 add_settings_error( $setting_name, 'settings_saved', __( 'Settings saved.', $this->domain ), 'updated' );
690 // reset settings
691 } elseif ( isset( $_POST['reset_' . $setting_name] ) ) {
692 // get default values
693 $input = $this->object->defaults[$setting_id];
694
695 // check custom reset functions
696 if ( ! empty( $this->settings[$setting_key]['fields'] ) ) {
697 foreach ( $this->settings[$setting_key]['fields'] as $field_id => $field ) {
698 // skip invalid tab field if any
699 if ( ! empty( $field['tab'] ) && $field['tab'] !== $setting_id )
700 continue;
701
702 // custom reset function?
703 if ( ! empty( $field['reset'] ) ) {
704 // valid function? no need to check "else" since all default values are already set
705 if ( $this->callback_function_exists( $field['reset'] ) ) {
706 if ( $field['type'] === 'custom' )
707 $input = call_user_func( $field['reset'], $input, $field );
708 else
709 $input[$field_id] = call_user_func( $field['reset'], $input[$field_id], $field );
710 }
711 }
712 }
713 }
714
715 add_settings_error( $setting_name, 'settings_restored', __( 'Settings restored to defaults.', $this->domain ), 'updated' );
716 }
717
718 return $input;
719 }
720
721 /**
722 * Validate input settings.
723 *
724 * @param string $setting_id
725 * @param array $input
726 * @return array
727 */
728 public function validate_input_settings( $setting_id, $setting_key, $input ) {
729 if ( ! empty( $this->settings[$setting_key]['fields'] ) ) {
730 foreach ( $this->settings[$setting_key]['fields'] as $field_id => $field ) {
731 // skip saving this field?
732 if ( ! empty( $field['skip_saving'] ) )
733 continue;
734
735 // skip invalid tab field if any
736 if ( ! empty( $field['tab'] ) && $field['tab'] !== $setting_id )
737 continue;
738
739 // custom validate function?
740 if ( ! empty( $field['validate'] ) ) {
741 // valid function?
742 if ( $this->callback_function_exists( $field['validate'] ) ) {
743 if ( $field['type'] === 'custom' )
744 $input = call_user_func( $field['validate'], $input, $field );
745 else
746 $input[$field_id] = isset( $input[$field_id] ) ? call_user_func( $field['validate'], $input[$field_id], $field ) : $this->object->defaults[$setting_id][$field_id];
747 } else
748 $input[$field_id] = $this->object->defaults[$setting_id][$field_id];
749 } else {
750 // field data?
751 if ( isset( $input[$field_id] ) ) {
752 // make sure default value is available
753 if ( ! isset( $field['default'] ) )
754 $field['default'] = $this->object->defaults[$setting_id][$field_id];
755
756 $input[$field_id] = $this->validate_field( $input[$field_id], $field['type'], $field );
757 } else
758 $input[$field_id] = $this->object->defaults[$setting_id][$field_id];
759 }
760
761 // update input data
762 $this->input_settings = $input;
763
764 // add this field as validated
765 $this->validated_settings[] = $field_id;
766 }
767 }
768
769 return $input;
770 }
771
772 /**
773 * Check whether callback is a valid function.
774 *
775 * @param string|array $callback
776 * @return bool
777 */
778 public function callback_function_exists( $callback ) {
779 // function as array?
780 if ( is_array( $callback ) ) {
781 list( $object, $function ) = $callback;
782
783 // check function existence
784 $function_exists = method_exists( $object, $function );
785 // function as string?
786 } elseif ( is_string( $callback ) ) {
787 // check function existence
788 $function_exists = function_exists( $callback );
789 } else
790 $function_exists = false;
791
792 return $function_exists;
793 }
794
795 /**
796 * Get value based on minimum and maximum.
797 *
798 * @param array $data
799 * @param string $setting_name
800 * @param int $default
801 * @param int $min
802 * @param int $max
803 * @return void
804 */
805 public function get_int_value( $data, $setting_name, $default, $min, $max ) {
806 // check existence of value
807 $value = array_key_exists( $setting_name, $data ) ? (int) $data[$setting_name] : $default;
808
809 if ( $value > $max || $value < $min )
810 $value = $default;
811
812 return $value;
813 }
814 }
815