PluginProbe
Bricksable for Bricks Builder / 1.5.2
Bricksable for Bricks Builder v1.5.2
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.5.2, at includes/class-bricksable-settings.php

699 lines 18.5 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/$file_name/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 * Get Elements
241 */
242 public function get_elements() {
243 $elements = array();
244 $elements_dir = __DIR__ . '/elements';
245 $scan = scandir( $elements_dir );
246 foreach ( $scan as $result ) {
247 if ( '.' === $result || '..' === $result ) {
248 continue;
249 }
250 if ( is_dir( $elements_dir . '/' . $result ) ) {
251 $elements[] = $result;
252 }
253 }
254 return $elements;
255 }
256
257 /**
258 * Build settings fields
259 *
260 * @return array Fields to be displayed on settings page
261 */
262 private function settings_fields() {
263 $settings['general'] = array(
264 'title' => __( 'General', 'bricksable' ),
265 'fields' => array(
266 array(
267 'id' => 'json_uploads',
268 'label' => __( 'JSON Uploads', 'bricksable' ),
269 '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' ),
270 'type' => 'checkbox_multi',
271 'options' => $this->get_editable_roles(),
272 ),
273 ),
274 );
275
276 $fields = array(
277 array(
278 'id' => 'all_elements',
279 'description' => __( 'Check all Bricks Custom Elements.', 'bricksable' ),
280 'type' => 'checkbox',
281 'default' => 'on',
282 ),
283 );
284
285 $elements = $this->get_elements();
286 foreach ( $elements as $element ) {
287 $label = ucwords( str_replace( '-', ' ', $element ) );
288 $fields[] = array(
289 'id' => $element,
290 'label' => esc_attr( $label ),
291 /* translators: %s: enable elements */
292 'description' => sprintf( __( 'Enable %1$s Elements', 'bricksable' ), esc_html( $label ) ),
293 'type' => 'checkbox',
294 'default' => 'on',
295 );
296 }
297 $settings['elements'] = array(
298 'title' => __( 'Elements', 'bricksable' ),
299 'fields' => $fields,
300 );
301
302 $settings['misc'] = array(
303 'title' => __( 'Misc', 'bricksable' ),
304 'fields' => array(
305 array(
306 'id' => 'uninstall_on_delete',
307 'label' => __( 'Remove Data on Uninstall?', 'bricksable' ),
308 'description' => __( 'Check this box if you would like Bricksable to completely remove all of its data when the plugin is deleted.', 'bricksable' ),
309 'type' => 'checkbox',
310 ),
311 ),
312 );
313
314 $settings = apply_filters( $this->parent->_token . '_settings_fields', $settings );
315
316 return $settings;
317 }
318
319 /**
320 * Register plugin settings
321 *
322 * @return void
323 */
324 public function register_settings() {
325 if ( is_array( $this->settings ) ) {
326
327 // Check posted/selected tab.
328 //phpcs:disable
329 $current_section = '';
330 if ( isset( $_POST['tab'] ) && $_POST['tab'] ) {
331 $current_section = sanitize_text_field( wp_unslash( $_POST['tab'] ) );
332 } else {
333 if ( isset( $_GET['tab'] ) && $_GET['tab'] ) {
334 $current_section = sanitize_text_field( wp_unslash( $_GET['tab'] ) );
335 }
336 }
337 //phpcs:enable
338
339 foreach ( $this->settings as $section => $data ) {
340
341 if ( $current_section && $current_section !== $section ) {
342 continue;
343 }
344
345 // Add section to page.
346 add_settings_section( $section, $data['title'], array( $this, 'settings_section' ), $this->parent->_token . '_settings' );
347
348 foreach ( $data['fields'] as $field ) {
349
350 // Validation callback for field.
351 $validation = '';
352 if ( isset( $field['callback'] ) ) {
353 $validation = $field['callback'];
354 }
355
356 // Register field.
357 $option_name = $this->base . $field['id'];
358 register_setting( $this->parent->_token . '_settings', $option_name, $validation );
359
360 // Add field to page.
361 add_settings_field(
362 $field['id'],
363 isset( $field['label'] ) ? $field['label'] : '',
364 array( $this->parent->admin, 'display_field' ),
365 $this->parent->_token . '_settings',
366 $section,
367 array(
368 'field' => $field,
369 'prefix' => $this->base,
370 )
371 );
372 }
373
374 if ( ! $current_section ) {
375 break;
376 }
377 }
378 }
379 }
380
381 /**
382 * Settings section.
383 *
384 * @param array $section Array of section ids.
385 * @return void
386 */
387 public function settings_section( $section ) {
388 $html = '';
389 if ( isset( $this->settings[ $section['id'] ]['description'] ) ) {
390 $html = '<p> ' . $this->settings[ $section['id'] ]['description'] . '</p>' . "\n";
391 }
392 echo wp_kses( $html, $this->allowed_htmls );
393 }
394
395 /**
396 * Load settings page content.
397 *
398 * @return void
399 */
400 public function settings_page() {
401
402 // Build page HTML.
403 $html = '<div class="wrap" id="' . $this->parent->_token . '_settings">' . "\n";
404 $html .= '<h2>' . __( 'Bricksable Settings', 'bricksable' ) . '</h2>' . "\n";
405
406 $tab = '';
407
408 $nonce_name = 'bricksable_settings_nonce';
409 $nonce = sanitize_text_field( wp_create_nonce( $nonce_name ) );
410
411 if ( isset( $_POST['tab'] ) ) {
412 if ( wp_verify_nonce( $nonce, $nonce_name ) ) {
413 $current_section = sanitize_text_field( wp_unslash( $_POST['tab'] ) );
414 }
415 } else {
416 if ( isset( $_GET['tab'] ) && sanitize_text_field( wp_unslash( $_GET['tab'] ) ) ) {
417 $current_section = sanitize_text_field( wp_unslash( $_GET['tab'] ) );
418 }
419 }
420
421 // Show page tabs.
422 if ( is_array( $this->settings ) && 1 < count( $this->settings ) ) {
423
424 $html .= '<h2 class="nav-tab-wrapper">' . "\n";
425
426 $c = 0;
427 foreach ( $this->settings as $section => $data ) {
428
429 // Set tab class.
430 $class = 'nav-tab';
431 if ( ! isset( $_GET['tab'] ) ) {
432 if ( 0 === $c ) {
433 $class .= ' nav-tab-active';
434 }
435 } else {
436 if ( isset( $_GET['tab'] ) && $section === $_GET['tab'] ) {
437 $tab = sanitize_text_field( wp_unslash( $_GET['tab'] ) );
438 $class .= ' nav-tab-active';
439 }
440 }
441
442 // Set tab link.
443 $tab_link = add_query_arg(
444 array(
445 'tab' => $section,
446 $nonce_name => $nonce,
447 )
448 );
449
450 if ( isset( $_GET['settings-updated'] ) ) {
451 $updated = sanitize_text_field( wp_unslash( $_GET['settings-updated'] ) );
452
453 $tab_link = remove_query_arg( 'settings-updated', $tab_link );
454 }
455
456 // Output tab.
457 $html .= '<a href="' . $tab_link . '" class="' . esc_attr( $class ) . '">' . esc_html( $data['title'] ) . '</a>' . "\n";
458
459 ++$c;
460 }
461
462 $html .= '</h2>' . "\n";
463 }
464
465 $html .= '<form method="post" action="options.php" enctype="multipart/form-data">' . "\n";
466
467 // Get settings fields.
468 ob_start();
469 settings_fields( $this->parent->_token . '_settings' );
470 do_settings_sections( $this->parent->_token . '_settings' );
471 $html .= ob_get_clean();
472
473 $html .= '<p class="submit">' . "\n";
474 $html .= '<input type="hidden" name="tab" value="' . esc_attr( $tab ) . '" />' . "\n";
475 $html .= '<input name="Submit" type="submit" class="button-primary" value="' . esc_attr( __( 'Save Settings', 'bricksable' ) ) . '" />' . "\n";
476 $html .= '</p>' . "\n";
477 $html .= '</form>' . "\n";
478 $html .= '</div>' . "\n";
479
480 echo wp_kses( $html, $this->allowed_htmls );
481 }
482
483 /**
484 * Main Bricksable_Settings Instance
485 *
486 * Ensures only one instance of Bricksable_Settings is loaded or can be loaded.
487 *
488 * @since 1.0.0
489 * @static
490 * @see Bricksable()
491 * @param object $parent Object instance.
492 * @return object Bricksable_Settings instance
493 */
494 public static function instance( $parent ) {
495 if ( is_null( self::$instance ) ) {
496 self::$instance = new self( $parent );
497 }
498 return self::$instance;
499 } // End instance()
500
501 /**
502 * Cloning is forbidden.
503 *
504 * @since 1.0.0
505 */
506 public function __clone() {
507 _doing_it_wrong( __FUNCTION__, esc_html( __( 'Cloning of Bricksable_API is forbidden.' ) ), esc_attr( $this->parent->_version ) );
508 } // End __clone()
509
510 /**
511 * Unserializing instances of this class is forbidden.
512 *
513 * @since 1.0.0
514 */
515 public function __wakeup() {
516 _doing_it_wrong( __FUNCTION__, esc_html( __( 'Unserializing instances of Bricksable_API is forbidden.' ) ), esc_attr( $this->parent->_version ) );
517 } // End __wakeup()
518
519 /**
520 * Allowed html for output.
521 *
522 * @var array
523 */
524 public $allowed_htmls = array(
525 'a' => array(
526 'href' => array(),
527 'title' => array(),
528 'class' => array(),
529 ),
530 'h1' => array(
531 'href' => array(),
532 'title' => array(),
533 'class' => array(),
534 ),
535 'h2' => array(
536 'href' => array(),
537 'title' => array(),
538 'class' => array(),
539 ),
540 'h3' => array(
541 'href' => array(),
542 'title' => array(),
543 'class' => array(),
544 ),
545 'h4' => array(
546 'href' => array(),
547 'title' => array(),
548 'class' => array(),
549 ),
550 'input' => array(
551 'id' => array(),
552 'type' => array(),
553 'name' => array(),
554 'placeholder' => array(),
555 'value' => array(),
556 'class' => array(),
557 'checked' => array(),
558 'style' => array(),
559 'data-uploader_title' => array(),
560 'data-uploader_text' => array(),
561 ),
562 'select' => array(
563 'id' => array(),
564 'type' => array(),
565 'name' => array(),
566 'placeholder' => array(),
567 'value' => array(),
568 'multiple' => array(),
569 'style' => array(),
570 ),
571 'option' => array(
572 'id' => array(),
573 'type' => array(),
574 'name' => array(),
575 'placeholder' => array(),
576 'value' => array(),
577 'multiple' => array(),
578 'selected' => array(),
579 ),
580 'label' => array(
581 'for' => array(),
582 'title' => array(),
583 ),
584 'span' => array(
585 'class' => array(),
586 'title' => array(),
587 ),
588 'table' => array(
589 'scope' => array(),
590 'title' => array(),
591 'class' => array(),
592 'role' => array(),
593 ),
594 'tbody' => array(
595 'scope' => array(),
596 'title' => array(),
597 'class' => array(),
598 'role' => array(),
599 ),
600 'th' => array(
601 'scope' => array(),
602 'title' => array(),
603 ),
604 'form' => array(
605 'method' => array(),
606 'type' => array(),
607 'name' => array(),
608 'placeholder' => array(),
609 'value' => array(),
610 'multiple' => array(),
611 'selected' => array(),
612 'action' => array(),
613 'enctype' => array(),
614 ),
615 'div' => array(
616 'class' => array(),
617 'id' => array(),
618 ),
619 'img' => array(
620 'class' => array(),
621 'id' => array(),
622 'src' => array(),
623 ),
624 'textarea' => array(
625 'class' => array(),
626 'id' => array(),
627 'rows' => array(),
628 'cols' => array(),
629 'name' => array(),
630 'placeholder' => array(),
631 'spellcheck' => array(),
632 ),
633 'tr' => array(),
634 'td' => array(),
635 'p' => array(),
636 'br' => array(),
637 'em' => array(),
638 'strong' => array(),
639 'th' => array(),
640 );
641
642 /**
643 * Get WP Roles
644 *
645 * @return array Exclude subscriber and other very limited roles
646 */
647 public function get_editable_roles() {
648 $roles = wp_roles()->get_names();
649 $has_roles = array();
650 foreach ( $roles as $key => $label ) {
651 $role = get_role( $key );
652 if ( ! $role->has_cap( 'edit_posts' ) ) {
653 continue;
654 }
655 $has_roles[ $key ] = $label;
656 }
657 return $has_roles;
658 }
659
660 /**
661 * Mine Types
662 *
663 * @param return $mimes Check WP roles and allow json upload.
664 */
665 public function bricksable_file_mime_types( $mimes ) {
666 $user = wp_get_current_user();
667 $current_options = get_option( 'bricksable_json_uploads' );
668 if ( array_intersect( $current_options, $user->roles ) ) {
669 $mimes['json'] = 'application/json';
670 }
671 return $mimes;
672 }
673
674 /**
675 * Bricksable Elements
676 */
677 public function bricksable_load_elements() {
678 $file_names = $this->get_elements();
679 return $file_names;
680 }
681
682 /**
683 * Bricksable Check Elements
684 */
685 public function bricksable_check_elements() {
686 $file_names = array();
687 $elements = $this->get_elements();
688
689 foreach ( $elements as $element ) {
690 if ( 'on' === get_option( 'bricksable_' . $element ) || false === get_option( 'bricksable_' . $element ) ) {
691 $file_names[] = $element;
692 }
693 }
694
695 return $file_names;
696 }
697
698 }
699