· 7 years ago · Oct 14, 2018, 10:34 AM
1<?php
2
3if ( ! class_exists( 'Ever_WP_Settings_API' ) ):
4 class Ever_WP_Settings_API {
5 /**
6 * settings sections array
7 *
8 * @var array
9 */
10 protected $settings_sections = array();
11 /**
12 * Settings fields array
13 *
14 * @var array
15 */
16 protected $settings_fields = array();
17
18 public function __construct() {
19 add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
20 }
21
22 /**
23 * Enqueue scripts and styles
24 */
25 function admin_enqueue_scripts() {
26 wp_enqueue_style( 'wp-color-picker' );
27 wp_enqueue_media();
28 wp_enqueue_script( 'wp-color-picker' );
29 wp_enqueue_script( 'jquery' );
30 }
31
32 /**
33 * Set settings sections
34 *
35 * @since 1.0.0
36 *
37 * @param $sections
38 *
39 * @return $this
40 *
41 */
42 function set_sections( $sections ) {
43 $this->settings_sections = $sections;
44
45 return $this;
46 }
47
48 /**
49 * Add a single section
50 *
51 * @since 1.0.0
52 *
53 * @param $section
54 *
55 * @return $this
56 *
57 */
58 function add_section( $section ) {
59 $this->settings_sections[] = $section;
60
61 return $this;
62 }
63
64 /**
65 * Set settings fields
66 *
67 * @since 1.0.0
68 *
69 * @param $fields
70 *
71 * @return $this
72 *
73 */
74 function set_fields( $fields ) {
75 $this->settings_fields = $fields;
76
77 return $this;
78 }
79
80 /**
81 * Set fields
82 *
83 * @since 1.0.0
84 *
85 * @param $section
86 * @param $field
87 *
88 * @return $this
89 *
90 */
91 function add_field( $section, $field ) {
92 $defaults = array(
93 'name' => '',
94 'label' => '',
95 'desc' => '',
96 'type' => 'text'
97 );
98 $arg = wp_parse_args( $field, $defaults );
99 $this->settings_fields[ $section ][] = $arg;
100
101 return $this;
102 }
103
104 /**
105 * Initialize and registers the settings sections and fileds to WordPress
106 *
107 * Usually this should be called at `admin_init` hook.
108 *
109 * This function gets the initiated settings sections and fields. Then
110 * registers them to WordPress and ready for use.
111 */
112 function admin_init() {
113 //register settings sections
114 foreach ( $this->settings_sections as $section ) {
115 if ( false == get_option( $section['id'] ) ) {
116 add_option( $section['id'] );
117 }
118 if ( isset( $section['desc'] ) && ! empty( $section['desc'] ) ) {
119 $section['desc'] = '<div class="inside">' . $section['desc'] . '</div>';
120 $callback = create_function( '', 'echo "' . str_replace( '"', '\"', $section['desc'] ) . '";' );
121 } else if ( isset( $section['callback'] ) ) {
122 $callback = $section['callback'];
123 } else {
124 $callback = null;
125 }
126 add_settings_section( $section['id'], $section['title'], $callback, $section['id'] );
127 }
128 //register settings fields
129 foreach ( $this->settings_fields as $section => $field ) {
130 foreach ( $field as $option ) {
131 $name = $option['name'];
132 $type = isset( $option['type'] ) ? $option['type'] : 'text';
133 $label = isset( $option['label'] ) ? $option['label'] : '';
134 $callback = isset( $option['callback'] ) ? $option['callback'] : array(
135 $this,
136 'callback_' . $type
137 );
138 $args = array(
139 'id' => $name,
140 'class' => isset( $option['class'] ) ? $option['class'] : $name,
141 'label_for' => "{$section}[{$name}]",
142 'desc' => isset( $option['desc'] ) ? $option['desc'] : '',
143 'name' => $label,
144 'section' => $section,
145 'size' => isset( $option['size'] ) ? $option['size'] : null,
146 'options' => isset( $option['options'] ) ? $option['options'] : '',
147 'std' => isset( $option['default'] ) ? $option['default'] : '',
148 'sanitize_callback' => isset( $option['sanitize_callback'] ) ? $option['sanitize_callback'] : '',
149 'type' => $type,
150 'placeholder' => isset( $option['placeholder'] ) ? $option['placeholder'] : '',
151 'min' => isset( $option['min'] ) ? $option['min'] : '',
152 'max' => isset( $option['max'] ) ? $option['max'] : '',
153 'step' => isset( $option['step'] ) ? $option['step'] : '',
154 );
155 add_settings_field( "{$section}[{$name}]", $label, $callback, $section, $section, $args );
156 }
157 }
158 // creates our settings in the options table
159 foreach ( $this->settings_sections as $section ) {
160 register_setting( $section['id'], $section['id'], array( $this, 'sanitize_options' ) );
161 }
162 }
163
164 /**
165 * Get field description for display
166 *
167 * @since 1.0.0
168 *
169 * @param $args
170 *
171 * @return string
172 *
173 */
174 public function get_field_description( $args ) {
175 if ( ! empty( $args['desc'] ) ) {
176 $desc = sprintf( '<p class="description">%s</p>', $args['desc'] );
177 } else {
178 $desc = '';
179 }
180
181 return $desc;
182 }
183
184 /**
185 * Displays a text field for a settings field
186 *
187 * @param array $args settings field args
188 */
189 function callback_text( $args ) {
190 $value = esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) );
191 $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular';
192 $type = isset( $args['type'] ) ? $args['type'] : 'text';
193 $placeholder = empty( $args['placeholder'] ) ? '' : ' placeholder="' . $args['placeholder'] . '"';
194 $html = sprintf( '<input type="%1$s" class="%2$s-text" id="%3$s[%4$s]" name="%3$s[%4$s]" value="%5$s"%6$s/>', $type, $size, $args['section'], $args['id'], $value, $placeholder );
195 $html .= $this->get_field_description( $args );
196 echo $html;
197 }
198
199 /**
200 * Displays a url field for a settings field
201 *
202 * @param array $args settings field args
203 */
204 function callback_url( $args ) {
205 $this->callback_text( $args );
206 }
207
208 /**
209 * Displays a number field for a settings field
210 *
211 * @param array $args settings field args
212 */
213 function callback_number( $args ) {
214 $value = esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) );
215 $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular';
216 $type = isset( $args['type'] ) ? $args['type'] : 'number';
217 $placeholder = empty( $args['placeholder'] ) ? '' : ' placeholder="' . $args['placeholder'] . '"';
218 $min = ( $args['min'] == '' ) ? '' : ' min="' . $args['min'] . '"';
219 $max = ( $args['max'] == '' ) ? '' : ' max="' . $args['max'] . '"';
220 $step = ( $args['step'] == '' ) ? '' : ' step="' . $args['step'] . '"';
221 $html = sprintf( '<input type="%1$s" class="%2$s-number" id="%3$s[%4$s]" name="%3$s[%4$s]" value="%5$s"%6$s%7$s%8$s%9$s/>', $type, $size, $args['section'], $args['id'], $value, $placeholder, $min, $max, $step );
222 $html .= $this->get_field_description( $args );
223 echo $html;
224 }
225
226 /**
227 * Displays a checkbox for a settings field
228 *
229 * @param array $args settings field args
230 */
231 function callback_checkbox( $args ) {
232 $value = esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) );
233 $html = '<fieldset>';
234 $html .= sprintf( '<label for="wpuf-%1$s[%2$s]">', $args['section'], $args['id'] );
235 $html .= sprintf( '<input type="hidden" name="%1$s[%2$s]" value="off" />', $args['section'], $args['id'] );
236 $html .= sprintf( '<input type="checkbox" class="checkbox" id="wpuf-%1$s[%2$s]" name="%1$s[%2$s]" value="on" %3$s />', $args['section'], $args['id'], checked( $value, 'on', false ) );
237 $html .= sprintf( '%1$s</label>', $args['desc'] );
238 $html .= '</fieldset>';
239 echo $html;
240 }
241
242 /**
243 * Displays a multicheckbox for a settings field
244 *
245 * @param array $args settings field args
246 */
247 function callback_multicheck( $args ) {
248 $value = $this->get_option( $args['id'], $args['section'], $args['std'] );
249 $html = '<fieldset>';
250 $html .= sprintf( '<input type="hidden" name="%1$s[%2$s]" value="" />', $args['section'], $args['id'] );
251 foreach ( $args['options'] as $key => $label ) {
252 $checked = isset( $value[ $key ] ) ? $value[ $key ] : '0';
253 $html .= sprintf( '<label for="wpuf-%1$s[%2$s][%3$s]">', $args['section'], $args['id'], $key );
254 $html .= sprintf( '<input type="checkbox" class="checkbox" id="wpuf-%1$s[%2$s][%3$s]" name="%1$s[%2$s][%3$s]" value="%3$s" %4$s />', $args['section'], $args['id'], $key, checked( $checked, $key, false ) );
255 $html .= sprintf( '%1$s</label><br>', $label );
256 }
257 $html .= $this->get_field_description( $args );
258 $html .= '</fieldset>';
259 echo $html;
260 }
261
262 /**
263 * Displays a radio button for a settings field
264 *
265 * @param array $args settings field args
266 */
267 function callback_radio( $args ) {
268 $value = $this->get_option( $args['id'], $args['section'], $args['std'] );
269 $html = '<fieldset>';
270 foreach ( $args['options'] as $key => $label ) {
271 $html .= sprintf( '<label for="wpuf-%1$s[%2$s][%3$s]">', $args['section'], $args['id'], $key );
272 $html .= sprintf( '<input type="radio" class="radio" id="wpuf-%1$s[%2$s][%3$s]" name="%1$s[%2$s]" value="%3$s" %4$s />', $args['section'], $args['id'], $key, checked( $value, $key, false ) );
273 $html .= sprintf( '%1$s</label><br>', $label );
274 }
275 $html .= $this->get_field_description( $args );
276 $html .= '</fieldset>';
277 echo $html;
278 }
279
280 /**
281 * Displays a selectbox for a settings field
282 *
283 * @param array $args settings field args
284 */
285 function callback_select( $args ) {
286 $value = esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) );
287 $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular';
288 $html = sprintf( '<select class="%1$s" name="%2$s[%3$s]" id="%2$s[%3$s]">', $size, $args['section'], $args['id'] );
289 foreach ( $args['options'] as $key => $label ) {
290 $html .= sprintf( '<option value="%s"%s>%s</option>', $key, selected( $value, $key, false ), $label );
291 }
292 $html .= sprintf( '</select>' );
293 $html .= $this->get_field_description( $args );
294 echo $html;
295 }
296
297 /**
298 * Displays a textarea for a settings field
299 *
300 * @param array $args settings field args
301 */
302 function callback_textarea( $args ) {
303 $value = esc_textarea( $this->get_option( $args['id'], $args['section'], $args['std'] ) );
304 $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular';
305 $placeholder = empty( $args['placeholder'] ) ? '' : ' placeholder="' . $args['placeholder'] . '"';
306 $html = sprintf( '<textarea rows="5" cols="55" class="%1$s-text" id="%2$s[%3$s]" name="%2$s[%3$s]"%4$s>%5$s</textarea>', $size, $args['section'], $args['id'], $placeholder, $value );
307 $html .= $this->get_field_description( $args );
308 echo $html;
309 }
310
311 /**
312 * Displays the html for a settings field
313 *
314 * @param array $args settings field args
315 *
316 * @return string
317 */
318 function callback_html( $args ) {
319 echo $this->get_field_description( $args );
320 }
321
322 /**
323 * Displays a rich text textarea for a settings field
324 *
325 * @param array $args settings field args
326 */
327 function callback_wysiwyg( $args ) {
328 $value = $this->get_option( $args['id'], $args['section'], $args['std'] );
329 $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : '500px';
330 echo '<div style="max-width: ' . $size . ';">';
331 $editor_settings = array(
332 'teeny' => true,
333 'textarea_name' => $args['section'] . '[' . $args['id'] . ']',
334 'textarea_rows' => 10
335 );
336 if ( isset( $args['options'] ) && is_array( $args['options'] ) ) {
337 $editor_settings = array_merge( $editor_settings, $args['options'] );
338 }
339 wp_editor( $value, $args['section'] . '-' . $args['id'], $editor_settings );
340 echo '</div>';
341 echo $this->get_field_description( $args );
342 }
343
344 /**
345 * Displays a file upload field for a settings field
346 *
347 * @param array $args settings field args
348 */
349 function callback_file( $args ) {
350 $value = esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) );
351 $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular';
352 $id = $args['section'] . '[' . $args['id'] . ']';
353 $label = isset( $args['options']['button_label'] ) ? $args['options']['button_label'] : __( 'Choose File' );
354 $html = sprintf( '<input type="text" class="%1$s-text wpsa-url" id="%2$s[%3$s]" name="%2$s[%3$s]" value="%4$s"/>', $size, $args['section'], $args['id'], $value );
355 $html .= '<input type="button" class="button wpsa-browse" value="' . $label . '" />';
356 $html .= $this->get_field_description( $args );
357 echo $html;
358 }
359
360 /**
361 * Displays a password field for a settings field
362 *
363 * @param array $args settings field args
364 */
365 function callback_password( $args ) {
366 $value = esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) );
367 $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular';
368 $html = sprintf( '<input type="password" class="%1$s-text" id="%2$s[%3$s]" name="%2$s[%3$s]" value="%4$s"/>', $size, $args['section'], $args['id'], $value );
369 $html .= $this->get_field_description( $args );
370 echo $html;
371 }
372
373 /**
374 * Displays a color picker field for a settings field
375 *
376 * @param array $args settings field args
377 */
378 function callback_color( $args ) {
379 $value = esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) );
380 $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular';
381 $html = sprintf( '<input type="text" class="%1$s-text wp-color-picker-field" id="%2$s[%3$s]" name="%2$s[%3$s]" value="%4$s" data-default-color="%5$s" />', $size, $args['section'], $args['id'], $value, $args['std'] );
382 $html .= $this->get_field_description( $args );
383 echo $html;
384 }
385
386 /**
387 * Displays a select box for creating the pages select box
388 *
389 * @param array $args settings field args
390 */
391 function callback_pages( $args ) {
392 $dropdown_args = array(
393 'selected' => esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) ),
394 'name' => $args['section'] . '[' . $args['id'] . ']',
395 'id' => $args['section'] . '[' . $args['id'] . ']',
396 'echo' => 0
397 );
398 $html = wp_dropdown_pages( $dropdown_args );
399 echo $html;
400 }
401
402 /**
403 * Sanitize callback for Settings API
404 *
405 * @return mixed
406 */
407 function sanitize_options( $options ) {
408 if ( ! $options ) {
409 return $options;
410 }
411 foreach ( $options as $option_slug => $option_value ) {
412 $sanitize_callback = $this->get_sanitize_callback( $option_slug );
413 // If callback is set, call it
414 if ( $sanitize_callback ) {
415 $options[ $option_slug ] = call_user_func( $sanitize_callback, $option_value );
416 continue;
417 }
418 }
419
420 return $options;
421 }
422
423 /**
424 * Get sanitization callback for given option slug
425 *
426 * @param string $slug option slug
427 *
428 * @return mixed string or bool false
429 */
430 function get_sanitize_callback( $slug = '' ) {
431 if ( empty( $slug ) ) {
432 return false;
433 }
434 // Iterate over registered fields and see if we can find proper callback
435 foreach ( $this->settings_fields as $section => $options ) {
436 foreach ( $options as $option ) {
437 if ( $option['name'] != $slug ) {
438 continue;
439 }
440
441 // Return the callback name
442 return isset( $option['sanitize_callback'] ) && is_callable( $option['sanitize_callback'] ) ? $option['sanitize_callback'] : false;
443 }
444 }
445
446 return false;
447 }
448
449 /**
450 * Get the value of a settings field
451 *
452 * @param string $option settings field name
453 * @param string $section the section name this field belongs to
454 * @param string $default default text if it's not found
455 *
456 * @return string
457 */
458 function get_option( $option, $section, $default = '' ) {
459 $options = get_option( $section );
460 if ( isset( $options[ $option ] ) ) {
461 return $options[ $option ];
462 }
463
464 return $default;
465 }
466
467 /**
468 * Show navigations as tab
469 *
470 * Shows all the settings section labels as tab
471 */
472 function show_navigation() {
473 $html = '<div class="ever-settings-sidebar"><ul>';
474 $count = count( $this->settings_sections );
475 // don't show the navigation if only one section exists
476 if ( $count === 1 ) {
477 return;
478 }
479 foreach ( $this->settings_sections as $tab ) {
480 $html .= sprintf( '<li><a href="#%1$s" id="%1$s-tab">%2$s</a></li>', $tab['id'], $tab['title'] );
481 }
482 $html .= '</ul></div>';
483 echo $html;
484 }
485
486 /**
487 * Show the section settings forms
488 *
489 * This function displays every sections in a different form
490 */
491 function show_forms() {
492 $this->_style_fix();
493 ?>
494 <div class="ever-settings-content">
495 <?php foreach ( $this->settings_sections as $form ) { ?>
496 <div id="<?php echo $form['id']; ?>" class="group" style="display: none;">
497 <form method="post" action="options.php">
498 <?php
499 do_action( 'wsa_form_top_' . $form['id'], $form );
500 settings_fields( $form['id'] );
501 do_settings_sections( $form['id'] );
502 do_action( 'wsa_form_bottom_' . $form['id'], $form );
503 if ( isset( $this->settings_fields[ $form['id'] ] ) ):
504 ?>
505 <div style="padding-left: 10px">
506 <?php submit_button(); ?>
507 </div>
508 <?php endif; ?>
509 </form>
510 </div>
511 <?php } ?>
512 </div>
513 <?php
514 $this->script();
515 }
516
517 function show_settings() {
518 echo '<div class="ever-settings d-flex">';
519 $this->show_navigation();
520 $this->show_forms();
521 echo '</div>';
522 }
523
524 /**
525 * Tabbable JavaScript codes & Initiate Color Picker
526 *
527 * This code uses localstorage for displaying active tabs
528 */
529 function script() {
530 ?>
531 <script>
532 jQuery(document).ready(function ($) {
533 //Initiate Color Picker
534 $('.wp-color-picker-field').wpColorPicker();
535 // Switches option sections
536 $('.group').hide();
537 var activetab = '';
538 if (typeof(localStorage) != 'undefined') {
539 activetab = localStorage.getItem("activetab");
540 }
541 //if url has section id as hash then set it as active or override the current local storage value
542 if (window.location.hash) {
543 activetab = window.location.hash;
544 if (typeof(localStorage) != 'undefined') {
545 localStorage.setItem("activetab", activetab);
546 }
547 }
548 if (activetab != '' && $(activetab).length) {
549 $(activetab).fadeIn();
550 } else {
551 $('.group:first').fadeIn();
552 }
553 $('.group .collapsed').each(function () {
554 $(this).find('input:checked').parent().parent().parent().nextAll().each(
555 function () {
556 if ($(this).hasClass('last')) {
557 $(this).removeClass('hidden');
558 return false;
559 }
560 $(this).filter('.hidden').removeClass('hidden');
561 });
562 });
563
564 if (activetab != '' && $(activetab + '-tab').length) {
565 $(activetab + '-tab').closest('li').addClass('active');
566 }
567 else {
568 $('.ever-settings-sidebar li:first').addClass('active');
569 }
570
571 $('.ever-settings-sidebar li a').click(function (evt) {
572 $('.ever-settings-sidebar li').removeClass('active');
573 $(this).closest('li').addClass('active').blur();
574
575 var clicked_group = $(this).attr('href');
576 if (typeof(localStorage) != 'undefined') {
577 localStorage.setItem("activetab", $(this).attr('href'));
578 }
579 $('.group').hide();
580 $(clicked_group).fadeIn();
581 evt.preventDefault();
582 });
583
584 $('.wpsa-browse').on('click', function (event) {
585 event.preventDefault();
586 var self = $(this);
587 // Create the media frame.
588 var file_frame = wp.media.frames.file_frame = wp.media({
589 title: self.data('uploader_title'),
590 button: {
591 text: self.data('uploader_button_text'),
592 },
593 multiple: false
594 });
595 file_frame.on('select', function () {
596 attachment = file_frame.state().get('selection').first().toJSON();
597 self.prev('.wpsa-url').val(attachment.url).change();
598 });
599 // Finally, open the modal
600 file_frame.open();
601 });
602 });
603 </script>
604 <?php
605 }
606
607 function _style_fix() {
608 global $wp_version;
609 ?>
610 <style type="text/css">
611 <?php if (version_compare($wp_version, '3.8', '<=')):?>
612 /** WordPress 3.8 Fix **/
613 .form-table th {
614 padding: 20px 10px;
615 }
616
617 <?php endif; ?>
618 .ever-settings *, .ever-settings *::before, .ever-settings *::after {
619 box-sizing: border-box;
620 }
621
622 .ever-settings {
623 margin: 16px 0;
624 }
625
626 .ever-settings.d-flex {
627 display: -ms-flexbox !important;
628 display: flex !important;
629 }
630
631 .ever-settings-sidebar {
632 position: relative;
633 z-index: 1;
634 min-width: 185px;
635 background-color: #eaeaea;
636 border-bottom: 1px solid #cccccc;
637 border-left: 1px solid #cccccc;
638 }
639
640 .ever-settings-sidebar > ul {
641 margin: 0;
642 /*overflow: hidden;*/
643 }
644
645 .ever-settings-sidebar > ul > li {
646 margin: 0;
647 /*overflow: hidden;*/
648 }
649
650 .ever-settings-sidebar > ul > li:first-child a {
651 border-top-color: #cccccc;
652 }
653
654 .ever-settings-sidebar > ul > li a {
655 display: block;
656 padding: 0 20px;
657 margin: 0 -1px 0 0;
658 overflow: hidden;
659 font-size: 13px;
660 font-weight: 700;
661 line-height: 3;
662 color: #777;
663 text-decoration: none;
664 text-overflow: ellipsis;
665 white-space: nowrap;
666 border-top: 1px solid #f7f5f5;
667 border-bottom: 1px solid #cccccc;
668 width: 100%;
669 border-right: 0;
670 border-left: 0;
671 box-shadow: none !important;
672 }
673
674 .ever-settings-sidebar > ul > li.active a {
675 color: #23282d;
676 background-color: #fff;
677 border-right: 1px solid #fff !important;
678 }
679
680 .ever-settings-content {
681 position: relative;
682 width: 100%;
683 padding: 10px 20px;
684 background-color: #fff;
685 border: 1px solid #cccccc;
686 min-height: 500px;
687 }
688
689 .ever-settings-content h2 {
690 padding-bottom: 16px;
691 margin: 8px 0 16px;
692 font-size: 18px;
693 font-weight: 300;
694 border-bottom: 1px solid #cccccc;
695
696 }
697
698 </style>
699 <?php
700 }
701 }
702endif;