PluginProbe ʕ •ᴥ•ʔ
Post Views Counter / 1.6.1
Post Views Counter v1.6.1
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 6 months ago class-columns.php 6 months ago class-counter.php 6 months ago class-crawler-detect.php 6 months ago class-cron.php 6 months ago class-dashboard.php 6 months ago class-frontend.php 6 months ago class-functions.php 6 months ago class-import.php 6 months ago class-query.php 6 months ago class-settings-api.php 6 months ago class-settings.php 6 months ago class-toolbar.php 6 months ago class-update.php 6 months ago class-widgets.php 6 months ago functions.php 6 months ago
class-settings-api.php
837 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" novalidate>';
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 if ( empty( $args['options'] ) || ! is_array( $args['options'] ) )
473 break;
474 if ( count( $args['options'] ) > 1 )
475 $html .= '<div class="pvc-field-group pvc-radio-group">';
476 foreach ( $args['options'] as $key => $name ) {
477 $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> ';
478 }
479 if ( count( $args['options'] ) > 1 )
480 $html .= '</div>';
481 break;
482
483 case 'checkbox':
484 // possible "empty" value
485 if ( $args['value'] === 'empty' )
486 $args['value'] = [];
487
488 $display_type = ! empty( $args['display_type'] ) && in_array( $args['display_type'], [ 'horizontal', 'vertical' ], true ) ? $args['display_type'] : 'horizontal';
489
490 $html .= '<input type="hidden" name="' . esc_attr( $args['name'] ) . '" value="empty" />';
491
492 if ( empty( $args['options'] ) || ! is_array( $args['options'] ) )
493 break;
494 if ( count( $args['options'] ) > 1 )
495 $html .= '<div class="pvc-field-group pvc-checkbox-group">';
496 foreach ( $args['options'] as $key => $name ) {
497 $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 />' );
498 }
499 if ( count( $args['options'] ) > 1 )
500 $html .= '</div>';
501 break;
502
503 case 'select':
504 $html .= '<select id="' . esc_attr( $args['id'] ) . '" name="' . esc_attr( $args['name'] ) . '" ' . disabled( empty( $args['disabled'] ), false, false ) . '/>';
505
506 foreach ( $args['options'] as $key => $name ) {
507 $html .= '<option value="' . esc_attr( $key ) . '" ' . selected( $args['value'], $key, false ) . '>' . esc_html( $name ) . '</option>';
508 }
509
510 $html .= '</select>';
511 break;
512
513 case 'range':
514 $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>';
515 break;
516
517 case 'number':
518 $html .= ( ! empty( $args['prepend'] ) ? wp_kses_post( $args['prepend'] ) : '' );
519 $html .= '<input id="' . $args['id'] . '" type="text" value="' . esc_attr( $args['value'] ) . '" name="' . esc_attr( $args['name'] ) . '" />';
520 $html .= ( ! empty( $args['append'] ) ? wp_kses_post( $args['append'] ) : '' );
521 break;
522
523 case 'custom':
524 $html .= call_user_func( $args['callback'], $args );
525 break;
526
527 case 'info':
528 $html .= '<span' . ( ! empty( $args['subclass'] ) ? ' class="' . esc_attr( $args['subclass'] ) . '"' : '' ) . '>' . esc_html( $args['text'] ) . '</span>';
529 break;
530
531 case 'class':
532 case 'input':
533 default:
534 $empty_disabled = empty( $args['disabled'] );
535
536 $html .= ( ! empty( $args['prepend'] ) ? wp_kses_post( $args['prepend'] ) : '' );
537 $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 ) . '/>';
538 $html .= ( ! empty( $args['append'] ) ? wp_kses_post( $args['append'] ) : '' );
539
540 if ( ! $empty_disabled )
541 $html .= '<input' . ( $empty_disabled ? '' : ' class="hidden"' ) . ' type="text" value="' . esc_attr( $args['value'] ) . '" name="' . esc_attr( $args['name'] ) . '">';
542 }
543
544 if ( ! empty ( $args['after_field'] ) )
545 $html .= $args['after_field'];
546
547 if ( ! empty ( $args['description'] ) )
548 $html .= '<p class="description">' . $args['description'] . '</p>';
549
550 $html .= '</div>';
551
552 if ( ! empty( $args['return'] ) )
553 return $html;
554 else
555 echo $html;
556 }
557
558 /**
559 * Validate settings field.
560 *
561 * @param mixed $value
562 * @param string $type
563 * @param array $args
564 * @return mixed
565 */
566 public function validate_field( $value = null, $type = '', $args = [] ) {
567 if ( is_null( $value ) )
568 return null;
569
570 switch ( $type ) {
571 case 'boolean':
572 // possible value: 'true' or 'false'
573 $value = ( $value === 'true' || $value === true );
574 break;
575
576 case 'radio':
577 $value = is_array( $value ) ? $args['default'] : sanitize_key( $value );
578
579 // disallow disabled radios
580 if ( ! empty( $args['disabled'] ) && in_array( $value, $args['disabled'], true ) )
581 $value = $args['default'];
582 break;
583
584 case 'checkbox':
585 // possible value: 'empty' or array
586 if ( $value === 'empty' )
587 $value = [];
588 else {
589 if ( is_array( $value ) && ! empty( $value ) ) {
590 $value = array_map( 'sanitize_key', $value );
591 $values = [];
592
593 foreach ( $value as $single_value ) {
594 if ( array_key_exists( $single_value, $args['options'] ) )
595 $values[] = $single_value;
596 }
597
598 $value = $values;
599 } else
600 $value = [];
601 }
602 break;
603
604 case 'number':
605 $value = (int) $value;
606
607 // is value lower than?
608 if ( isset( $args['min'] ) && $value < $args['min'] )
609 $value = $args['min'];
610
611 // is value greater than?
612 if ( isset( $args['max'] ) && $value > $args['max'] )
613 $value = $args['max'];
614 break;
615
616 case 'info':
617 $value = '';
618 break;
619
620 case 'custom':
621 // do nothing
622 break;
623
624 case 'class':
625 $value = trim( $value );
626
627 // more than 1 class?
628 if ( strpos( $value, ' ' ) !== false ) {
629 // get unique valid HTML classes
630 $value = array_unique( array_filter( array_map( 'sanitize_html_class', explode( ' ', $value ) ) ) );
631
632 if ( ! empty( $value ) )
633 $value = implode( ' ', $value );
634 else
635 $value = '';
636 // single class
637 } else
638 $value = sanitize_html_class( $value, $args['default'] );
639 break;
640
641 case 'input':
642 case 'select':
643 default:
644 $value = is_array( $value ) ? array_map( 'sanitize_text_field', $value ) : sanitize_text_field( $value );
645 break;
646 }
647
648 return stripslashes_deep( $value );
649 }
650
651 /**
652 * Validate settings.
653 *
654 * @param array $input
655 * @return array
656 */
657 public function validate_settings( $input ) {
658 // check capability
659 if ( ! current_user_can( 'manage_options' ) )
660 return $input;
661
662 // check option page
663 if ( empty( $_POST['option_page'] ) )
664 return $input;
665
666 // try to get setting name and ID
667 foreach ( $this->settings as $id => $setting ) {
668 // tabs?
669 if ( is_array( $setting['option_name'] ) ) {
670 foreach ( $setting['option_name'] as $tab => $option_name ) {
671 // found valid setting?
672 if ( $option_name === $_POST['option_page'] ) {
673 // assign setting ID
674 $setting_id = $tab;
675
676 // assign setting name
677 $setting_name = $option_name;
678
679 // assign setting key
680 $setting_key = $id;
681
682 // already found setting, no need to check the rest
683 break 2;
684 }
685 }
686 } else {
687 // found valid setting?
688 if ( $setting['option_name'] === $_POST['option_page'] ) {
689 // assign setting ID and key
690 $setting_key = $setting_id = $id;
691
692 // assign setting name
693 $setting_name = $setting['option_name'];
694
695 // already found setting, no need to check the rest
696 break;
697 }
698 }
699 }
700
701 // check setting id, no need to check $setting_name since it was at the same stage
702 if ( empty( $setting_id ) )
703 return $input;
704
705 // save settings
706 if ( isset( $_POST['save_' . $setting_name] ) ) {
707 $input = $this->validate_input_settings( $setting_id, $setting_key, $input );
708
709 add_settings_error( $setting_name, 'settings_saved', __( 'Settings saved.', $this->domain ), 'updated' );
710 // reset settings
711 } elseif ( isset( $_POST['reset_' . $setting_name] ) ) {
712 // get default values
713 $input = $this->object->defaults[$setting_id];
714
715 // check custom reset functions
716 if ( ! empty( $this->settings[$setting_key]['fields'] ) ) {
717 foreach ( $this->settings[$setting_key]['fields'] as $field_id => $field ) {
718 // skip invalid tab field if any
719 if ( ! empty( $field['tab'] ) && $field['tab'] !== $setting_id )
720 continue;
721
722 // custom reset function?
723 if ( ! empty( $field['reset'] ) ) {
724 // valid function? no need to check "else" since all default values are already set
725 if ( $this->callback_function_exists( $field['reset'] ) ) {
726 if ( $field['type'] === 'custom' )
727 $input = call_user_func( $field['reset'], $input, $field );
728 else
729 $input[$field_id] = call_user_func( $field['reset'], $input[$field_id], $field );
730 }
731 }
732 }
733 }
734
735 add_settings_error( $setting_name, 'settings_restored', __( 'Settings restored to defaults.', $this->domain ), 'updated' );
736 }
737
738 do_action( $this->short . '_configuration_updated', 'settings', $input );
739
740 return $input;
741 }
742
743 /**
744 * Validate input settings.
745 *
746 * @param string $setting_id
747 * @param array $input
748 * @return array
749 */
750 public function validate_input_settings( $setting_id, $setting_key, $input ) {
751 if ( ! empty( $this->settings[$setting_key]['fields'] ) ) {
752 foreach ( $this->settings[$setting_key]['fields'] as $field_id => $field ) {
753 // skip saving this field?
754 if ( ! empty( $field['skip_saving'] ) )
755 continue;
756
757 // skip invalid tab field if any
758 if ( ! empty( $field['tab'] ) && $field['tab'] !== $setting_id )
759 continue;
760
761 // custom validate function?
762 if ( ! empty( $field['validate'] ) ) {
763 // valid function?
764 if ( $this->callback_function_exists( $field['validate'] ) ) {
765 if ( $field['type'] === 'custom' )
766 $input = call_user_func( $field['validate'], $input, $field );
767 else
768 $input[$field_id] = isset( $input[$field_id] ) ? call_user_func( $field['validate'], $input[$field_id], $field ) : $this->object->defaults[$setting_id][$field_id];
769 } else
770 $input[$field_id] = $this->object->defaults[$setting_id][$field_id];
771 } else {
772 // field data?
773 if ( isset( $input[$field_id] ) ) {
774 // make sure default value is available
775 if ( ! isset( $field['default'] ) )
776 $field['default'] = $this->object->defaults[$setting_id][$field_id];
777
778 $input[$field_id] = $this->validate_field( $input[$field_id], $field['type'], $field );
779 } else
780 $input[$field_id] = $this->object->defaults[$setting_id][$field_id];
781 }
782
783 // update input data
784 $this->input_settings = $input;
785
786 // add this field as validated
787 $this->validated_settings[] = $field_id;
788 }
789 }
790
791 return $input;
792 }
793
794 /**
795 * Check whether callback is a valid function.
796 *
797 * @param string|array $callback
798 * @return bool
799 */
800 public function callback_function_exists( $callback ) {
801 // function as array?
802 if ( is_array( $callback ) ) {
803 list( $object, $function ) = $callback;
804
805 // check function existence
806 $function_exists = method_exists( $object, $function );
807 // function as string?
808 } elseif ( is_string( $callback ) ) {
809 // check function existence
810 $function_exists = function_exists( $callback );
811 } else
812 $function_exists = false;
813
814 return $function_exists;
815 }
816
817 /**
818 * Get value based on minimum and maximum.
819 *
820 * @param array $data
821 * @param string $setting_name
822 * @param int $default
823 * @param int $min
824 * @param int $max
825 * @return void
826 */
827 public function get_int_value( $data, $setting_name, $default, $min, $max ) {
828 // check existence of value
829 $value = array_key_exists( $setting_name, $data ) ? (int) $data[$setting_name] : $default;
830
831 if ( $value > $max || $value < $min )
832 $value = $default;
833
834 return $value;
835 }
836 }
837