PluginProbe
StreamCast – bring live radio to your site with a sleek player / 2.4.0
StreamCast – bring live radio to your site with a sleek player v2.4.0
2.4.5 2.4.4 trunk 1.0 1.1 2.0.0 2.1.10 2.1.2 2.1.4 2.1.5 2.1.8 2.2.1 2.2.3 2.2.4 2.2.5 2.3.0 2.3.1 2.3.2 2.3.3 2.3.4 2.3.5 2.3.6 2.3.7 2.3.8 2.3.9 All 29 releases
← All changes | frameworks/codestar-framework/classes/admin-options.class.php +665 -665 2.3.42.4.0 View file →
@@ -1,665 +1,665 @@
1 -<?php if ( ! defined( 'ABSPATH' ) ) { die; } // Cannot access directly.
2 -/**
3 - *
4 - * Options Class
5 - *
6 - * @since 1.0.0
7 - * @version 1.0.0
8 - *
9 - */
10 -if ( ! class_exists( 'CSF_Options' ) ) {
11 - class CSF_Options extends CSF_Abstract {
12 -
13 - // constans
14 - public $unique = '';
15 - public $notice = '';
16 - public $abstract = 'options';
17 - public $sections = array();
18 - public $options = array();
19 - public $errors = array();
20 - public $pre_tabs = array();
21 - public $pre_fields = array();
22 - public $pre_sections = array();
23 - public $args = array(
24 -
25 - // framework title
26 - 'framework_title' => 'Codestar Framework <small>by Codestar</small>',
27 - 'framework_class' => '',
28 -
29 - // menu settings
30 - 'menu_title' => '',
31 - 'menu_slug' => '',
32 - 'menu_type' => 'menu',
33 - 'menu_capability' => 'manage_options',
34 - 'menu_icon' => null,
35 - 'menu_position' => null,
36 - 'menu_hidden' => false,
37 - 'menu_parent' => '',
38 - 'sub_menu_title' => '',
39 -
40 - // menu extras
41 - 'show_bar_menu' => true,
42 - 'show_sub_menu' => true,
43 - 'show_in_network' => true,
44 - 'show_in_customizer' => false,
45 -
46 - 'show_search' => true,
47 - 'show_reset_all' => true,
48 - 'show_reset_section' => true,
49 - 'show_footer' => true,
50 - 'show_all_options' => true,
51 - 'show_form_warning' => true,
52 - 'sticky_header' => true,
53 - 'save_defaults' => true,
54 - 'ajax_save' => true,
55 - 'form_action' => '',
56 -
57 - // admin bar menu settings
58 - 'admin_bar_menu_icon' => '',
59 - 'admin_bar_menu_priority' => 50,
60 -
61 - // footer
62 - 'footer_text' => 'Thank you for creating with Codestar Framework',
63 - 'footer_after' => '',
64 - 'footer_credit' => '',
65 -
66 - // database model
67 - 'database' => '', // options, transient, theme_mod, network
68 - 'transient_time' => 0,
69 -
70 - // contextual help
71 - 'contextual_help' => array(),
72 - 'contextual_help_sidebar' => '',
73 -
74 - // typography options
75 - 'enqueue_webfont' => true,
76 - 'async_webfont' => false,
77 -
78 - // others
79 - 'output_css' => true,
80 -
81 - // theme
82 - 'nav' => 'normal',
83 - 'theme' => 'dark',
84 - 'class' => '',
85 -
86 - // external default values
87 - 'defaults' => array(),
88 -
89 - );
90 -
91 - // run framework construct
92 - public function __construct( $key, $params = array() ) {
93 -
94 - $this->unique = $key;
95 - $this->args = apply_filters( "csf_{$this->unique}_args", wp_parse_args( $params['args'], $this->args ), $this );
96 - $this->sections = apply_filters( "csf_{$this->unique}_sections", $params['sections'], $this );
97 -
98 - // run only is admin panel options, avoid performance loss
99 - $this->pre_tabs = $this->pre_tabs( $this->sections );
100 - $this->pre_fields = $this->pre_fields( $this->sections );
101 - $this->pre_sections = $this->pre_sections( $this->sections );
102 -
103 - $this->get_options();
104 - $this->set_options();
105 - $this->save_defaults();
106 -
107 - add_action( 'admin_menu', array( $this, 'add_admin_menu' ) );
108 - add_action( 'admin_bar_menu', array( $this, 'add_admin_bar_menu' ), $this->args['admin_bar_menu_priority'] );
109 - add_action( 'wp_ajax_csf_'. $this->unique .'_ajax_save', array( $this, 'ajax_save' ) );
110 -
111 - if ( $this->args['database'] === 'network' && ! empty( $this->args['show_in_network'] ) ) {
112 - add_action( 'network_admin_menu', array( $this, 'add_admin_menu' ) );
113 - }
114 -
115 - // wp enqeueu for typography and output css
116 - parent::__construct();
117 -
118 - }
119 -
120 - // instance
121 - public static function instance( $key, $params = array() ) {
122 - return new self( $key, $params );
123 - }
124 -
125 - // add admin bar menu
126 - public function add_admin_bar_menu( $wp_admin_bar ) {
127 -
128 - if ( ! current_user_can( $this->args['menu_capability'] ) ) {
129 - return;
130 - }
131 -
132 - if ( is_network_admin() && ( $this->args['database'] !== 'network' || $this->args['show_in_network'] !== true ) ) {
133 - return;
134 - }
135 -
136 - if ( ! empty( $this->args['show_bar_menu'] ) && empty( $this->args['menu_hidden'] ) ) {
137 -
138 - global $submenu;
139 -
140 - $menu_slug = $this->args['menu_slug'];
141 - $menu_icon = ( ! empty( $this->args['admin_bar_menu_icon'] ) ) ? '<span class="csf-ab-icon ab-icon '. esc_attr( $this->args['admin_bar_menu_icon'] ) .'"></span>' : '';
142 -
143 - $wp_admin_bar->add_node( array(
144 - 'id' => $menu_slug,
145 - 'title' => $menu_icon . esc_attr( $this->args['menu_title'] ),
146 - 'href' => esc_url( ( is_network_admin() ) ? network_admin_url( 'admin.php?page='. $menu_slug ) : admin_url( 'admin.php?page='. $menu_slug ) ),
147 - ) );
148 -
149 - if ( ! empty( $submenu[$menu_slug] ) ) {
150 - foreach ( $submenu[$menu_slug] as $menu_key => $menu_value ) {
151 - $wp_admin_bar->add_node( array(
152 - 'parent' => $menu_slug,
153 - 'id' => $menu_slug .'-'. $menu_key,
154 - 'title' => $menu_value[0],
155 - 'href' => esc_url( ( is_network_admin() ) ? network_admin_url( 'admin.php?page='. $menu_value[2] ) : admin_url( 'admin.php?page='. $menu_value[2] ) ),
156 - ) );
157 - }
158 - }
159 -
160 - }
161 -
162 - }
163 -
164 - public function ajax_save() {
165 -
166 - $result = $this->set_options( true );
167 -
168 - if ( ! $result ) {
169 - wp_send_json_error( array( 'error' => esc_html__( 'Error while saving the changes.', 'csf' ) ) );
170 - } else {
171 - wp_send_json_success( array( 'notice' => $this->notice, 'errors' => $this->errors ) );
172 - }
173 -
174 - }
175 -
176 - // get default value
177 - public function get_default( $field ) {
178 -
179 - $default = ( isset( $field['default'] ) ) ? $field['default'] : '';
180 - $default = ( isset( $this->args['defaults'][$field['id']] ) ) ? $this->args['defaults'][$field['id']] : $default;
181 -
182 - return $default;
183 -
184 - }
185 -
186 - // save defaults and set new fields value to main options
187 - public function save_defaults() {
188 -
189 - $tmp_options = $this->options;
190 -
191 - foreach ( $this->pre_fields as $field ) {
192 - if ( ! empty( $field['id'] ) ) {
193 - $this->options[$field['id']] = ( isset( $this->options[$field['id']] ) ) ? $this->options[$field['id']] : $this->get_default( $field );
194 - }
195 - }
196 -
197 - if ( $this->args['save_defaults'] && empty( $tmp_options ) ) {
198 - $this->save_options( $this->options );
199 - }
200 -
201 - }
202 -
203 - // set options
204 - public function set_options( $ajax = false ) {
205 -
206 - // XSS ok.
207 - // No worries, This "POST" requests is sanitizing in the below foreach. see #L337 - #L341
208 - $response = ( $ajax && ! empty( $_POST['data'] ) ) ? json_decode( wp_unslash( trim( $_POST['data'] ) ), true ) : $_POST;
209 -
210 - // Set variables.
211 - $data = array();
212 - $noncekey = 'csf_options_nonce'. $this->unique;
213 - $nonce = ( ! empty( $response[$noncekey] ) ) ? $response[$noncekey] : '';
214 - $options = ( ! empty( $response[$this->unique] ) ) ? $response[$this->unique] : array();
215 - $transient = ( ! empty( $response['csf_transient'] ) ) ? $response['csf_transient'] : array();
216 -
217 - if ( wp_verify_nonce( $nonce, 'csf_options_nonce' ) ) {
218 -
219 - $importing = false;
220 - $section_id = ( ! empty( $transient['section'] ) ) ? $transient['section'] : '';
221 -
222 - if ( ! $ajax && ! empty( $response[ 'csf_import_data' ] ) ) {
223 -
224 - // XSS ok.
225 - // No worries, This "POST" requests is sanitizing in the below foreach. see #L337 - #L341
226 - $import_data = json_decode( wp_unslash( trim( $response[ 'csf_import_data' ] ) ), true );
227 - $options = ( is_array( $import_data ) && ! empty( $import_data ) ) ? $import_data : array();
228 - $importing = true;
229 - $this->notice = esc_html__( 'Settings successfully imported.', 'csf' );
230 -
231 - }
232 -
233 - if ( ! empty( $transient['reset'] ) ) {
234 -
235 - foreach ( $this->pre_fields as $field ) {
236 - if ( ! empty( $field['id'] ) ) {
237 - $data[$field['id']] = $this->get_default( $field );
238 - }
239 - }
240 -
241 - $this->notice = esc_html__( 'Default settings restored.', 'csf' );
242 -
243 - } else if ( ! empty( $transient['reset_section'] ) && ! empty( $section_id ) ) {
244 -
245 - if ( ! empty( $this->pre_sections[$section_id-1]['fields'] ) ) {
246 -
247 - foreach ( $this->pre_sections[$section_id-1]['fields'] as $field ) {
248 - if ( ! empty( $field['id'] ) ) {
249 - $data[$field['id']] = $this->get_default( $field );
250 - }
251 - }
252 -
253 - }
254 -
255 - $data = wp_parse_args( $data, $this->options );
256 -
257 - $this->notice = esc_html__( 'Default settings restored.', 'csf' );
258 -
259 - } else {
260 -
261 - // sanitize and validate
262 - foreach ( $this->pre_fields as $field ) {
263 -
264 - if ( ! empty( $field['id'] ) ) {
265 -
266 - $field_id = $field['id'];
267 - $field_value = isset( $options[$field_id] ) ? $options[$field_id] : '';
268 -
269 - // Ajax and Importing doing wp_unslash already.
270 - if ( ! $ajax && ! $importing ) {
271 - $field_value = wp_unslash( $field_value );
272 - }
273 -
274 - // Sanitize "post" request of field.
275 - if ( ! isset( $field['sanitize'] ) ) {
276 -
277 - if( is_array( $field_value ) ) {
278 -
279 - $data[$field_id] = wp_kses_post_deep( $field_value );
280 -
281 - } else {
282 -
283 - $data[$field_id] = wp_kses_post( $field_value );
284 -
285 - }
286 -
287 - } else if( isset( $field['sanitize'] ) && is_callable( $field['sanitize'] ) ) {
288 -
289 - $data[$field_id] = call_user_func( $field['sanitize'], $field_value );
290 -
291 - } else {
292 -
293 - $data[$field_id] = $field_value;
294 -
295 - }
296 -
297 - // Validate "post" request of field.
298 - if ( isset( $field['validate'] ) && is_callable( $field['validate'] ) ) {
299 -
300 - $has_validated = call_user_func( $field['validate'], $field_value );
301 -
302 - if ( ! empty( $has_validated ) ) {
303 -
304 - $data[$field_id] = ( isset( $this->options[$field_id] ) ) ? $this->options[$field_id] : '';
305 - $this->errors[$field_id] = $has_validated;
306 -
307 - }
308 -
309 - }
310 -
311 - }
312 -
313 - }
314 -
315 - }
316 -
317 - $data = apply_filters( "csf_{$this->unique}_save", $data, $this );
318 -
319 - do_action( "csf_{$this->unique}_save_before", $data, $this );
320 -
321 - $this->options = $data;
322 -
323 - $this->save_options( $data );
324 -
325 - do_action( "csf_{$this->unique}_save_after", $data, $this );
326 -
327 - if ( empty( $this->notice ) ) {
328 - $this->notice = esc_html__( 'Settings saved.', 'csf' );
329 - }
330 -
331 - return true;
332 -
333 - }
334 -
335 - return false;
336 -
337 - }
338 -
339 - // save options database
340 - public function save_options( $data ) {
341 -
342 - if ( $this->args['database'] === 'transient' ) {
343 - set_transient( $this->unique, $data, $this->args['transient_time'] );
344 - } else if ( $this->args['database'] === 'theme_mod' ) {
345 - set_theme_mod( $this->unique, $data );
346 - } else if ( $this->args['database'] === 'network' ) {
347 - update_site_option( $this->unique, $data );
348 - } else {
349 - update_option( $this->unique, $data );
350 - }
351 -
352 - do_action( "csf_{$this->unique}_saved", $data, $this );
353 -
354 - }
355 -
356 - // get options from database
357 - public function get_options() {
358 -
359 - if ( $this->args['database'] === 'transient' ) {
360 - $this->options = get_transient( $this->unique );
361 - } else if ( $this->args['database'] === 'theme_mod' ) {
362 - $this->options = get_theme_mod( $this->unique );
363 - } else if ( $this->args['database'] === 'network' ) {
364 - $this->options = get_site_option( $this->unique );
365 - } else {
366 - $this->options = get_option( $this->unique );
367 - }
368 -
369 - if ( empty( $this->options ) ) {
370 - $this->options = array();
371 - }
372 -
373 - return $this->options;
374 -
375 - }
376 -
377 - // admin menu
378 - public function add_admin_menu() {
379 -
380 - extract( $this->args );
381 -
382 - if ( $menu_type === 'submenu' ) {
383 -
384 - $menu_page = call_user_func( 'add_submenu_page', $menu_parent, esc_attr( $menu_title ), esc_attr( $menu_title ), $menu_capability, $menu_slug, array( $this, 'add_options_html' ) );
385 -
386 - } else {
387 -
388 - $menu_page = call_user_func( 'add_menu_page', esc_attr( $menu_title ), esc_attr( $menu_title ), $menu_capability, $menu_slug, array( $this, 'add_options_html' ), $menu_icon, $menu_position );
389 -
390 - if ( ! empty( $sub_menu_title ) ) {
391 - call_user_func( 'add_submenu_page', $menu_slug, esc_attr( $sub_menu_title ), esc_attr( $sub_menu_title ), $menu_capability, $menu_slug, array( $this, 'add_options_html' ) );
392 - }
393 -
394 - if ( ! empty( $this->args['show_sub_menu'] ) && count( $this->pre_tabs ) > 1 ) {
395 -
396 - // create submenus
397 - foreach ( $this->pre_tabs as $section ) {
398 - call_user_func( 'add_submenu_page', $menu_slug, esc_attr( $section['title'] ), esc_attr( $section['title'] ), $menu_capability, $menu_slug .'#tab='. sanitize_title( $section['title'] ), '__return_null' );
399 - }
400 -
401 - remove_submenu_page( $menu_slug, $menu_slug );
402 -
403 - }
404 -
405 - if ( ! empty( $menu_hidden ) ) {
406 - remove_menu_page( $menu_slug );
407 - }
408 -
409 - }
410 -
411 - add_action( 'load-'. $menu_page, array( $this, 'add_page_on_load' ) );
412 -
413 - }
414 -
415 - public function add_page_on_load() {
416 -
417 - if ( ! empty( $this->args['contextual_help'] ) ) {
418 -
419 - $screen = get_current_screen();
420 -
421 - foreach ( $this->args['contextual_help'] as $tab ) {
422 - $screen->add_help_tab( $tab );
423 - }
424 -
425 - if ( ! empty( $this->args['contextual_help_sidebar'] ) ) {
426 - $screen->set_help_sidebar( $this->args['contextual_help_sidebar'] );
427 - }
428 -
429 - }
430 -
431 - if ( ! empty( $this->args['footer_credit'] ) ) {
432 - add_filter( 'admin_footer_text', array( $this, 'add_admin_footer_text' ) );
433 - }
434 -
435 - }
436 -
437 - public function add_admin_footer_text() {
438 - echo wp_kses_post( $this->args['footer_credit'] );
439 - }
440 -
441 - public function error_check( $sections, $err = '' ) {
442 -
443 - if ( ! $this->args['ajax_save'] ) {
444 -
445 - if ( ! empty( $sections['fields'] ) ) {
446 - foreach ( $sections['fields'] as $field ) {
447 - if ( ! empty( $field['id'] ) ) {
448 - if ( array_key_exists( $field['id'], $this->errors ) ) {
449 - $err = '<span class="csf-label-error">!</span>';
450 - }
451 - }
452 - }
453 - }
454 -
455 - if ( ! empty( $sections['subs'] ) ) {
456 - foreach ( $sections['subs'] as $sub ) {
457 - $err = $this->error_check( $sub, $err );
458 - }
459 - }
460 -
461 - if ( ! empty( $sections['id'] ) && array_key_exists( $sections['id'], $this->errors ) ) {
462 - $err = $this->errors[$sections['id']];
463 - }
464 -
465 - }
466 -
467 - return $err;
468 - }
469 -
470 - // option page html output
471 - public function add_options_html() {
472 -
473 - $has_nav = ( count( $this->pre_tabs ) > 1 ) ? true : false;
474 - $show_all = ( ! $has_nav ) ? ' csf-show-all' : '';
475 - $ajax_class = ( $this->args['ajax_save'] ) ? ' csf-save-ajax' : '';
476 - $sticky_class = ( $this->args['sticky_header'] ) ? ' csf-sticky-header' : '';
477 - $wrapper_class = ( $this->args['framework_class'] ) ? ' '. $this->args['framework_class'] : '';
478 - $theme = ( $this->args['theme'] ) ? ' csf-theme-'. $this->args['theme'] : '';
479 - $class = ( $this->args['class'] ) ? ' '. $this->args['class'] : '';
480 - $nav_type = ( $this->args['nav'] === 'inline' ) ? 'inline' : 'normal';
481 - $form_action = ( $this->args['form_action'] ) ? $this->args['form_action'] : '';
482 -
483 - do_action( 'csf_options_before' );
484 -
485 - echo '<div class="csf csf-options'. esc_attr( $theme . $class . $wrapper_class ) .'" data-slug="'. esc_attr( $this->args['menu_slug'] ) .'" data-unique="'. esc_attr( $this->unique ) .'">';
486 -
487 - echo '<div class="csf-container">';
488 -
489 - echo '<form method="post" action="'. esc_attr( $form_action ) .'" enctype="multipart/form-data" id="csf-form" autocomplete="off" novalidate="novalidate">';
490 -
491 - echo '<input type="hidden" class="csf-section-id" name="csf_transient[section]" value="1">';
492 -
493 - wp_nonce_field( 'csf_options_nonce', 'csf_options_nonce'. $this->unique );
494 -
495 - echo '<div class="csf-header'. esc_attr( $sticky_class ) .'">';
496 - echo '<div class="csf-header-inner">';
497 -
498 - echo '<div class="csf-header-left">';
499 - echo '<h1>'. $this->args['framework_title'] .'</h1>';
500 - echo '</div>';
501 -
502 - echo '<div class="csf-header-right">';
503 -
504 - $notice_class = ( ! empty( $this->notice ) ) ? 'csf-form-show' : '';
505 - $notice_text = ( ! empty( $this->notice ) ) ? $this->notice : '';
506 -
507 - echo '<div class="csf-form-result csf-form-success '. esc_attr( $notice_class ) .'">'. $notice_text .'</div>';
508 -
509 - echo ( $this->args['show_form_warning'] ) ? '<div class="csf-form-result csf-form-warning">'. esc_html__( 'You have unsaved changes, save your changes!', 'csf' ) .'</div>' : '';
510 -
511 - echo ( $has_nav && $this->args['show_all_options'] ) ? '<div class="csf-expand-all" title="'. esc_html__( 'show all settings', 'csf' ) .'"><i class="fas fa-outdent"></i></div>' : '';
512 -
513 - echo ( $this->args['show_search'] ) ? '<div class="csf-search"><input type="text" name="csf-search" placeholder="'. esc_html__( 'Search...', 'csf' ) .'" autocomplete="off" /></div>' : '';
514 -
515 - echo '<div class="csf-buttons">';
516 - echo '<input type="submit" name="'. esc_attr( $this->unique ) .'[_nonce][save]" class="button button-primary csf-top-save csf-save'. esc_attr( $ajax_class ) .'" value="'. esc_html__( 'Save', 'csf' ) .'" data-save="'. esc_html__( 'Saving...', 'csf' ) .'">';
517 - echo ( $this->args['show_reset_section'] ) ? '<input type="submit" name="csf_transient[reset_section]" class="button button-secondary csf-reset-section csf-confirm" value="'. esc_html__( 'Reset Section', 'csf' ) .'" data-confirm="'. esc_html__( 'Are you sure to reset this section options?', 'csf' ) .'">' : '';
518 - echo ( $this->args['show_reset_all'] ) ? '<input type="submit" name="csf_transient[reset]" class="button csf-warning-primary csf-reset-all csf-confirm" value="'. ( ( $this->args['show_reset_section'] ) ? esc_html__( 'Reset All', 'csf' ) : esc_html__( 'Reset', 'csf' ) ) .'" data-confirm="'. esc_html__( 'Are you sure you want to reset all settings to default values?', 'csf' ) .'">' : '';
519 - echo '</div>';
520 -
521 - echo '</div>';
522 -
523 - echo '<div class="clear"></div>';
524 - echo '</div>';
525 - echo '</div>';
526 -
527 - echo '<div class="csf-wrapper'. esc_attr( $show_all ) .'">';
528 -
529 - if ( $has_nav ) {
530 -
531 - echo '<div class="csf-nav csf-nav-'. esc_attr( $nav_type ) .' csf-nav-options">';
532 -
533 - echo '<ul>';
534 -
535 - foreach ( $this->pre_tabs as $tab ) {
536 -
537 - $tab_id = sanitize_title( $tab['title'] );
538 - $tab_error = $this->error_check( $tab );
539 - $tab_icon = ( ! empty( $tab['icon'] ) ) ? '<i class="csf-tab-icon '. esc_attr( $tab['icon'] ) .'"></i>' : '';
540 -
541 - if ( ! empty( $tab['subs'] ) ) {
542 -
543 - echo '<li class="csf-tab-item">';
544 -
545 - echo '<a href="#tab='. esc_attr( $tab_id ) .'" data-tab-id="'. esc_attr( $tab_id ) .'" class="csf-arrow">'. $tab_icon . $tab['title'] . $tab_error .'</a>';
546 -
547 - echo '<ul>';
548 -
549 - foreach ( $tab['subs'] as $sub ) {
550 -
551 - $sub_id = $tab_id .'/'. sanitize_title( $sub['title'] );
552 - $sub_error = $this->error_check( $sub );
553 - $sub_icon = ( ! empty( $sub['icon'] ) ) ? '<i class="csf-tab-icon '. esc_attr( $sub['icon'] ) .'"></i>' : '';
554 -
555 - echo '<li><a href="#tab='. esc_attr( $sub_id ) .'" data-tab-id="'. esc_attr( $sub_id ) .'">'. $sub_icon . $sub['title'] . $sub_error .'</a></li>';
556 -
557 - }
558 -
559 - echo '</ul>';
560 -
561 - echo '</li>';
562 -
563 - } else {
564 -
565 - echo '<li class="csf-tab-item"><a href="#tab='. esc_attr( $tab_id ) .'" data-tab-id="'. esc_attr( $tab_id ) .'">'. $tab_icon . $tab['title'] . $tab_error .'</a></li>';
566 -
567 - }
568 -
569 - }
570 -
571 - echo '</ul>';
572 -
573 - echo '</div>';
574 -
575 - }
576 -
577 - echo '<div class="csf-content">';
578 -
579 - echo '<div class="csf-sections">';
580 -
581 - foreach ( $this->pre_sections as $section ) {
582 -
583 - $section_onload = ( ! $has_nav ) ? ' csf-onload' : '';
584 - $section_class = ( ! empty( $section['class'] ) ) ? ' '. $section['class'] : '';
585 - $section_icon = ( ! empty( $section['icon'] ) ) ? '<i class="csf-section-icon '. esc_attr( $section['icon'] ) .'"></i>' : '';
586 - $section_title = ( ! empty( $section['title'] ) ) ? $section['title'] : '';
587 - $section_parent = ( ! empty( $section['ptitle'] ) ) ? sanitize_title( $section['ptitle'] ) .'/' : '';
588 - $section_slug = ( ! empty( $section['title'] ) ) ? sanitize_title( $section_title ) : '';
589 -
590 - echo '<div class="csf-section hidden'. esc_attr( $section_onload . $section_class ) .'" data-section-id="'. esc_attr( $section_parent . $section_slug ) .'">';
591 - echo ( $has_nav ) ? '<div class="csf-section-title"><h3>'. $section_icon . $section_title .'</h3></div>' : '';
592 - echo ( ! empty( $section['description'] ) ) ? '<div class="csf-field csf-section-description">'. $section['description'] .'</div>' : '';
593 -
594 - if ( ! empty( $section['fields'] ) ) {
595 -
596 - foreach ( $section['fields'] as $field ) {
597 -
598 - $is_field_error = $this->error_check( $field );
599 -
600 - if ( ! empty( $is_field_error ) ) {
601 - $field['_error'] = $is_field_error;
602 - }
603 -
604 - if ( ! empty( $field['id'] ) ) {
605 - $field['default'] = $this->get_default( $field );
606 - }
607 -
608 - $value = ( ! empty( $field['id'] ) && isset( $this->options[$field['id']] ) ) ? $this->options[$field['id']] : '';
609 -
610 - CSF::field( $field, $value, $this->unique, 'options' );
611 -
612 - }
613 -
614 - } else {
615 -
616 - echo '<div class="csf-no-option">'. esc_html__( 'No data available.', 'csf' ) .'</div>';
617 -
618 - }
619 -
620 - echo '</div>';
621 -
622 - }
623 -
624 - echo '</div>';
625 -
626 - echo '<div class="clear"></div>';
627 -
628 - echo '</div>';
629 -
630 - echo ( $has_nav && $nav_type === 'normal' ) ? '<div class="csf-nav-background"></div>' : '';
631 -
632 - echo '</div>';
633 -
634 - if ( ! empty( $this->args['show_footer'] ) ) {
635 -
636 - echo '<div class="csf-footer">';
637 -
638 - echo '<div class="csf-buttons">';
639 - echo '<input type="submit" name="csf_transient[save]" class="button button-primary csf-save'. esc_attr( $ajax_class ) .'" value="'. esc_html__( 'Save', 'csf' ) .'" data-save="'. esc_html__( 'Saving...', 'csf' ) .'">';
640 - echo ( $this->args['show_reset_section'] ) ? '<input type="submit" name="csf_transient[reset_section]" class="button button-secondary csf-reset-section csf-confirm" value="'. esc_html__( 'Reset Section', 'csf' ) .'" data-confirm="'. esc_html__( 'Are you sure to reset this section options?', 'csf' ) .'">' : '';
641 - echo ( $this->args['show_reset_all'] ) ? '<input type="submit" name="csf_transient[reset]" class="button csf-warning-primary csf-reset-all csf-confirm" value="'. ( ( $this->args['show_reset_section'] ) ? esc_html__( 'Reset All', 'csf' ) : esc_html__( 'Reset', 'csf' ) ) .'" data-confirm="'. esc_html__( 'Are you sure you want to reset all settings to default values?', 'csf' ) .'">' : '';
642 - echo '</div>';
643 -
644 - echo ( ! empty( $this->args['footer_text'] ) ) ? '<div class="csf-copyright">'. $this->args['footer_text'] .'</div>' : '';
645 -
646 - echo '<div class="clear"></div>';
647 - echo '</div>';
648 -
649 - }
650 -
651 - echo '</form>';
652 -
653 - echo '</div>';
654 -
655 - echo '<div class="clear"></div>';
656 -
657 - echo ( ! empty( $this->args['footer_after'] ) ) ? $this->args['footer_after'] : '';
658 -
659 - echo '</div>';
660 -
661 - do_action( 'csf_options_after' );
662 -
663 - }
664 - }
665 -}
1 +<?php if ( ! defined( 'ABSPATH' ) ) { die; } // Cannot access directly.
2 +/**
3 + *
4 + * Options Class
5 + *
6 + * @since 1.0.0
7 + * @version 1.0.0
8 + *
9 + */
10 +if ( ! class_exists( 'CSF_Options' ) ) {
11 + class CSF_Options extends CSF_Abstract {
12 +
13 + // constans
14 + public $unique = '';
15 + public $notice = '';
16 + public $abstract = 'options';
17 + public $sections = array();
18 + public $options = array();
19 + public $errors = array();
20 + public $pre_tabs = array();
21 + public $pre_fields = array();
22 + public $pre_sections = array();
23 + public $args = array(
24 +
25 + // framework title
26 + 'framework_title' => 'Codestar Framework <small>by Codestar</small>',
27 + 'framework_class' => '',
28 +
29 + // menu settings
30 + 'menu_title' => '',
31 + 'menu_slug' => '',
32 + 'menu_type' => 'menu',
33 + 'menu_capability' => 'manage_options',
34 + 'menu_icon' => null,
35 + 'menu_position' => null,
36 + 'menu_hidden' => false,
37 + 'menu_parent' => '',
38 + 'sub_menu_title' => '',
39 +
40 + // menu extras
41 + 'show_bar_menu' => true,
42 + 'show_sub_menu' => true,
43 + 'show_in_network' => true,
44 + 'show_in_customizer' => false,
45 +
46 + 'show_search' => true,
47 + 'show_reset_all' => true,
48 + 'show_reset_section' => true,
49 + 'show_footer' => true,
50 + 'show_all_options' => true,
51 + 'show_form_warning' => true,
52 + 'sticky_header' => true,
53 + 'save_defaults' => true,
54 + 'ajax_save' => true,
55 + 'form_action' => '',
56 +
57 + // admin bar menu settings
58 + 'admin_bar_menu_icon' => '',
59 + 'admin_bar_menu_priority' => 50,
60 +
61 + // footer
62 + 'footer_text' => 'Thank you for creating with Codestar Framework',
63 + 'footer_after' => '',
64 + 'footer_credit' => '',
65 +
66 + // database model
67 + 'database' => '', // options, transient, theme_mod, network
68 + 'transient_time' => 0,
69 +
70 + // contextual help
71 + 'contextual_help' => array(),
72 + 'contextual_help_sidebar' => '',
73 +
74 + // typography options
75 + 'enqueue_webfont' => true,
76 + 'async_webfont' => false,
77 +
78 + // others
79 + 'output_css' => true,
80 +
81 + // theme
82 + 'nav' => 'normal',
83 + 'theme' => 'dark',
84 + 'class' => '',
85 +
86 + // external default values
87 + 'defaults' => array(),
88 +
89 + );
90 +
91 + // run framework construct
92 + public function __construct( $key, $params = array() ) {
93 +
94 + $this->unique = $key;
95 + $this->args = apply_filters( "csf_{$this->unique}_args", wp_parse_args( $params['args'], $this->args ), $this );
96 + $this->sections = apply_filters( "csf_{$this->unique}_sections", $params['sections'], $this );
97 +
98 + // run only is admin panel options, avoid performance loss
99 + $this->pre_tabs = $this->pre_tabs( $this->sections );
100 + $this->pre_fields = $this->pre_fields( $this->sections );
101 + $this->pre_sections = $this->pre_sections( $this->sections );
102 +
103 + $this->get_options();
104 + $this->set_options();
105 + $this->save_defaults();
106 +
107 + add_action( 'admin_menu', array( $this, 'add_admin_menu' ) );
108 + add_action( 'admin_bar_menu', array( $this, 'add_admin_bar_menu' ), $this->args['admin_bar_menu_priority'] );
109 + add_action( 'wp_ajax_csf_'. $this->unique .'_ajax_save', array( $this, 'ajax_save' ) );
110 +
111 + if ( $this->args['database'] === 'network' && ! empty( $this->args['show_in_network'] ) ) {
112 + add_action( 'network_admin_menu', array( $this, 'add_admin_menu' ) );
113 + }
114 +
115 + // wp enqeueu for typography and output css
116 + parent::__construct();
117 +
118 + }
119 +
120 + // instance
121 + public static function instance( $key, $params = array() ) {
122 + return new self( $key, $params );
123 + }
124 +
125 + // add admin bar menu
126 + public function add_admin_bar_menu( $wp_admin_bar ) {
127 +
128 + if ( ! current_user_can( $this->args['menu_capability'] ) ) {
129 + return;
130 + }
131 +
132 + if ( is_network_admin() && ( $this->args['database'] !== 'network' || $this->args['show_in_network'] !== true ) ) {
133 + return;
134 + }
135 +
136 + if ( ! empty( $this->args['show_bar_menu'] ) && empty( $this->args['menu_hidden'] ) ) {
137 +
138 + global $submenu;
139 +
140 + $menu_slug = $this->args['menu_slug'];
141 + $menu_icon = ( ! empty( $this->args['admin_bar_menu_icon'] ) ) ? '<span class="csf-ab-icon ab-icon '. esc_attr( $this->args['admin_bar_menu_icon'] ) .'"></span>' : '';
142 +
143 + $wp_admin_bar->add_node( array(
144 + 'id' => $menu_slug,
145 + 'title' => $menu_icon . esc_attr( $this->args['menu_title'] ),
146 + 'href' => esc_url( ( is_network_admin() ) ? network_admin_url( 'admin.php?page='. $menu_slug ) : admin_url( 'admin.php?page='. $menu_slug ) ),
147 + ) );
148 +
149 + if ( ! empty( $submenu[$menu_slug] ) ) {
150 + foreach ( $submenu[$menu_slug] as $menu_key => $menu_value ) {
151 + $wp_admin_bar->add_node( array(
152 + 'parent' => $menu_slug,
153 + 'id' => $menu_slug .'-'. $menu_key,
154 + 'title' => $menu_value[0],
155 + 'href' => esc_url( ( is_network_admin() ) ? network_admin_url( 'admin.php?page='. $menu_value[2] ) : admin_url( 'admin.php?page='. $menu_value[2] ) ),
156 + ) );
157 + }
158 + }
159 +
160 + }
161 +
162 + }
163 +
164 + public function ajax_save() {
165 +
166 + $result = $this->set_options( true );
167 +
168 + if ( ! $result ) {
169 + wp_send_json_error( array( 'error' => esc_html__( 'Error while saving the changes.', 'streamcast' ) ) );
170 + } else {
171 + wp_send_json_success( array( 'notice' => $this->notice, 'errors' => $this->errors ) );
172 + }
173 +
174 + }
175 +
176 + // get default value
177 + public function get_default( $field ) {
178 +
179 + $default = ( isset( $field['default'] ) ) ? $field['default'] : '';
180 + $default = ( isset( $this->args['defaults'][$field['id']] ) ) ? $this->args['defaults'][$field['id']] : $default;
181 +
182 + return $default;
183 +
184 + }
185 +
186 + // save defaults and set new fields value to main options
187 + public function save_defaults() {
188 +
189 + $tmp_options = $this->options;
190 +
191 + foreach ( $this->pre_fields as $field ) {
192 + if ( ! empty( $field['id'] ) ) {
193 + $this->options[$field['id']] = ( isset( $this->options[$field['id']] ) ) ? $this->options[$field['id']] : $this->get_default( $field );
194 + }
195 + }
196 +
197 + if ( $this->args['save_defaults'] && empty( $tmp_options ) ) {
198 + $this->save_options( $this->options );
199 + }
200 +
201 + }
202 +
203 + // set options
204 + public function set_options( $ajax = false ) {
205 +
206 + // XSS ok.
207 + // No worries, This "POST" requests is sanitizing in the below foreach. see #L337 - #L341
208 + $response = ( $ajax && ! empty( $_POST['data'] ) ) ? json_decode( wp_unslash( trim( $_POST['data'] ) ), true ) : $_POST; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
209 +
210 + // Set variables.
211 + $data = array();
212 + $noncekey = 'csf_options_nonce'. $this->unique;
213 + $nonce = ( ! empty( $response[$noncekey] ) ) ? $response[$noncekey] : '';
214 + $options = ( ! empty( $response[$this->unique] ) ) ? $response[$this->unique] : array();
215 + $transient = ( ! empty( $response['csf_transient'] ) ) ? $response['csf_transient'] : array();
216 +
217 + if ( wp_verify_nonce( $nonce, 'csf_options_nonce' ) ) {
218 +
219 + $importing = false;
220 + $section_id = ( ! empty( $transient['section'] ) ) ? $transient['section'] : '';
221 +
222 + if ( ! $ajax && ! empty( $response[ 'csf_import_data' ] ) ) {
223 +
224 + // XSS ok.
225 + // No worries, This "POST" requests is sanitizing in the below foreach. see #L337 - #L341
226 + $import_data = json_decode( wp_unslash( trim( $response[ 'csf_import_data' ] ) ), true );
227 + $options = ( is_array( $import_data ) && ! empty( $import_data ) ) ? $import_data : array();
228 + $importing = true;
229 + $this->notice = esc_html__( 'Settings successfully imported.', 'streamcast' );
230 +
231 + }
232 +
233 + if ( ! empty( $transient['reset'] ) ) {
234 +
235 + foreach ( $this->pre_fields as $field ) {
236 + if ( ! empty( $field['id'] ) ) {
237 + $data[$field['id']] = $this->get_default( $field );
238 + }
239 + }
240 +
241 + $this->notice = esc_html__( 'Default settings restored.', 'streamcast' );
242 +
243 + } else if ( ! empty( $transient['reset_section'] ) && ! empty( $section_id ) ) {
244 +
245 + if ( ! empty( $this->pre_sections[$section_id-1]['fields'] ) ) {
246 +
247 + foreach ( $this->pre_sections[$section_id-1]['fields'] as $field ) {
248 + if ( ! empty( $field['id'] ) ) {
249 + $data[$field['id']] = $this->get_default( $field );
250 + }
251 + }
252 +
253 + }
254 +
255 + $data = wp_parse_args( $data, $this->options );
256 +
257 + $this->notice = esc_html__( 'Default settings restored.', 'streamcast' );
258 +
259 + } else {
260 +
261 + // sanitize and validate
262 + foreach ( $this->pre_fields as $field ) {
263 +
264 + if ( ! empty( $field['id'] ) ) {
265 +
266 + $field_id = $field['id'];
267 + $field_value = isset( $options[$field_id] ) ? $options[$field_id] : '';
268 +
269 + // Ajax and Importing doing wp_unslash already.
270 + if ( ! $ajax && ! $importing ) {
271 + $field_value = wp_unslash( $field_value );
272 + }
273 +
274 + // Sanitize "post" request of field.
275 + if ( ! isset( $field['sanitize'] ) ) {
276 +
277 + if( is_array( $field_value ) ) {
278 +
279 + $data[$field_id] = wp_kses_post_deep( $field_value );
280 +
281 + } else {
282 +
283 + $data[$field_id] = wp_kses_post( $field_value );
284 +
285 + }
286 +
287 + } else if( isset( $field['sanitize'] ) && is_callable( $field['sanitize'] ) ) {
288 +
289 + $data[$field_id] = call_user_func( $field['sanitize'], $field_value );
290 +
291 + } else {
292 +
293 + $data[$field_id] = $field_value;
294 +
295 + }
296 +
297 + // Validate "post" request of field.
298 + if ( isset( $field['validate'] ) && is_callable( $field['validate'] ) ) {
299 +
300 + $has_validated = call_user_func( $field['validate'], $field_value );
301 +
302 + if ( ! empty( $has_validated ) ) {
303 +
304 + $data[$field_id] = ( isset( $this->options[$field_id] ) ) ? $this->options[$field_id] : '';
305 + $this->errors[$field_id] = $has_validated;
306 +
307 + }
308 +
309 + }
310 +
311 + }
312 +
313 + }
314 +
315 + }
316 +
317 + $data = apply_filters( "csf_{$this->unique}_save", $data, $this );
318 +
319 + do_action( "csf_{$this->unique}_save_before", $data, $this );
320 +
321 + $this->options = $data;
322 +
323 + $this->save_options( $data );
324 +
325 + do_action( "csf_{$this->unique}_save_after", $data, $this );
326 +
327 + if ( empty( $this->notice ) ) {
328 + $this->notice = esc_html__( 'Settings saved.', 'streamcast' );
329 + }
330 +
331 + return true;
332 +
333 + }
334 +
335 + return false;
336 +
337 + }
338 +
339 + // save options database
340 + public function save_options( $data ) {
341 +
342 + if ( $this->args['database'] === 'transient' ) {
343 + set_transient( $this->unique, $data, $this->args['transient_time'] );
344 + } else if ( $this->args['database'] === 'theme_mod' ) {
345 + set_theme_mod( $this->unique, $data );
346 + } else if ( $this->args['database'] === 'network' ) {
347 + update_site_option( $this->unique, $data );
348 + } else {
349 + update_option( $this->unique, $data );
350 + }
351 +
352 + do_action( "csf_{$this->unique}_saved", $data, $this );
353 +
354 + }
355 +
356 + // get options from database
357 + public function get_options() {
358 +
359 + if ( $this->args['database'] === 'transient' ) {
360 + $this->options = get_transient( $this->unique );
361 + } else if ( $this->args['database'] === 'theme_mod' ) {
362 + $this->options = get_theme_mod( $this->unique );
363 + } else if ( $this->args['database'] === 'network' ) {
364 + $this->options = get_site_option( $this->unique );
365 + } else {
366 + $this->options = get_option( $this->unique );
367 + }
368 +
369 + if ( empty( $this->options ) ) {
370 + $this->options = array();
371 + }
372 +
373 + return $this->options;
374 +
375 + }
376 +
377 + // admin menu
378 + public function add_admin_menu() {
379 +
380 + extract( $this->args );
381 +
382 + if ( $menu_type === 'submenu' ) {
383 +
384 + $menu_page = call_user_func( 'add_submenu_page', $menu_parent, esc_attr( $menu_title ), esc_attr( $menu_title ), $menu_capability, $menu_slug, array( $this, 'add_options_html' ) );
385 +
386 + } else {
387 +
388 + $menu_page = call_user_func( 'add_menu_page', esc_attr( $menu_title ), esc_attr( $menu_title ), $menu_capability, $menu_slug, array( $this, 'add_options_html' ), $menu_icon, $menu_position );
389 +
390 + if ( ! empty( $sub_menu_title ) ) {
391 + call_user_func( 'add_submenu_page', $menu_slug, esc_attr( $sub_menu_title ), esc_attr( $sub_menu_title ), $menu_capability, $menu_slug, array( $this, 'add_options_html' ) );
392 + }
393 +
394 + if ( ! empty( $this->args['show_sub_menu'] ) && count( $this->pre_tabs ) > 1 ) {
395 +
396 + // create submenus
397 + foreach ( $this->pre_tabs as $section ) {
398 + call_user_func( 'add_submenu_page', $menu_slug, esc_attr( $section['title'] ), esc_attr( $section['title'] ), $menu_capability, $menu_slug .'#tab='. sanitize_title( $section['title'] ), '__return_null' );
399 + }
400 +
401 + remove_submenu_page( $menu_slug, $menu_slug );
402 +
403 + }
404 +
405 + if ( ! empty( $menu_hidden ) ) {
406 + remove_menu_page( $menu_slug );
407 + }
408 +
409 + }
410 +
411 + add_action( 'load-'. $menu_page, array( $this, 'add_page_on_load' ) );
412 +
413 + }
414 +
415 + public function add_page_on_load() {
416 +
417 + if ( ! empty( $this->args['contextual_help'] ) ) {
418 +
419 + $screen = get_current_screen();
420 +
421 + foreach ( $this->args['contextual_help'] as $tab ) {
422 + $screen->add_help_tab( $tab );
423 + }
424 +
425 + if ( ! empty( $this->args['contextual_help_sidebar'] ) ) {
426 + $screen->set_help_sidebar( $this->args['contextual_help_sidebar'] );
427 + }
428 +
429 + }
430 +
431 + if ( ! empty( $this->args['footer_credit'] ) ) {
432 + add_filter( 'admin_footer_text', array( $this, 'add_admin_footer_text' ) );
433 + }
434 +
435 + }
436 +
437 + public function add_admin_footer_text() {
438 + echo wp_kses_post( $this->args['footer_credit'] );
439 + }
440 +
441 + public function error_check( $sections, $err = '' ) {
442 +
443 + if ( ! $this->args['ajax_save'] ) {
444 +
445 + if ( ! empty( $sections['fields'] ) ) {
446 + foreach ( $sections['fields'] as $field ) {
447 + if ( ! empty( $field['id'] ) ) {
448 + if ( array_key_exists( $field['id'], $this->errors ) ) {
449 + $err = '<span class="csf-label-error">!</span>';
450 + }
451 + }
452 + }
453 + }
454 +
455 + if ( ! empty( $sections['subs'] ) ) {
456 + foreach ( $sections['subs'] as $sub ) {
457 + $err = $this->error_check( $sub, $err );
458 + }
459 + }
460 +
461 + if ( ! empty( $sections['id'] ) && array_key_exists( $sections['id'], $this->errors ) ) {
462 + $err = $this->errors[$sections['id']];
463 + }
464 +
465 + }
466 +
467 + return $err;
468 + }
469 +
470 + // option page html output
471 + public function add_options_html() {
472 +
473 + $has_nav = ( count( $this->pre_tabs ) > 1 ) ? true : false;
474 + $show_all = ( ! $has_nav ) ? ' csf-show-all' : '';
475 + $ajax_class = ( $this->args['ajax_save'] ) ? ' csf-save-ajax' : '';
476 + $sticky_class = ( $this->args['sticky_header'] ) ? ' csf-sticky-header' : '';
477 + $wrapper_class = ( $this->args['framework_class'] ) ? ' '. $this->args['framework_class'] : '';
478 + $theme = ( $this->args['theme'] ) ? ' csf-theme-'. $this->args['theme'] : '';
479 + $class = ( $this->args['class'] ) ? ' '. $this->args['class'] : '';
480 + $nav_type = ( $this->args['nav'] === 'inline' ) ? 'inline' : 'normal';
481 + $form_action = ( $this->args['form_action'] ) ? $this->args['form_action'] : '';
482 +
483 + do_action( 'csf_options_before' );
484 +
485 + echo '<div class="csf csf-options'. esc_attr( $theme . $class . $wrapper_class ) .'" data-slug="'. esc_attr( $this->args['menu_slug'] ) .'" data-unique="'. esc_attr( $this->unique ) .'">';
486 +
487 + echo '<div class="csf-container">';
488 +
489 + echo '<form method="post" action="'. esc_attr( $form_action ) .'" enctype="multipart/form-data" id="csf-form" autocomplete="off" novalidate="novalidate">';
490 +
491 + echo '<input type="hidden" class="csf-section-id" name="csf_transient[section]" value="1">';
492 +
493 + wp_nonce_field( 'csf_options_nonce', 'csf_options_nonce'. $this->unique );
494 +
495 + echo '<div class="csf-header'. esc_attr( $sticky_class ) .'">';
496 + echo '<div class="csf-header-inner">';
497 +
498 + echo '<div class="csf-header-left">';
499 + echo '<h1>'. wp_kses_post( $this->args['framework_title'] ) .'</h1>';
500 + echo '</div>';
501 +
502 + echo '<div class="csf-header-right">';
503 +
504 + $notice_class = ( ! empty( $this->notice ) ) ? 'csf-form-show' : '';
505 + $notice_text = ( ! empty( $this->notice ) ) ? $this->notice : '';
506 +
507 + echo '<div class="csf-form-result csf-form-success '. esc_attr( $notice_class ) .'">'. wp_kses_post( $notice_text ) .'</div>';
508 +
509 + echo ( $this->args['show_form_warning'] ) ? '<div class="csf-form-result csf-form-warning">'. esc_html__( 'You have unsaved changes, save your changes!', 'streamcast' ) .'</div>' : '';
510 +
511 + echo ( $has_nav && $this->args['show_all_options'] ) ? '<div class="csf-expand-all" title="'. esc_html__( 'show all settings', 'streamcast' ) .'"><i class="fas fa-outdent"></i></div>' : '';
512 +
513 + echo ( $this->args['show_search'] ) ? '<div class="csf-search"><input type="text" name="csf-search" placeholder="'. esc_html__( 'Search...', 'streamcast' ) .'" autocomplete="off" /></div>' : '';
514 +
515 + echo '<div class="csf-buttons">';
516 + echo '<input type="submit" name="'. esc_attr( $this->unique ) .'[_nonce][save]" class="button button-primary csf-top-save csf-save'. esc_attr( $ajax_class ) .'" value="'. esc_html__( 'Save', 'streamcast' ) .'" data-save="'. esc_html__( 'Saving...', 'streamcast' ) .'">';
517 + echo ( $this->args['show_reset_section'] ) ? '<input type="submit" name="csf_transient[reset_section]" class="button button-secondary csf-reset-section csf-confirm" value="'. esc_html__( 'Reset Section', 'streamcast' ) .'" data-confirm="'. esc_html__( 'Are you sure to reset this section options?', 'streamcast' ) .'">' : '';
518 + echo ( $this->args['show_reset_all'] ) ? '<input type="submit" name="csf_transient[reset]" class="button csf-warning-primary csf-reset-all csf-confirm" value="'. ( ( $this->args['show_reset_section'] ) ? esc_html__( 'Reset All', 'streamcast' ) : esc_html__( 'Reset', 'streamcast' ) ) .'" data-confirm="'. esc_html__( 'Are you sure you want to reset all settings to default values?', 'streamcast' ) .'">' : '';
519 + echo '</div>';
520 +
521 + echo '</div>';
522 +
523 + echo '<div class="clear"></div>';
524 + echo '</div>';
525 + echo '</div>';
526 +
527 + echo '<div class="csf-wrapper'. esc_attr( $show_all ) .'">';
528 +
529 + if ( $has_nav ) {
530 +
531 + echo '<div class="csf-nav csf-nav-'. esc_attr( $nav_type ) .' csf-nav-options">';
532 +
533 + echo '<ul>';
534 +
535 + foreach ( $this->pre_tabs as $tab ) {
536 +
537 + $tab_id = sanitize_title( $tab['title'] );
538 + $tab_error = $this->error_check( $tab );
539 + $tab_icon = ( ! empty( $tab['icon'] ) ) ? '<i class="csf-tab-icon '. esc_attr( $tab['icon'] ) .'"></i>' : '';
540 +
541 + if ( ! empty( $tab['subs'] ) ) {
542 +
543 + echo '<li class="csf-tab-item">';
544 +
545 + echo '<a href="#tab='. esc_attr( $tab_id ) .'" data-tab-id="'. esc_attr( $tab_id ) .'" class="csf-arrow">'. wp_kses_post( $tab_icon ) . wp_kses_post( $tab['title'] ) . wp_kses_post( $tab_error ) .'</a>';
546 +
547 + echo '<ul>';
548 +
549 + foreach ( $tab['subs'] as $sub ) {
550 +
551 + $sub_id = $tab_id .'/'. sanitize_title( $sub['title'] );
552 + $sub_error = $this->error_check( $sub );
553 + $sub_icon = ( ! empty( $sub['icon'] ) ) ? '<i class="csf-tab-icon '. esc_attr( $sub['icon'] ) .'"></i>' : '';
554 +
555 + echo '<li><a href="#tab='. esc_attr( $sub_id ) .'" data-tab-id="'. esc_attr( $sub_id ) .'">'. wp_kses_post( $sub_icon ) . wp_kses_post( $sub['title'] ) . wp_kses_post( $sub_error ) .'</a></li>';
556 +
557 + }
558 +
559 + echo '</ul>';
560 +
561 + echo '</li>';
562 +
563 + } else {
564 +
565 + echo '<li class="csf-tab-item"><a href="#tab='. esc_attr( $tab_id ) .'" data-tab-id="'. esc_attr( $tab_id ) .'">'. wp_kses_post( $tab_icon ) . wp_kses_post( $tab['title'] ) . wp_kses_post( $tab_error ) .'</a></li>';
566 +
567 + }
568 +
569 + }
570 +
571 + echo '</ul>';
572 +
573 + echo '</div>';
574 +
575 + }
576 +
577 + echo '<div class="csf-content">';
578 +
579 + echo '<div class="csf-sections">';
580 +
581 + foreach ( $this->pre_sections as $section ) {
582 +
583 + $section_onload = ( ! $has_nav ) ? ' csf-onload' : '';
584 + $section_class = ( ! empty( $section['class'] ) ) ? ' '. $section['class'] : '';
585 + $section_icon = ( ! empty( $section['icon'] ) ) ? '<i class="csf-section-icon '. esc_attr( $section['icon'] ) .'"></i>' : '';
586 + $section_title = ( ! empty( $section['title'] ) ) ? $section['title'] : '';
587 + $section_parent = ( ! empty( $section['ptitle'] ) ) ? sanitize_title( $section['ptitle'] ) .'/' : '';
588 + $section_slug = ( ! empty( $section['title'] ) ) ? sanitize_title( $section_title ) : '';
589 +
590 + echo '<div class="csf-section hidden'. esc_attr( $section_onload . $section_class ) .'" data-section-id="'. esc_attr( $section_parent . $section_slug ) .'">';
591 + echo ( $has_nav ) ? '<div class="csf-section-title"><h3>'. wp_kses_post( $section_icon ) . wp_kses_post( $section_title ) .'</h3></div>' : '';
592 + echo ( ! empty( $section['description'] ) ) ? '<div class="csf-field csf-section-description">'. wp_kses_post( $section['description'] ) .'</div>' : '';
593 +
594 + if ( ! empty( $section['fields'] ) ) {
595 +
596 + foreach ( $section['fields'] as $field ) {
597 +
598 + $is_field_error = $this->error_check( $field );
599 +
600 + if ( ! empty( $is_field_error ) ) {
601 + $field['_error'] = $is_field_error;
602 + }
603 +
604 + if ( ! empty( $field['id'] ) ) {
605 + $field['default'] = $this->get_default( $field );
606 + }
607 +
608 + $value = ( ! empty( $field['id'] ) && isset( $this->options[$field['id']] ) ) ? $this->options[$field['id']] : '';
609 +
610 + CSF::field( $field, $value, $this->unique, 'options' );
611 +
612 + }
613 +
614 + } else {
615 +
616 + echo '<div class="csf-no-option">'. esc_html__( 'No data available.', 'streamcast' ) .'</div>';
617 +
618 + }
619 +
620 + echo '</div>';
621 +
622 + }
623 +
624 + echo '</div>';
625 +
626 + echo '<div class="clear"></div>';
627 +
628 + echo '</div>';
629 +
630 + echo ( $has_nav && $nav_type === 'normal' ) ? '<div class="csf-nav-background"></div>' : '';
631 +
632 + echo '</div>';
633 +
634 + if ( ! empty( $this->args['show_footer'] ) ) {
635 +
636 + echo '<div class="csf-footer">';
637 +
638 + echo '<div class="csf-buttons">';
639 + echo '<input type="submit" name="csf_transient[save]" class="button button-primary csf-save'. esc_attr( $ajax_class ) .'" value="'. esc_html__( 'Save', 'streamcast' ) .'" data-save="'. esc_html__( 'Saving...', 'streamcast' ) .'">';
640 + echo ( $this->args['show_reset_section'] ) ? '<input type="submit" name="csf_transient[reset_section]" class="button button-secondary csf-reset-section csf-confirm" value="'. esc_html__( 'Reset Section', 'streamcast' ) .'" data-confirm="'. esc_html__( 'Are you sure to reset this section options?', 'streamcast' ) .'">' : '';
641 + echo ( $this->args['show_reset_all'] ) ? '<input type="submit" name="csf_transient[reset]" class="button csf-warning-primary csf-reset-all csf-confirm" value="'. ( ( $this->args['show_reset_section'] ) ? esc_html__( 'Reset All', 'streamcast' ) : esc_html__( 'Reset', 'streamcast' ) ) .'" data-confirm="'. esc_html__( 'Are you sure you want to reset all settings to default values?', 'streamcast' ) .'">' : '';
642 + echo '</div>';
643 +
644 + echo ( ! empty( $this->args['footer_text'] ) ) ? '<div class="csf-copyright">'. wp_kses_post( $this->args['footer_text'] ) .'</div>' : '';
645 +
646 + echo '<div class="clear"></div>';
647 + echo '</div>';
648 +
649 + }
650 +
651 + echo '</form>';
652 +
653 + echo '</div>';
654 +
655 + echo '<div class="clear"></div>';
656 +
657 + echo ( ! empty( $this->args['footer_after'] ) ) ? wp_kses_post( $this->args['footer_after'] ) : '';
658 +
659 + echo '</div>';
660 +
661 + do_action( 'csf_options_after' );
662 +
663 + }
664 + }
665 +}