PluginProbe
Bricksable for Bricks Builder / 1.3.0
Bricksable for Bricks Builder v1.3.0
1.2.9 1.3.0 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2 1.4.3 1.4.31 1.4.32 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 All 132 releases
bricksable / includes / class-bricksable-settings.php

class-bricksable-settings.php in Bricksable for Bricks Builder 1.3.0, at includes/class-bricksable-settings.php

746 lines 20.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Settings class file.
4 *
5 * @package Bricksable/Settings
6 */
7
8 if ( ! defined( 'ABSPATH' ) ) {
9 exit;
10 }
11
12 /**
13 * Settings class.
14 */
15 class Bricksable_Settings {
16
17 /**
18 * The single instance of Bricksable_Settings.
19 *
20 * @var object
21 * @access private
22 * @since 1.0.0
23 */
24 private static $instance = null;
25
26 /**
27 * The main plugin object.
28 *
29 * @var object
30 * @access public
31 * @since 1.0.0
32 */
33 public $parent = null;
34
35 /**
36 * Prefix for plugin settings.
37 *
38 * @var string
39 * @access public
40 * @since 1.0.0
41 */
42 public $base = '';
43
44 /**
45 * Available settings for plugin.
46 *
47 * @var array
48 * @access public
49 * @since 1.0.0
50 */
51 public $settings = array();
52
53 /**
54 * Constructor function.
55 *
56 * @param object $parent Parent object.
57 */
58 public function __construct( $parent ) {
59 $this->parent = $parent;
60
61 $this->base = 'bricksable_';
62 // Check if Bricks Builder is installed.
63 if ( 'bricks' !== wp_get_theme()->get( 'Template' ) ) {
64 if ( 'Bricks' !== wp_get_theme()->get( 'Name' ) ) {
65 add_action(
66 'admin_notices',
67 function() {
68 $message = sprintf(
69 /* translators: 1: Theme name 2: Bricksable */
70 esc_html__( '%1$s requires %2$s to be installed and activated', 'bricksable' ),
71 '<strong>Bricksable</strong>',
72 '<strong>Bricks Builder</strong>'
73 );
74 $html = sprintf( '<div class="notice notice-warning">%s</div>', wpautop( $message ) );
75 echo wp_kses_post( $html );
76 }
77 );
78 return;
79 }
80 }
81
82 // Initialise settings.
83 add_action( 'init', array( $this, 'init_settings' ), 11 );
84
85 // Register plugin settings.
86 add_action( 'admin_init', array( $this, 'register_settings' ) );
87
88 // Add settings page to menu.
89 add_action( 'admin_menu', array( $this, 'add_menu_item' ), 11 );
90
91 // Add settings link to plugins page.
92 $bricksable_file = isset( $this->parent->file ) ? $this->parent->file : false;
93
94 add_filter(
95 'plugin_action_links_' . plugin_basename( $bricksable_file ),
96 array(
97 $this,
98 'add_settings_link',
99 )
100 );
101
102 // Configure placement of plugin settings page. See readme for implementation.
103 add_filter( $this->base . 'menu_settings', array( $this, 'configure_settings' ) );
104
105 // Enable JSON Uploads.
106 if ( ! empty( get_option( 'bricksable_json_uploads' ) ) ) {
107 add_filter( 'upload_mimes', array( $this, 'bricksable_file_mime_types' ) );
108 }
109
110 // Register custom elements.
111 add_action(
112 'init',
113 function() {
114 if ( 'on' === get_option( 'bricksable_all_elements' ) || false === get_option( 'bricksable_all_elements' ) ) {
115 $file_names = $this->bricksable_load_elements();
116 } else {
117 $file_names = $this->bricksable_check_elements();
118 }
119
120 foreach ( $file_names as $file_name ) {
121 $file = __DIR__ . "/elements/element-$file_name.php";
122 // Register all element in builder and frontend.
123 \Bricks\Elements::register_element( $file );
124 }
125 },
126 11
127 );
128
129 add_filter(
130 'bricks/builder/i18n',
131 function( $i18n ) {
132 $i18n['bricksable'] = esc_html__( 'Bricksable', 'bricksable' );
133
134 return $i18n;
135 }
136 );
137 }
138
139 /**
140 * Initialise settings
141 *
142 * @return void
143 */
144 public function init_settings() {
145 $this->settings = $this->settings_fields();
146 }
147
148 /**
149 * Add settings page to admin menu
150 *
151 * @return void
152 */
153 public function add_menu_item() {
154
155 $args = $this->menu_settings();
156
157 // Do nothing if wrong location key is set.
158 if ( is_array( $args ) && isset( $args['location'] ) && function_exists( 'add_' . $args['location'] . '_page' ) ) {
159 switch ( $args['location'] ) {
160 case 'options':
161 case 'submenu':
162 $page = add_submenu_page( $args['parent_slug'], $args['page_title'], $args['menu_title'], $args['capability'], $args['menu_slug'], $args['function'] );
163 break;
164 case 'menu':
165 $page = add_menu_page( $args['page_title'], $args['menu_title'], $args['capability'], $args['menu_slug'], $args['function'], $args['icon_url'], $args['position'] );
166 break;
167 default:
168 return;
169 }
170 add_action( 'admin_print_styles-' . $page, array( $this, 'settings_assets' ) );
171 }
172 }
173
174 /**
175 * Prepare default settings page arguments
176 *
177 * @return mixed|void
178 */
179 private function menu_settings() {
180 return apply_filters(
181 $this->base . 'menu_settings',
182 array(
183 'location' => 'submenu', // Possible settings: options, menu, submenu.
184 'parent_slug' => 'bricks',
185 'page_title' => __( 'Bricksable', 'bricksable' ),
186 'menu_title' => __( 'Bricksable', 'bricksable' ),
187 'capability' => 'manage_options',
188 'menu_slug' => $this->parent->_token . '_settings',
189 'function' => array( $this, 'settings_page' ),
190 'icon_url' => '',
191 'position' => 99,
192 )
193 );
194 }
195
196 /**
197 * Container for settings page arguments
198 *
199 * @param array $settings Settings array.
200 *
201 * @return array
202 */
203 public function configure_settings( $settings = array() ) {
204 return $settings;
205 }
206
207 /**
208 * Load settings JS & CSS
209 *
210 * @return void
211 */
212 public function settings_assets() {
213
214 // We're including the farbtastic script & styles here because they're needed for the colour picker
215 // If you're not including a colour picker field then you can leave these calls out as well as the farbtastic dependency for the wpt-admin-js script below.
216 wp_enqueue_style( 'farbtastic' );
217 wp_enqueue_script( 'farbtastic' );
218
219 // We're including the WP media scripts here because they're needed for the image upload field.
220 // If you're not including an image upload then you can leave this function call out.
221 // wp_enqueue_media().
222
223 wp_register_script( $this->parent->_token . '-settings', $this->parent->assets_url . 'js/settings' . $this->parent->script_suffix . '.js', array( 'farbtastic', 'jquery' ), '1.0.0', true );
224 wp_enqueue_script( $this->parent->_token . '-settings' );
225 }
226
227 /**
228 * Add settings link to plugin list table
229 *
230 * @param array $links Existing links.
231 * @return array Modified links.
232 */
233 public function add_settings_link( $links ) {
234 $settings_link = '<a href="admin.php?page=' . $this->parent->_token . '_settings">' . __( 'Settings', 'bricksable' ) . '</a>';
235 array_push( $links, $settings_link );
236 return $links;
237 }
238
239 /**
240 * Build settings fields
241 *
242 * @return array Fields to be displayed on settings page
243 */
244 private function settings_fields() {
245 $settings['general'] = array(
246 'title' => __( 'General', 'bricksable' ),
247 'fields' => array(
248 array(
249 'id' => 'json_uploads',
250 'label' => __( 'JSON Uploads', 'bricksable' ),
251 'description' => __( 'Please be careful about uploading Lottie JSON files from an unknown source. JSON files may potentially include malicious content. You should therefore download JSON files only from trusted sources, and only enable JSON uploads for user roles that you trust to follow this rule.', 'bricksable' ),
252 'type' => 'checkbox_multi',
253 'options' => $this->get_editable_roles(),
254 ),
255 ),
256 );
257
258 $settings['elements'] = array(
259 'title' => __( 'Elements', 'bricksable' ),
260 'fields' => array(
261 array(
262 'id' => 'all_elements',
263 'description' => __( 'Check all Bricks Custom Elements.', 'bricksable' ),
264 'type' => 'checkbox',
265 'default' => 'on',
266 ),
267 array(
268 'id' => 'flip-box',
269 'label' => __( 'Flipbox', 'bricksable' ),
270 'description' => __( 'Enable Flipbox Element.', 'bricksable' ),
271 'type' => 'checkbox',
272 'default' => 'on',
273 ),
274 array(
275 'id' => 'tilt-image',
276 'label' => __( 'Tilt Image', 'bricksable' ),
277 'description' => __( 'Enable Tilt Image Element.', 'bricksable' ),
278 'type' => 'checkbox',
279 'default' => 'on',
280 ),
281 array(
282 'id' => 'text-notation',
283 'label' => __( 'Text Notation', 'bricksable' ),
284 'description' => __( 'Enable Text Notation Element.', 'bricksable' ),
285 'type' => 'checkbox',
286 'default' => 'on',
287 ),
288 array(
289 'id' => 'lottie',
290 'label' => __( 'Lottie', 'bricksable' ),
291 'description' => __( 'Enable Lottie Element.', 'bricksable' ),
292 'type' => 'checkbox',
293 'default' => 'on',
294 ),
295 array(
296 'id' => 'floating',
297 'label' => __( 'Floating', 'bricksable' ),
298 'description' => __( 'Enable Floating Element.', 'bricksable' ),
299 'type' => 'checkbox',
300 'default' => 'on',
301 ),
302 array(
303 'id' => 'before-after-image',
304 'label' => __( 'Before After Image', 'bricksable' ),
305 'description' => __( 'Enable Before After Image Element.', 'bricksable' ),
306 'type' => 'checkbox',
307 'default' => 'on',
308 ),
309 array(
310 'id' => 'icon-list',
311 'label' => __( 'Icon List', 'bricksable' ),
312 'description' => __( 'Enable Icon List Element.', 'bricksable' ),
313 'type' => 'checkbox',
314 'default' => 'on',
315 ),
316 array(
317 'id' => 'multi-heading',
318 'label' => __( 'Multi Heading', 'bricksable' ),
319 'description' => __( 'Enable Multi Heading Element.', 'bricksable' ),
320 'type' => 'checkbox',
321 'default' => 'on',
322 ),
323 array(
324 'id' => 'content-toggle',
325 'label' => __( 'Content Toggle', 'bricksable' ),
326 'description' => __( 'Enable Content Toggle Element.', 'bricksable' ),
327 'type' => 'checkbox',
328 'default' => 'on',
329 ),
330 ),
331 );
332
333 $settings['misc'] = array(
334 'title' => __( 'Misc', 'bricksable' ),
335 'fields' => array(
336 array(
337 'id' => 'uninstall_on_delete',
338 'label' => __( 'Remove Data on Uninstall?', 'bricksable' ),
339 'description' => __( 'Check this box if you would like Bricksable to completely remove all of its data when the plugin is deleted.', 'bricksable' ),
340 'type' => 'checkbox',
341 ),
342 ),
343 );
344
345 $settings = apply_filters( $this->parent->_token . '_settings_fields', $settings );
346
347 return $settings;
348 }
349
350 /**
351 * Register plugin settings
352 *
353 * @return void
354 */
355 public function register_settings() {
356 if ( is_array( $this->settings ) ) {
357
358 // Check posted/selected tab.
359 //phpcs:disable
360 $current_section = '';
361 if ( isset( $_POST['tab'] ) && $_POST['tab'] ) {
362 $current_section = sanitize_text_field( wp_unslash( $_POST['tab'] ) );
363 } else {
364 if ( isset( $_GET['tab'] ) && $_GET['tab'] ) {
365 $current_section = sanitize_text_field( wp_unslash( $_GET['tab'] ) );
366 }
367 }
368 //phpcs:enable
369
370 foreach ( $this->settings as $section => $data ) {
371
372 if ( $current_section && $current_section !== $section ) {
373 continue;
374 }
375
376 // Add section to page.
377 add_settings_section( $section, $data['title'], array( $this, 'settings_section' ), $this->parent->_token . '_settings' );
378
379 foreach ( $data['fields'] as $field ) {
380
381 // Validation callback for field.
382 $validation = '';
383 if ( isset( $field['callback'] ) ) {
384 $validation = $field['callback'];
385 }
386
387 // Register field.
388 $option_name = $this->base . $field['id'];
389 register_setting( $this->parent->_token . '_settings', $option_name, $validation );
390
391 // Add field to page.
392 add_settings_field(
393 $field['id'],
394 isset( $field['label'] ) ? $field['label'] : '',
395 array( $this->parent->admin, 'display_field' ),
396 $this->parent->_token . '_settings',
397 $section,
398 array(
399 'field' => $field,
400 'prefix' => $this->base,
401 )
402 );
403 }
404
405 if ( ! $current_section ) {
406 break;
407 }
408 }
409 }
410 }
411
412 /**
413 * Settings section.
414 *
415 * @param array $section Array of section ids.
416 * @return void
417 */
418 public function settings_section( $section ) {
419 $html = '';
420 if ( isset( $this->settings[ $section['id'] ]['description'] ) ) {
421 $html = '<p> ' . $this->settings[ $section['id'] ]['description'] . '</p>' . "\n";
422 }
423 echo wp_kses( $html, $this->allowed_htmls );
424 }
425
426 /**
427 * Load settings page content.
428 *
429 * @return void
430 */
431 public function settings_page() {
432
433 // Build page HTML.
434 $html = '<div class="wrap" id="' . $this->parent->_token . '_settings">' . "\n";
435 $html .= '<h2>' . __( 'Bricksable Settings', 'bricksable' ) . '</h2>' . "\n";
436
437 $tab = '';
438
439 $nonce_name = 'bricksable_settings_nonce';
440 $nonce = sanitize_text_field( wp_create_nonce( $nonce_name ) );
441
442 if ( isset( $_POST['tab'] ) ) {
443 if ( wp_verify_nonce( $nonce, $nonce_name ) ) {
444 $current_section = sanitize_text_field( wp_unslash( $_POST['tab'] ) );
445 }
446 } else {
447 if ( isset( $_GET['tab'] ) && sanitize_text_field( wp_unslash( $_GET['tab'] ) ) ) {
448 $current_section = sanitize_text_field( wp_unslash( $_GET['tab'] ) );
449 }
450 }
451
452 // Show page tabs.
453 if ( is_array( $this->settings ) && 1 < count( $this->settings ) ) {
454
455 $html .= '<h2 class="nav-tab-wrapper">' . "\n";
456
457 $c = 0;
458 foreach ( $this->settings as $section => $data ) {
459
460 // Set tab class.
461 $class = 'nav-tab';
462 if ( ! isset( $_GET['tab'] ) ) {
463 if ( 0 === $c ) {
464 $class .= ' nav-tab-active';
465 }
466 } else {
467 if ( isset( $_GET['tab'] ) && $section === $_GET['tab'] ) {
468 $tab = sanitize_text_field( wp_unslash( $_GET['tab'] ) );
469 $class .= ' nav-tab-active';
470 }
471 }
472
473 // Set tab link.
474 $tab_link = add_query_arg(
475 array(
476 'tab' => $section,
477 $nonce_name => $nonce,
478 )
479 );
480
481 if ( isset( $_GET['settings-updated'] ) ) {
482 $updated = sanitize_text_field( wp_unslash( $_GET['settings-updated'] ) );
483
484 $tab_link = remove_query_arg( 'settings-updated', $tab_link );
485 }
486
487 // Output tab.
488 $html .= '<a href="' . $tab_link . '" class="' . esc_attr( $class ) . '">' . esc_html( $data['title'] ) . '</a>' . "\n";
489
490 ++$c;
491 }
492
493 $html .= '</h2>' . "\n";
494 }
495
496 $html .= '<form method="post" action="options.php" enctype="multipart/form-data">' . "\n";
497
498 // Get settings fields.
499 ob_start();
500 settings_fields( $this->parent->_token . '_settings' );
501 do_settings_sections( $this->parent->_token . '_settings' );
502 $html .= ob_get_clean();
503
504 $html .= '<p class="submit">' . "\n";
505 $html .= '<input type="hidden" name="tab" value="' . esc_attr( $tab ) . '" />' . "\n";
506 $html .= '<input name="Submit" type="submit" class="button-primary" value="' . esc_attr( __( 'Save Settings', 'bricksable' ) ) . '" />' . "\n";
507 $html .= '</p>' . "\n";
508 $html .= '</form>' . "\n";
509 $html .= '</div>' . "\n";
510
511 echo wp_kses( $html, $this->allowed_htmls );
512 }
513
514 /**
515 * Main Bricksable_Settings Instance
516 *
517 * Ensures only one instance of Bricksable_Settings is loaded or can be loaded.
518 *
519 * @since 1.0.0
520 * @static
521 * @see Bricksable()
522 * @param object $parent Object instance.
523 * @return object Bricksable_Settings instance
524 */
525 public static function instance( $parent ) {
526 if ( is_null( self::$instance ) ) {
527 self::$instance = new self( $parent );
528 }
529 return self::$instance;
530 } // End instance()
531
532 /**
533 * Cloning is forbidden.
534 *
535 * @since 1.0.0
536 */
537 public function __clone() {
538 _doing_it_wrong( __FUNCTION__, esc_html( __( 'Cloning of Bricksable_API is forbidden.' ) ), esc_attr( $this->parent->_version ) );
539 } // End __clone()
540
541 /**
542 * Unserializing instances of this class is forbidden.
543 *
544 * @since 1.0.0
545 */
546 public function __wakeup() {
547 _doing_it_wrong( __FUNCTION__, esc_html( __( 'Unserializing instances of Bricksable_API is forbidden.' ) ), esc_attr( $this->parent->_version ) );
548 } // End __wakeup()
549
550 /**
551 * Allowed html for output.
552 *
553 * @var array
554 */
555 public $allowed_htmls = array(
556 'a' => array(
557 'href' => array(),
558 'title' => array(),
559 'class' => array(),
560 ),
561 'h1' => array(
562 'href' => array(),
563 'title' => array(),
564 'class' => array(),
565 ),
566 'h2' => array(
567 'href' => array(),
568 'title' => array(),
569 'class' => array(),
570 ),
571 'h3' => array(
572 'href' => array(),
573 'title' => array(),
574 'class' => array(),
575 ),
576 'h4' => array(
577 'href' => array(),
578 'title' => array(),
579 'class' => array(),
580 ),
581 'input' => array(
582 'id' => array(),
583 'type' => array(),
584 'name' => array(),
585 'placeholder' => array(),
586 'value' => array(),
587 'class' => array(),
588 'checked' => array(),
589 'style' => array(),
590 'data-uploader_title' => array(),
591 'data-uploader_text' => array(),
592 ),
593 'select' => array(
594 'id' => array(),
595 'type' => array(),
596 'name' => array(),
597 'placeholder' => array(),
598 'value' => array(),
599 'multiple' => array(),
600 'style' => array(),
601 ),
602 'option' => array(
603 'id' => array(),
604 'type' => array(),
605 'name' => array(),
606 'placeholder' => array(),
607 'value' => array(),
608 'multiple' => array(),
609 'selected' => array(),
610 ),
611 'label' => array(
612 'for' => array(),
613 'title' => array(),
614 ),
615 'span' => array(
616 'class' => array(),
617 'title' => array(),
618 ),
619 'table' => array(
620 'scope' => array(),
621 'title' => array(),
622 'class' => array(),
623 'role' => array(),
624 ),
625 'tbody' => array(
626 'scope' => array(),
627 'title' => array(),
628 'class' => array(),
629 'role' => array(),
630 ),
631 'th' => array(
632 'scope' => array(),
633 'title' => array(),
634 ),
635 'form' => array(
636 'method' => array(),
637 'type' => array(),
638 'name' => array(),
639 'placeholder' => array(),
640 'value' => array(),
641 'multiple' => array(),
642 'selected' => array(),
643 'action' => array(),
644 'enctype' => array(),
645 ),
646 'div' => array(
647 'class' => array(),
648 'id' => array(),
649 ),
650 'img' => array(
651 'class' => array(),
652 'id' => array(),
653 'src' => array(),
654 ),
655 'textarea' => array(
656 'class' => array(),
657 'id' => array(),
658 'rows' => array(),
659 'cols' => array(),
660 'name' => array(),
661 'placeholder' => array(),
662 'spellcheck' => array(),
663 ),
664 'tr' => array(),
665 'td' => array(),
666 'p' => array(),
667 'br' => array(),
668 'em' => array(),
669 'strong' => array(),
670 'th' => array(),
671 );
672
673 /**
674 * Get WP Roles
675 *
676 * @return array Exclude subscriber and other very limited roles
677 */
678 public function get_editable_roles() {
679 $roles = wp_roles()->get_names();
680 $has_roles = array();
681 foreach ( $roles as $key => $label ) {
682 $role = get_role( $key );
683 if ( ! $role->has_cap( 'edit_posts' ) ) {
684 continue;
685 }
686 $has_roles[ $key ] = $label;
687 }
688 return $has_roles;
689 }
690
691 /**
692 * Mine Types
693 *
694 * @param return $mimes Check WP roles and allow json upload.
695 */
696 public function bricksable_file_mime_types( $mimes ) {
697 $user = wp_get_current_user();
698 $current_options = get_option( 'bricksable_json_uploads' );
699 if ( array_intersect( $current_options, $user->roles ) ) {
700 $mimes['json'] = 'application/json';
701 }
702 return $mimes;
703 }
704
705 /**
706 * Bricksable Elements
707 *
708 * @param return $file_names All registered elements.
709 */
710 public function bricksable_load_elements() {
711 $file_names = array(
712 'flip-box',
713 'tilt-image',
714 'text-notation',
715 'lottie',
716 'floating',
717 'before-after-image',
718 'icon-list',
719 'multi-heading',
720 'content-toggle',
721 );
722 return $file_names;
723 }
724
725 /**
726 * Bricksable Check Elements
727 *
728 * @param return $file_names check registered elements.
729 */
730 public function bricksable_check_elements() {
731 $file_names = array(
732 'on' === get_option( 'bricksable_flip-box' ) || false === get_option( 'bricksable_flip-box' ) ? 'flip-box' : '',
733 'on' === get_option( 'bricksable_tilt-image' ) || false === get_option( 'bricksable_tilt-image' ) ? 'tilt-image' : '',
734 'on' === get_option( 'bricksable_text-notation' ) || false === get_option( 'bricksable_text-notation' ) ? 'text-notation' : '',
735 'on' === get_option( 'bricksable_lottie' ) || false === get_option( 'bricksable_lottie' ) ? 'lottie' : '',
736 'on' === get_option( 'bricksable_floating' ) || false === get_option( 'bricksable_floating' ) ? 'floating' : '',
737 'on' === get_option( 'bricksable_before-after-image' ) || false === get_option( 'bricksable_before-after-image' ) ? 'before-after-image' : '',
738 'on' === get_option( 'bricksable_icon-list' ) || false === get_option( 'bricksable_icon-list' ) ? 'icon-list' : '',
739 'on' === get_option( 'bricksable_multi-heading' ) || false === get_option( 'bricksable_multi-heading' ) ? 'multi-heading' : '',
740 'on' === get_option( 'bricksable_content-toggle' ) || false === get_option( 'bricksable_content-toggle' ) ? 'content-toggle' : '',
741 );
742 return $file_names;
743 }
744
745 }
746