Passed
Push — master ( bf4088...8d905d )
by Stiofan
04:38 queued 28s
created

WP_Super_Duper::get_widget_settings()   C

Complexity

Conditions 9
Paths 256

Size

Total Lines 28
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 20
nc 256
nop 0
dl 0
loc 28
rs 6.5222
c 0
b 0
f 0
1
<?php
2
if ( ! defined( 'ABSPATH' ) ) {
3
	exit;
4
}
5
6
if ( ! class_exists( 'WP_Super_Duper' ) ) {
7
8
9
	/**
10
	 * A Class to be able to create a Widget, Shortcode or Block to be able to output content for WordPress.
11
	 *
12
	 * Should not be called direct but extended instead.
13
	 *
14
	 * Class WP_Super_Duper
15
	 * @since 1.0.16 change log moved to file change-log.txt - CHANGED
16
	 * @ver 1.0.19
17
	 */
18
	class WP_Super_Duper extends WP_Widget {
19
20
		public $version = "1.0.27";
21
		public $font_awesome_icon_version = "5.11.2";
22
		public $block_code;
23
		public $options;
24
		public $base_id;
25
		public $settings_hash;
26
		public $arguments = array();
27
		public $instance = array();
28
		private $class_name;
29
30
		/**
31
		 * The relative url to the current folder.
32
		 *
33
		 * @var string
34
		 */
35
		public $url = '';
36
37
		/**
38
		 * Take the array options and use them to build.
39
		 */
40
		public function __construct( $options ) {
41
			global $sd_widgets;
42
43
			$sd_widgets[ $options['base_id'] ] = array(
44
				'name'       => $options['name'],
45
				'class_name' => $options['class_name']
46
			);
47
			$this->base_id                     = $options['base_id'];
48
			// lets filter the options before we do anything
49
			$options       = apply_filters( "wp_super_duper_options", $options );
50
			$options       = apply_filters( "wp_super_duper_options_{$this->base_id}", $options );
51
			$options       = $this->add_name_from_key( $options );
52
			$this->options = $options;
53
54
			$this->base_id   = $options['base_id'];
55
			$this->arguments = isset( $options['arguments'] ) ? $options['arguments'] : array();
56
57
			// init parent
58
			parent::__construct( $options['base_id'], $options['name'], $options['widget_ops'] );
59
60
			if ( isset( $options['class_name'] ) ) {
61
				// register widget
62
				$this->class_name = $options['class_name'];
63
64
				// register shortcode
65
				$this->register_shortcode();
66
67
				// Fusion Builder (avada) support
68
				if ( function_exists( 'fusion_builder_map' ) ) {
69
					add_action( 'init', array( $this, 'register_fusion_element' ) );
70
				}
71
72
				// register block
73
				add_action( 'admin_enqueue_scripts', array( $this, 'register_block' ) );
74
			}
75
76
			// add the CSS and JS we need ONCE
77
			global $sd_widget_scripts;
78
79
			if ( ! $sd_widget_scripts ) {
80
				wp_add_inline_script( 'admin-widgets', $this->widget_js() );
81
				wp_add_inline_script( 'customize-controls', $this->widget_js() );
82
				wp_add_inline_style( 'widgets', $this->widget_css() );
83
84
				// maybe add elementor editor styles
85
				add_action( 'elementor/editor/after_enqueue_styles', array( $this, 'elementor_editor_styles' ) );
86
87
				$sd_widget_scripts = true;
88
89
				// add shortcode insert button once
90
				add_action( 'media_buttons', array( $this, 'shortcode_insert_button' ) );
91
				// generatepress theme sections compatibility
92
				if ( function_exists( 'generate_sections_sections_metabox' ) ) {
93
					add_action( 'generate_sections_metabox', array( $this, 'shortcode_insert_button_script' ) );
94
				}
95
				if ( $this->is_preview() ) {
96
					add_action( 'wp_footer', array( $this, 'shortcode_insert_button_script' ) );
97
					// this makes the insert button work for elementor
98
					add_action( 'elementor/editor/after_enqueue_scripts', array(
99
						$this,
100
						'shortcode_insert_button_script'
101
					) ); // for elementor
102
				}
103
				// this makes the insert button work for cornerstone
104
				add_action( 'wp_print_footer_scripts', array( __CLASS__, 'maybe_cornerstone_builder' ) );
105
106
				add_action( 'wp_ajax_super_duper_get_widget_settings', array( __CLASS__, 'get_widget_settings' ) );
107
				add_action( 'wp_ajax_super_duper_get_picker', array( __CLASS__, 'get_picker' ) );
108
109
				// add generator text to admin head
110
				add_action( 'admin_head', array( $this, 'generator' ) );
111
			}
112
113
			do_action( 'wp_super_duper_widget_init', $options, $this );
114
		}
115
116
		/**
117
		 * Add our widget CSS to elementor editor.
118
		 */
119
		public function elementor_editor_styles() {
120
			wp_add_inline_style( 'elementor-editor', $this->widget_css( false ) );
121
		}
122
123
		public function register_fusion_element() {
124
125
			$options = $this->options;
126
127
			if ( $this->base_id ) {
128
129
				$params = $this->get_fusion_params();
130
131
				$args = array(
132
					'name'            => $options['name'],
133
					'shortcode'       => $this->base_id,
134
					'icon'            => $options['block-icon'] ? $options['block-icon'] : 'far fa-square',
135
					'allow_generator' => true,
136
				);
137
138
				if ( ! empty( $params ) ) {
139
					$args['params'] = $params;
140
				}
141
142
				fusion_builder_map( $args );
0 ignored issues
show
Bug introduced by
The function fusion_builder_map was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

142
				/** @scrutinizer ignore-call */ 
143
    fusion_builder_map( $args );
Loading history...
143
			}
144
145
		}
146
147
		public function get_fusion_params() {
148
			$params    = array();
149
			$arguments = $this->get_arguments();
150
151
			if ( ! empty( $arguments ) ) {
152
				foreach ( $arguments as $key => $val ) {
153
					$param = array();
154
					// type
155
					$param['type'] = str_replace(
156
						array(
157
							"text",
158
							"number",
159
							"email",
160
							"color",
161
							"checkbox"
162
						),
163
						array(
164
							"textfield",
165
							"textfield",
166
							"textfield",
167
							"colorpicker",
168
							"select",
169
170
						),
171
						$val['type'] );
172
173
					// multiselect
174
					if ( $val['type'] == 'multiselect' || ( ( $param['type'] == 'select' || $val['type'] == 'select' ) && ! empty( $val['multiple'] ) ) ) {
175
						$param['type']     = 'multiple_select';
176
						$param['multiple'] = true;
177
					}
178
179
					// heading
180
					$param['heading'] = $val['title'];
181
182
					// description
183
					$param['description'] = isset( $val['desc'] ) ? $val['desc'] : '';
184
185
					// param_name
186
					$param['param_name'] = $key;
187
188
					// Default
189
					$param['default'] = isset( $val['default'] ) ? $val['default'] : '';
190
191
					// Group
192
					if ( isset( $val['group'] ) ) {
193
						$param['group'] = $val['group'];
194
					}
195
196
					// value
197
					if ( $val['type'] == 'checkbox' ) {
198
						if ( isset( $val['default'] ) && $val['default'] == '0' ) {
199
							unset( $param['default'] );
200
						}
201
						$param['value'] = array( '' => __( "No" ), '1' => __( "Yes" ) );
202
					} elseif ( $param['type'] == 'select' || $param['type'] == 'multiple_select' ) {
203
						$param['value'] = isset( $val['options'] ) ? $val['options'] : array();
204
					} else {
205
						$param['value'] = isset( $val['default'] ) ? $val['default'] : '';
206
					}
207
208
					// setup the param
209
					$params[] = $param;
210
211
				}
212
			}
213
214
215
			return $params;
216
		}
217
218
		/**
219
		 * Maybe insert the shortcode inserter button in the footer if we are in the cornerstone builder
220
		 */
221
		public static function maybe_cornerstone_builder() {
222
			if ( did_action( 'cornerstone_before_boot_app' ) ) {
223
				self::shortcode_insert_button_script();
224
			}
225
		}
226
227
		/**
228
		 * A function to ge the shortcode builder picker html.
229
		 *
230
		 * @param string $editor_id
231
		 *
232
		 * @return string
233
		 */
234
		public static function get_picker( $editor_id = '' ) {
235
236
			ob_start();
237
			if ( isset( $_POST['editor_id'] ) ) {
238
				$editor_id = esc_attr( $_POST['editor_id'] );
239
			} elseif ( isset( $_REQUEST['et_fb'] ) ) {
240
				$editor_id = 'main_content_content_vb_tiny_mce';
241
			}
242
243
			global $sd_widgets;
244
			?>
245
246
			<div class="sd-shortcode-left-wrap">
247
				<?php
248
				ksort( $sd_widgets );
249
				//				print_r($sd_widgets);exit;
250
				if ( ! empty( $sd_widgets ) ) {
251
					echo '<select class="widefat" onchange="sd_get_shortcode_options(this);">';
252
					echo "<option>" . __( 'Select shortcode' ) . "</option>";
253
					foreach ( $sd_widgets as $shortcode => $class ) {
254
						echo "<option value='" . esc_attr( $shortcode ) . "'>" . esc_attr( $shortcode ) . " (" . esc_attr( $class['name'] ) . ")</option>";
255
					}
256
					echo "</select>";
257
258
				}
259
				?>
260
				<div class="sd-shortcode-settings"></div>
261
262
			</div>
263
264
			<div class="sd-shortcode-right-wrap">
265
				<textarea id='sd-shortcode-output' disabled></textarea>
266
				<div id='sd-shortcode-output-actions'>
267
					<?php if ( $editor_id != '' ) { ?>
268
						<button class="button sd-insert-shortcode-button"
269
						        onclick="sd_insert_shortcode(<?php if ( ! empty( $editor_id ) ) {
270
							        echo "'" . $editor_id . "'";
271
						        } ?>)"><?php _e( 'Insert shortcode' ); ?></button>
272
					<?php } ?>
273
					<button class="button"
274
					        onclick="sd_copy_to_clipboard()"><?php _e( 'Copy shortcode' ); ?></button>
275
				</div>
276
			</div>
277
			<?php
278
279
			$html = ob_get_clean();
280
281
			if ( wp_doing_ajax() ) {
282
				echo $html;
283
				$should_die = true;
284
285
				// some builder get the editor via ajax so we should not die on those occasions
286
				$dont_die = array(
287
					'parent_tag',// WP Bakery
288
					'avia_request' // enfold
289
				);
290
291
				foreach ( $dont_die as $request ) {
292
					if ( isset( $_REQUEST[ $request ] ) ) {
293
						$should_die = false;
294
					}
295
				}
296
297
				if ( $should_die ) {
298
					wp_die();
299
				}
300
301
			} else {
302
				return $html;
303
			}
304
305
			return '';
306
307
		}
308
309
		/**
310
		 * Output the version in the admin header.
311
		 */
312
		public function generator() {
313
			echo '<meta name="generator" content="WP Super Duper v' . $this->version . '" />';
314
		}
315
316
		/**
317
		 * Get widget settings.
318
		 *
319
		 * @since 1.0.0
320
		 */
321
		public static function get_widget_settings() {
322
			global $sd_widgets;
323
324
			$shortcode = isset( $_REQUEST['shortcode'] ) && $_REQUEST['shortcode'] ? sanitize_title_with_dashes( $_REQUEST['shortcode'] ) : '';
325
			if ( ! $shortcode ) {
326
				wp_die();
327
			}
328
			$widget_args = isset( $sd_widgets[ $shortcode ] ) ? $sd_widgets[ $shortcode ] : '';
329
			if ( ! $widget_args ) {
330
				wp_die();
331
			}
332
			$class_name = isset( $widget_args['class_name'] ) && $widget_args['class_name'] ? $widget_args['class_name'] : '';
333
			if ( ! $class_name ) {
334
				wp_die();
335
			}
336
337
			// invoke an instance method
338
			$widget = new $class_name;
339
340
			ob_start();
341
			$widget->form( array() );
342
			$form = ob_get_clean();
343
			echo "<form id='$shortcode'>" . $form . "<div class=\"widget-control-save\"></div></form>";
344
			echo "<style>" . $widget->widget_css() . "</style>";
345
			echo "<script>" . $widget->widget_js() . "</script>";
346
			?>
347
			<?php
348
			wp_die();
349
		}
350
351
		/**
352
		 * Insert shortcode builder button to classic editor (not inside Gutenberg, not needed).
353
		 *
354
		 * @since 1.0.0
355
		 *
356
		 * @param string $editor_id Optional. Shortcode editor id. Default null.
357
		 * @param string $insert_shortcode_function Optional. Insert shortcode function. Default null.
358
		 */
359
		public static function shortcode_insert_button( $editor_id = '', $insert_shortcode_function = '' ) {
360
			global $sd_widgets, $shortcode_insert_button_once;
361
			if ( $shortcode_insert_button_once ) {
362
				return;
363
			}
364
			add_thickbox();
365
366
367
			/**
368
			 * Cornerstone makes us play dirty tricks :/
369
			 * All media_buttons are removed via JS unless they are two specific id's so we wrap our content in this ID so it is not removed.
370
			 */
371
			if ( function_exists( 'cornerstone_plugin_init' ) && ! is_admin() ) {
372
				echo '<span id="insert-media-button">';
373
			}
374
375
			echo self::shortcode_button( 'this', 'true' );
376
377
			// see opening note
378
			if ( function_exists( 'cornerstone_plugin_init' ) && ! is_admin() ) {
379
				echo '</span>'; // end #insert-media-button
380
			}
381
382
			// Add separate script for generatepress theme sections
383
			if ( function_exists( 'generate_sections_sections_metabox' ) && did_action( 'generate_sections_metabox' ) ) {
384
			} else {
385
				self::shortcode_insert_button_script( $editor_id, $insert_shortcode_function );
386
			}
387
388
			$shortcode_insert_button_once = true;
389
		}
390
391
		/**
392
		 * Gets the shortcode insert button html.
393
		 *
394
		 * @param string $id
395
		 * @param string $search_for_id
396
		 *
397
		 * @return mixed
398
		 */
399
		public static function shortcode_button( $id = '', $search_for_id = '' ) {
400
			ob_start();
401
			?>
402
			<span class="sd-lable-shortcode-inserter">
403
				<a onclick="sd_ajax_get_picker(<?php echo $id;
404
				if ( $search_for_id ) {
405
					echo "," . $search_for_id;
406
				} ?>);" href="#TB_inline?width=100%&height=550&inlineId=super-duper-content-ajaxed"
407
				   class="thickbox button super-duper-content-open" title="Add Shortcode">
408
					<span style="vertical-align: middle;line-height: 18px;font-size: 20px;"
409
					      class="dashicons dashicons-screenoptions"></span>
410
				</a>
411
				<div id="super-duper-content-ajaxed" style="display:none;">
412
					<span>Loading</span>
413
				</div>
414
			</span>
415
416
			<?php
417
			$html = ob_get_clean();
418
419
			// remove line breaks so we can use it in js
420
			return preg_replace( "/\r|\n/", "", trim( $html ) );
421
		}
422
423
		/**
424
		 * Makes SD work with the siteOrigin page builder.
425
		 *
426
		 * @since 1.0.6
427
		 * @return mixed
428
		 */
429
		public static function siteorigin_js() {
430
			ob_start();
431
			?>
432
			<script>
433
				/**
434
				 * Check a form to see what items should be shown or hidden.
435
				 */
436
				function sd_so_show_hide(form) {
437
					jQuery(form).find(".sd-argument").each(function () {
438
439
						var $element_require = jQuery(this).data('element_require');
440
441
						if ($element_require) {
442
443
							$element_require = $element_require.replace("&#039;", "'"); // replace single quotes
444
							$element_require = $element_require.replace("&quot;", '"'); // replace double quotes
445
446
							if (eval($element_require)) {
447
								jQuery(this).removeClass('sd-require-hide');
448
							} else {
449
								jQuery(this).addClass('sd-require-hide');
450
							}
451
						}
452
					});
453
				}
454
455
				/**
456
				 * Toggle advanced settings visibility.
457
				 */
458
				function sd_so_toggle_advanced($this) {
459
					var form = jQuery($this).parents('form,.form,.so-content');
460
					form.find('.sd-advanced-setting').toggleClass('sd-adv-show');
461
					return false;// prevent form submit
462
				}
463
464
				/**
465
				 * Initialise a individual widget.
466
				 */
467
				function sd_so_init_widget($this, $selector) {
468
					if (!$selector) {
469
						$selector = 'form';
470
					}
471
					// only run once.
472
					if (jQuery($this).data('sd-widget-enabled')) {
473
						return;
474
					} else {
475
						jQuery($this).data('sd-widget-enabled', true);
476
					}
477
478
					var $button = '<button title="<?php _e( 'Advanced Settings' );?>" class="button button-primary right sd-advanced-button" onclick="sd_so_toggle_advanced(this);return false;"><i class="fas fa-sliders-h" aria-hidden="true"></i></button>';
479
					var form = jQuery($this).parents('' + $selector + '');
480
481
					if (jQuery($this).val() == '1' && jQuery(form).find('.sd-advanced-button').length == 0) {
482
						jQuery(form).append($button);
483
					}
484
485
					// show hide on form change
486
					jQuery(form).on("change", function () {
487
						sd_so_show_hide(form);
488
					});
489
490
					// show hide on load
491
					sd_so_show_hide(form);
492
				}
493
494
				jQuery(function () {
495
					jQuery(document).on('open_dialog', function (w, e) {
496
						setTimeout(function () {
497
							if (jQuery('.so-panels-dialog-wrapper:visible .so-content.panel-dialog .sd-show-advanced').length) {
498
								console.log('exists');
499
								if (jQuery('.so-panels-dialog-wrapper:visible .so-content.panel-dialog .sd-show-advanced').val() == '1') {
500
									console.log('true');
501
									sd_so_init_widget('.so-panels-dialog-wrapper:visible .so-content.panel-dialog .sd-show-advanced', 'div');
502
								}
503
							}
504
						}, 200);
505
					});
506
				});
507
			</script>
508
			<?php
509
			$output = ob_get_clean();
510
511
			/*
512
			 * We only add the <script> tags for code highlighting, so we strip them from the output.
513
			 */
514
515
			return str_replace( array(
516
				'<script>',
517
				'</script>'
518
			), '', $output );
519
		}
520
521
		/**
522
		 * Output the JS and CSS for the shortcode insert button.
523
		 *
524
		 * @since 1.0.6
525
		 *
526
		 * @param string $editor_id
527
		 * @param string $insert_shortcode_function
528
		 */
529
		public static function shortcode_insert_button_script( $editor_id = '', $insert_shortcode_function = '' ) {
530
			?>
531
			<style>
532
				.sd-shortcode-left-wrap {
533
					float: left;
534
					width: 60%;
535
				}
536
537
				.sd-shortcode-left-wrap .gd-help-tip {
538
					float: none;
539
				}
540
541
				.sd-shortcode-left-wrap .widefat {
542
					border-spacing: 0;
543
					width: 100%;
544
					clear: both;
545
					margin: 0;
546
					border: 1px solid #ddd;
547
					box-shadow: inset 0 1px 2px rgba(0, 0, 0, .07);
548
					background-color: #fff;
549
					color: #32373c;
550
					outline: 0;
551
					transition: 50ms border-color ease-in-out;
552
					padding: 3px 5px;
553
				}
554
555
				.sd-shortcode-left-wrap input[type=checkbox].widefat {
556
					border: 1px solid #b4b9be;
557
					background: #fff;
558
					color: #555;
559
					clear: none;
560
					cursor: pointer;
561
					display: inline-block;
562
					line-height: 0;
563
					height: 16px;
564
					margin: -4px 4px 0 0;
565
					margin-top: 0;
566
					outline: 0;
567
					padding: 0 !important;
568
					text-align: center;
569
					vertical-align: middle;
570
					width: 16px;
571
					min-width: 16px;
572
					-webkit-appearance: none;
573
					box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);
574
					transition: .05s border-color ease-in-out;
575
				}
576
577
				.sd-shortcode-left-wrap input[type=checkbox]:checked:before {
578
					content: "\f147";
579
					margin: -3px 0 0 -4px;
580
					color: #1e8cbe;
581
					float: left;
582
					display: inline-block;
583
					vertical-align: middle;
584
					width: 16px;
585
					font: normal 21px/1 dashicons;
586
					speak: none;
587
					-webkit-font-smoothing: antialiased;
588
					-moz-osx-font-smoothing: grayscale;
589
				}
590
591
				#sd-shortcode-output-actions button,
592
				.sd-advanced-button {
593
					color: #555;
594
					border-color: #ccc;
595
					background: #f7f7f7;
596
					box-shadow: 0 1px 0 #ccc;
597
					vertical-align: top;
598
					display: inline-block;
599
					text-decoration: none;
600
					font-size: 13px;
601
					line-height: 26px;
602
					height: 28px;
603
					margin: 0;
604
					padding: 0 10px 1px;
605
					cursor: pointer;
606
					border-width: 1px;
607
					border-style: solid;
608
					-webkit-appearance: none;
609
					border-radius: 3px;
610
					white-space: nowrap;
611
					box-sizing: border-box;
612
				}
613
614
				button.sd-advanced-button {
615
					background: #0073aa;
616
					border-color: #006799;
617
					box-shadow: inset 0 2px 0 #006799;
618
					vertical-align: top;
619
					color: #fff;
620
					text-decoration: none;
621
					text-shadow: 0 -1px 1px #006799, 1px 0 1px #006799, 0 1px 1px #006799, -1px 0 1px #006799;
622
					float: right;
623
					margin-right: 3px !important;
624
					font-size: 20px !important;
625
				}
626
627
				.sd-shortcode-right-wrap {
628
					float: right;
629
					width: 35%;
630
				}
631
632
				#sd-shortcode-output {
633
					background: rgba(255, 255, 255, .5);
634
					border-color: rgba(222, 222, 222, .75);
635
					box-shadow: inset 0 1px 2px rgba(0, 0, 0, .04);
636
					color: rgba(51, 51, 51, .5);
637
					overflow: auto;
638
					padding: 2px 6px;
639
					line-height: 1.4;
640
					resize: vertical;
641
				}
642
643
				#sd-shortcode-output {
644
					height: 250px;
645
					width: 100%;
646
				}
647
648
				<?php if ( function_exists( 'generate_sections_sections_metabox' ) ) { ?>
649
				.generate-sections-modal #custom-media-buttons > .sd-lable-shortcode-inserter {
650
					display: inline;
651
				}
652
653
				<?php } ?>
654
			</style>
655
			<?php
656
			if ( class_exists( 'SiteOrigin_Panels' ) ) {
657
				echo "<script>" . self::siteorigin_js() . "</script>";
658
			}
659
			?>
660
			<script>
661
				<?php
662
				if(! empty( $insert_shortcode_function )){
663
					echo $insert_shortcode_function;
664
				}else{
665
666
				/**
667
				 * Function for super duper insert shortcode.
668
				 *
669
				 * @since 1.0.0
670
				 */
671
				?>
672
				function sd_insert_shortcode($editor_id) {
673
					$shortcode = jQuery('#TB_ajaxContent #sd-shortcode-output').val();
674
					if ($shortcode) {
675
						if (!$editor_id) {
676
							<?php
677
							if ( isset( $_REQUEST['et_fb'] ) ) {
678
								echo '$editor_id = "#main_content_content_vb_tiny_mce";';
679
							} elseif ( isset( $_REQUEST['action'] ) && $_REQUEST['action'] == 'elementor' ) {
680
								echo '$editor_id = "#elementor-controls .wp-editor-container textarea";';
681
							} else {
682
								echo '$editor_id = "#wp-content-editor-container textarea";';
683
							}
684
							?>
685
						} else {
686
							$editor_id = '#' + $editor_id;
687
						}
688
						tmceActive = jQuery($editor_id).attr("aria-hidden") == "true" ? true : false;
689
						/* GeneratePress */
690
						if (jQuery('#generate-sections-modal-dialog ' + $editor_id).length) {
691
							$editor_id = '#generate-sections-modal-dialog ' + $editor_id;
692
							tmceActive = jQuery($editor_id).closest('.wp-editor-wrap').hasClass('tmce-active') ? true : false;
693
						}
694
						if (tinyMCE && tinyMCE.activeEditor && tmceActive) {
695
							tinyMCE.execCommand('mceInsertContent', false, $shortcode);
696
						} else {
697
							var $txt = jQuery($editor_id);
698
							var caretPos = $txt[0].selectionStart;
699
							var textAreaTxt = $txt.val();
700
							var txtToAdd = $shortcode;
701
							var textareaValue = textAreaTxt.substring(0, caretPos) + txtToAdd + textAreaTxt.substring(caretPos);
702
							$txt.focus().val(textareaValue).change().keydown().blur().keyup().keypress().trigger('input').trigger('change');
703
704
							// set Divi react input value
705
							var input = document.getElementById("main_content_content_vb_tiny_mce");
706
							if (input) {
707
								sd_setNativeValue(input, textareaValue);
708
							}
709
710
						}
711
						tb_remove();
712
					}
713
				}
714
715
				/*
716
				 Set the value of elements controlled via react.
717
				 */
718
				function sd_setNativeValue(element, value) {
719
					let lastValue = element.value;
720
					element.value = value;
721
					let event = new Event("input", {target: element, bubbles: true});
722
					// React 15
723
					event.simulated = true;
724
					// React 16
725
					let tracker = element._valueTracker;
726
					if (tracker) {
727
						tracker.setValue(lastValue);
728
					}
729
					element.dispatchEvent(event);
730
				}
731
				<?php }?>
732
733
				/*
734
				 Copies the shortcode to the clipboard.
735
				 */
736
				function sd_copy_to_clipboard() {
737
					/* Get the text field */
738
					var copyText = document.querySelector("#TB_ajaxContent #sd-shortcode-output");
739
					//un-disable the field
740
					copyText.disabled = false;
741
					/* Select the text field */
742
					copyText.select();
743
					/* Copy the text inside the text field */
744
					document.execCommand("Copy");
745
					//re-disable the field
746
					copyText.disabled = true;
747
					/* Alert the copied text */
748
					alert("Copied the text: " + copyText.value);
749
				}
750
751
				/*
752
				 Gets the shortcode options.
753
				 */
754
				function sd_get_shortcode_options($this) {
755
756
					$short_code = jQuery($this).val();
757
					if ($short_code) {
758
759
						var data = {
760
							'action': 'super_duper_get_widget_settings',
761
							'shortcode': $short_code,
762
							'attributes': 123,
763
							'post_id': 321,
764
							'_ajax_nonce': '<?php echo wp_create_nonce( 'super_duper_output_shortcode' );?>'
765
						};
766
767
						if (typeof ajaxurl === 'undefined') {
768
							var ajaxurl = "<?php echo admin_url( 'admin-ajax.php' );?>";
769
						}
770
771
						jQuery.post(ajaxurl, data, function (response) {
772
							jQuery('#TB_ajaxContent .sd-shortcode-settings').html(response);
773
774
							jQuery('#' + $short_code).on('change', 'select', function () {
775
								sd_build_shortcode($short_code);
776
							}); // take care of select tags
777
778
							jQuery('#' + $short_code).on('change keypress keyup', 'input,textarea', function () {
779
								sd_build_shortcode($short_code);
780
							});
781
782
							sd_build_shortcode($short_code);
783
784
							// resize the window to fit
785
							setTimeout(function () {
786
								jQuery('#TB_ajaxContent').css('width', 'auto').css('height', '75vh');
787
							}, 200);
788
789
790
							return response;
791
						});
792
					}
793
794
				}
795
796
				/*
797
				 Builds and inserts the shortcode into the viewer.
798
				 */
799
				function sd_build_shortcode($id) {
800
801
					var multiSelects = {};
802
					var multiSelectsRemove = [];
803
804
					$output = "[" + $id;
805
806
					$form_data = jQuery("#" + $id).serializeArray();
807
808
					// run checks for multiselects
809
					jQuery.each($form_data, function (index, element) {
810
						if (element && element.value) {
811
							$field_name = element.name.substr(element.name.indexOf("][") + 2);
812
							$field_name = $field_name.replace("]", "");
813
							// check if its a multiple
814
							if ($field_name.includes("[]")) {
815
								multiSelectsRemove[multiSelectsRemove.length] = index;
816
								$field_name = $field_name.replace("[]", "");
817
								if ($field_name in multiSelects) {
818
									multiSelects[$field_name] = multiSelects[$field_name] + "," + element.value;
819
								} else {
820
									multiSelects[$field_name] = element.value;
821
								}
822
							}
823
						}
824
					});
825
826
					// fix multiselects if any are found
827
					if (multiSelectsRemove.length) {
828
829
						// remove all multiselects
830
						multiSelectsRemove.reverse();
831
						multiSelectsRemove.forEach(function (index) {
832
							$form_data.splice(index, 1);
833
						});
834
835
						$ms_arr = [];
836
						// add multiselets back
837
						jQuery.each(multiSelects, function (index, value) {
838
							$ms_arr[$ms_arr.length] = {"name": "[][" + index + "]", "value": value};
839
						});
840
						$form_data = $form_data.concat($ms_arr);
841
					}
842
843
844
					if ($form_data) {
845
						$content = '';
846
						$form_data.forEach(function (element) {
847
848
							if (element.value) {
849
								$field_name = element.name.substr(element.name.indexOf("][") + 2);
850
								$field_name = $field_name.replace("]", "");
851
								if ($field_name == 'html') {
852
									$content = element.value;
853
								} else {
854
									$output = $output + " " + $field_name + '="' + element.value + '"';
855
								}
856
							}
857
858
						});
859
					}
860
					$output = $output + "]";
861
862
					// check for content field
863
					if ($content) {
864
						$output = $output + $content + "[/" + $id + "]";
865
					}
866
867
					jQuery('#TB_ajaxContent #sd-shortcode-output').html($output);
868
				}
869
870
871
				/*
872
				 Delay the init of the textareas for 1 second.
873
				 */
874
				(function () {
875
					setTimeout(function () {
876
						sd_init_textareas();
877
					}, 1000);
878
				})();
879
880
				/*
881
				 Init the textareas to be able to show the shortcode builder button.
882
				 */
883
				function sd_init_textareas() {
884
885
					// General textareas
886
					jQuery(document).on('focus', 'textarea', function () {
887
888
						if (jQuery(this).hasClass('wp-editor-area')) {
889
							// insert the shortcode button to the textarea lable if not there already
890
							if (!jQuery(this).parent().find('.sd-lable-shortcode-inserter').length) {
891
								jQuery(this).parent().find('.quicktags-toolbar').append(sd_shortcode_button(jQuery(this).attr('id')));
892
							}
893
						} else {
894
							// insert the shortcode button to the textarea lable if not there already
895
							if (!jQuery("label[for='" + jQuery(this).attr('id') + "']").find('.sd-lable-shortcode-inserter').length) {
896
								jQuery("label[for='" + jQuery(this).attr('id') + "']").append(sd_shortcode_button(jQuery(this).attr('id')));
897
							}
898
						}
899
					});
900
901
					// The below tries to add the shortcode builder button to the builders own raw/shortcode sections.
902
903
					// DIVI
904
					jQuery(document).on('focusin', '.et-fb-codemirror', function () {
905
						// insert the shortcode button to the textarea lable if not there already
906
						if (!jQuery(this).closest('.et-fb-form__group').find('.sd-lable-shortcode-inserter').length) {
907
							jQuery(this).closest('.et-fb-form__group').find('.et-fb-form__label-text').append(sd_shortcode_button());
908
						}
909
					});
910
911
					// Beaver
912
					jQuery(document).on('focusin', '.fl-code-field', function () {
913
						// insert the shortcode button to the textarea lable if not there already
914
						if (!jQuery(this).closest('.fl-field-control-wrapper').find('.sd-lable-shortcode-inserter').length) {
915
							jQuery(this).closest('.fl-field-control-wrapper').prepend(sd_shortcode_button());
916
						}
917
					});
918
919
					// Fushion builder (avada)
920
					jQuery(document).on('focusin', '.CodeMirror.cm-s-default', function () {
921
						// insert the shortcode button to the textarea lable if not there already
922
						if (!jQuery(this).parent().find('.sd-lable-shortcode-inserter').length) {
923
							jQuery(sd_shortcode_button()).insertBefore(this);
924
						}
925
					});
926
927
					// Avia builder (enfold)
928
					jQuery(document).on('focusin', '#aviaTBcontent', function () {
929
						// insert the shortcode button to the textarea lable if not there already
930
						if (!jQuery(this).parent().parent().find('.avia-name-description ').find('.sd-lable-shortcode-inserter').length) {
931
							jQuery(this).parent().parent().find('.avia-name-description strong').append(sd_shortcode_button(jQuery(this).attr('id')));
932
						}
933
					});
934
935
					// Cornerstone textareas
936
					jQuery(document).on('focusin', '.cs-control.cs-control-textarea', function () {
937
						// insert the shortcode button to the textarea lable if not there already
938
						if (!jQuery(this).find('.cs-control-header label').find('.sd-lable-shortcode-inserter').length) {
939
							jQuery(this).find('.cs-control-header label').append(sd_shortcode_button());
940
						}
941
					});
942
943
					// Cornerstone main bar
944
					setTimeout(function () {
945
						// insert the shortcode button to the textarea lable if not there already
946
						if (!jQuery('.cs-bar-btns').find('.sd-lable-shortcode-inserter').length) {
947
							jQuery('<li style="text-align: center;padding: 5px;list-style: none;">' + sd_shortcode_button() + '</li>').insertBefore('.cs-action-toggle-custom-css');
948
						}
949
					}, 2000);
950
951
952
					// WP Bakery, code editor does not render shortcodes.
953
//					jQuery(document).on('focusin', '.wpb-textarea_raw_html', function () {
954
//						// insert the shortcode button to the textarea lable if not there already
955
//						if(!jQuery(this).parent().parent().find('.wpb_element_label').find('.sd-lable-shortcode-inserter').length){
956
//							jQuery(this).parent().parent().find('.wpb_element_label').append(sd_shortcode_button());
957
//						}
958
//					});
959
960
				}
961
962
				/**
963
				 * Gets the html for the picker via ajax and updates it on the fly.
964
				 *
965
				 * @param $id
966
				 * @param $search
967
				 */
968
				function sd_ajax_get_picker($id, $search) {
969
					if ($search) {
970
						$this = $id;
971
						$id = jQuery($this).closest('.wp-editor-wrap').find('.wp-editor-container textarea').attr('id');
972
					}
973
974
					var data = {
975
						'action': 'super_duper_get_picker',
976
						'editor_id': $id,
977
						'_ajax_nonce': '<?php echo wp_create_nonce( 'super_duper_picker' );?>'
978
					};
979
980
					if (!ajaxurl) {
981
						var ajaxurl = "<?php echo admin_url( 'admin-ajax.php' ); ?>";
982
					}
983
984
					jQuery.post(ajaxurl, data, function (response) {
985
						jQuery('#TB_ajaxContent').html(response);
986
						//return response;
987
					}).then(function (env) {
988
						jQuery('body').on('thickbox:removed', function () {
989
							jQuery('#super-duper-content-ajaxed').html('');
990
						});
991
					});
992
				}
993
994
				/**
995
				 * Get the html for the shortcode inserter button depending on if a textarea id is available.
996
				 *
997
				 * @param $id string The textarea id.
998
				 * @returns {string}
999
				 */
1000
				function sd_shortcode_button($id) {
1001
					if ($id) {
1002
						return '<?php echo self::shortcode_button( "\\''+\$id+'\\'" );?>';
1003
					} else {
1004
						return '<?php echo self::shortcode_button();?>';
1005
					}
1006
				}
1007
1008
			</script>
1009
			<?php
1010
		}
1011
1012
		/**
1013
		 * Gets some CSS for the widgets screen.
1014
		 *
1015
		 * @param bool $advanced If we should include advanced CSS.
1016
		 *
1017
		 * @return mixed
1018
		 */
1019
		public function widget_css( $advanced = true ) {
1020
			ob_start();
1021
			?>
1022
			<style>
1023
				<?php if( $advanced ){ ?>
1024
				.sd-advanced-setting {
1025
					display: none;
1026
				}
1027
1028
				.sd-advanced-setting.sd-adv-show {
1029
					display: block;
1030
				}
1031
1032
				.sd-argument.sd-require-hide,
1033
				.sd-advanced-setting.sd-require-hide {
1034
					display: none;
1035
				}
1036
1037
				button.sd-advanced-button {
1038
					margin-right: 3px !important;
1039
					font-size: 20px !important;
1040
				}
1041
1042
				<?php } ?>
1043
1044
				button.sd-toggle-group-button {
1045
					background-color: #f3f3f3;
1046
					color: #23282d;
1047
					cursor: pointer;
1048
					padding: 10px;
1049
					width: 100%;
1050
					border: none;
1051
					text-align: left;
1052
					outline: none;
1053
					font-size: 13px;
1054
					font-weight: bold;
1055
					margin-bottom: 1px;
1056
				}
1057
			</style>
1058
			<?php
1059
			$output = ob_get_clean();
1060
1061
			/*
1062
			 * We only add the <script> tags for code highlighting, so we strip them from the output.
1063
			 */
1064
1065
			return str_replace( array(
1066
				'<style>',
1067
				'</style>'
1068
			), '', $output );
1069
		}
1070
1071
		/**
1072
		 * Gets some JS for the widgets screen.
1073
		 *
1074
		 * @return mixed
1075
		 */
1076
		public function widget_js() {
1077
			ob_start();
1078
			?>
1079
			<script>
1080
1081
				/**
1082
				 * Toggle advanced settings visibility.
1083
				 */
1084
				function sd_toggle_advanced($this) {
1085
					var form = jQuery($this).parents('form,.form');
1086
					form.find('.sd-advanced-setting').toggleClass('sd-adv-show');
1087
					return false;// prevent form submit
1088
				}
1089
1090
				/**
1091
				 * Check a form to see what items should be shown or hidden.
1092
				 */
1093
				function sd_show_hide(form) {
1094
					console.log('show/hide');
1095
					jQuery(form).find(".sd-argument").each(function () {
1096
1097
						var $element_require = jQuery(this).data('element_require');
1098
1099
						if ($element_require) {
1100
1101
							$element_require = $element_require.replace("&#039;", "'"); // replace single quotes
1102
							$element_require = $element_require.replace("&quot;", '"'); // replace double quotes
1103
1104
							if (eval($element_require)) {
1105
								jQuery(this).removeClass('sd-require-hide');
1106
							} else {
1107
								jQuery(this).addClass('sd-require-hide');
1108
							}
1109
						}
1110
					});
1111
				}
1112
1113
				/**
1114
				 * Initialise widgets from the widgets screen.
1115
				 */
1116
				function sd_init_widgets($selector) {
1117
					jQuery(".sd-show-advanced").each(function (index) {
1118
						sd_init_widget(this, $selector);
1119
					});
1120
				}
1121
1122
				/**
1123
				 * Initialise a individual widget.
1124
				 */
1125
				function sd_init_widget($this, $selector) {
1126
					console.log($selector);
1127
1128
					if (!$selector) {
1129
						$selector = 'form';
1130
					}
1131
					// only run once.
1132
					if (jQuery($this).data('sd-widget-enabled')) {
1133
						return;
1134
					} else {
1135
						jQuery($this).data('sd-widget-enabled', true);
1136
					}
1137
1138
					var $button = '<button title="<?php _e( 'Advanced Settings' );?>" style="line-height: 28px;" class="button button-primary right sd-advanced-button" onclick="sd_toggle_advanced(this);return false;"><span class="dashicons dashicons-admin-settings" style="width: 28px;font-size: 28px;"></span></button>';
1139
					var form = jQuery($this).parents('' + $selector + '');
1140
1141
					if (jQuery($this).val() == '1' && jQuery(form).find('.sd-advanced-button').length == 0) {
1142
						console.log('add advanced button');
1143
						if(jQuery(form).find('.widget-control-save').length > 0){
1144
							jQuery(form).find('.widget-control-save').after($button);
1145
						}else{
1146
							jQuery(form).find('.sd-show-advanced').after($button);
1147
						}
1148
					} else {
1149
						console.log('no advanced button');
1150
						console.log(jQuery($this).val());
1151
						console.log(jQuery(form).find('.sd-advanced-button').length);
1152
1153
					}
1154
1155
					// show hide on form change
1156
					jQuery(form).on("change", function () {
1157
						sd_show_hide(form);
1158
					});
1159
1160
					// show hide on load
1161
					sd_show_hide(form);
1162
				}
1163
1164
				/**
1165
				 * Init a customizer widget.
1166
				 */
1167
				function sd_init_customizer_widget(section) {
1168
					if (section.expanded) {
1169
						section.expanded.bind(function (isExpanding) {
1170
							if (isExpanding) {
1171
								// is it a SD widget?
1172
								if (jQuery(section.container).find('.sd-show-advanced').length) {
1173
									// init the widget
1174
									sd_init_widget(jQuery(section.container).find('.sd-show-advanced'), ".form");
1175
								}
1176
							}
1177
						});
1178
					}
1179
				}
1180
1181
				/**
1182
				 * If on widgets screen.
1183
				 */
1184
				jQuery(function () {
1185
					// if not in customizer.
1186
					if (!wp.customize) {
1187
						sd_init_widgets("form");
1188
					}
1189
1190
					// init on widget added
1191
					jQuery(document).on('widget-added', function (e, widget) {
1192
						console.log('widget added');
1193
						// is it a SD widget?
1194
						if (jQuery(widget).find('.sd-show-advanced').length) {
1195
							// init the widget
1196
							sd_init_widget(jQuery(widget).find('.sd-show-advanced'), "form");
1197
						}
1198
					});
1199
1200
					// init on widget updated
1201
					jQuery(document).on('widget-updated', function (e, widget) {
1202
						console.log('widget updated');
1203
1204
						// is it a SD widget?
1205
						if (jQuery(widget).find('.sd-show-advanced').length) {
1206
							// init the widget
1207
							sd_init_widget(jQuery(widget).find('.sd-show-advanced'), "form");
1208
						}
1209
					});
1210
1211
				});
1212
1213
1214
				/**
1215
				 * We need to run this before jQuery is ready
1216
				 */
1217
				if (wp.customize) {
1218
					wp.customize.bind('ready', function () {
1219
1220
						// init widgets on load
1221
						wp.customize.control.each(function (section) {
1222
							sd_init_customizer_widget(section);
1223
						});
1224
1225
						// init widgets on add
1226
						wp.customize.control.bind('add', function (section) {
1227
							sd_init_customizer_widget(section);
1228
						});
1229
1230
					});
1231
1232
				}
1233
				<?php do_action( 'wp_super_duper_widget_js', $this ); ?>
1234
			</script>
1235
			<?php
1236
			$output = ob_get_clean();
1237
1238
			/*
1239
			 * We only add the <script> tags for code highlighting, so we strip them from the output.
1240
			 */
1241
1242
			return str_replace( array(
1243
				'<script>',
1244
				'</script>'
1245
			), '', $output );
1246
		}
1247
1248
1249
		/**
1250
		 * Set the name from the argument key.
1251
		 *
1252
		 * @param $options
1253
		 *
1254
		 * @return mixed
1255
		 */
1256
		private function add_name_from_key( $options, $arguments = false ) {
1257
			if ( ! empty( $options['arguments'] ) ) {
1258
				foreach ( $options['arguments'] as $key => $val ) {
1259
					$options['arguments'][ $key ]['name'] = $key;
1260
				}
1261
			} elseif ( $arguments && is_array( $options ) && ! empty( $options ) ) {
1262
				foreach ( $options as $key => $val ) {
1263
					$options[ $key ]['name'] = $key;
1264
				}
1265
			}
1266
1267
			return $options;
1268
		}
1269
1270
		/**
1271
		 * Register the parent shortcode.
1272
		 *
1273
		 * @since 1.0.0
1274
		 */
1275
		public function register_shortcode() {
1276
			add_shortcode( $this->base_id, array( $this, 'shortcode_output' ) );
1277
			add_action( 'wp_ajax_super_duper_output_shortcode', array( __CLASS__, 'render_shortcode' ) );
1278
		}
1279
1280
		/**
1281
		 * Render the shortcode via ajax so we can return it to Gutenberg.
1282
		 *
1283
		 * @since 1.0.0
1284
		 */
1285
		public static function render_shortcode() {
1286
1287
			check_ajax_referer( 'super_duper_output_shortcode', '_ajax_nonce', true );
1288
			if ( ! current_user_can( 'manage_options' ) ) {
1289
				wp_die();
1290
			}
1291
1292
			// we might need the $post value here so lets set it.
1293
			if ( isset( $_POST['post_id'] ) && $_POST['post_id'] ) {
1294
				$post_obj = get_post( absint( $_POST['post_id'] ) );
1295
				if ( ! empty( $post_obj ) && empty( $post ) ) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $post seems to never exist and therefore empty should always be true.
Loading history...
1296
					global $post;
1297
					$post = $post_obj;
1298
				}
1299
			}
1300
1301
			if ( isset( $_POST['shortcode'] ) && $_POST['shortcode'] ) {
1302
				$shortcode_name   = sanitize_title_with_dashes( $_POST['shortcode'] );
1303
				$attributes_array = isset( $_POST['attributes'] ) && $_POST['attributes'] ? $_POST['attributes'] : array();
1304
				$attributes       = '';
1305
				if ( ! empty( $attributes_array ) ) {
1306
					foreach ( $attributes_array as $key => $value ) {
1307
						if ( is_array( $value ) ) {
1308
							$value = implode( ",", $value );
1309
						}
1310
						$attributes .= " " . sanitize_title_with_dashes( $key ) . "='" . wp_slash( $value ) . "' ";
1311
					}
1312
				}
1313
1314
				$shortcode = "[" . $shortcode_name . " " . $attributes . "]";
1315
1316
				echo do_shortcode( $shortcode );
0 ignored issues
show
Security Cross-Site Scripting introduced by
do_shortcode($shortcode) can contain request data and is used in output context(s) leading to a potential security vulnerability.

2 paths for user data to reach this point

  1. Path: Read from $_POST, and Data is passed through sanitize_title_with_dashes(), and sanitize_title_with_dashes($_POST['shortcode']) is assigned to $shortcode_name in vendor/ayecode/wp-super-duper/wp-super-duper.php on line 1302
  1. Read from $_POST, and Data is passed through sanitize_title_with_dashes(), and sanitize_title_with_dashes($_POST['shortcode']) is assigned to $shortcode_name
    in vendor/ayecode/wp-super-duper/wp-super-duper.php on line 1302
  2. '[' . $shortcode_name . ' ' . $attributes . ']' is assigned to $shortcode
    in vendor/ayecode/wp-super-duper/wp-super-duper.php on line 1314
  3. Data is passed through do_shortcode()
    in vendor/ayecode/wp-super-duper/wp-super-duper.php on line 1316
  2. Path: Read from $_POST, and IssetNode && $_POST['attributes'] ? $_POST['attributes'] : array() is assigned to $attributes_array in vendor/ayecode/wp-super-duper/wp-super-duper.php on line 1303
  1. Read from $_POST, and IssetNode && $_POST['attributes'] ? $_POST['attributes'] : array() is assigned to $attributes_array
    in vendor/ayecode/wp-super-duper/wp-super-duper.php on line 1303
  2. $attributes_array is assigned to $key
    in vendor/ayecode/wp-super-duper/wp-super-duper.php on line 1306
  3. Data is passed through sanitize_title_with_dashes(), and ' ' . sanitize_title_with_dashes($key) . '='' . wp_slash($value) . '' ' is assigned to $attributes
    in vendor/ayecode/wp-super-duper/wp-super-duper.php on line 1310
  4. '[' . $shortcode_name . ' ' . $attributes . ']' is assigned to $shortcode
    in vendor/ayecode/wp-super-duper/wp-super-duper.php on line 1314
  5. Data is passed through do_shortcode()
    in vendor/ayecode/wp-super-duper/wp-super-duper.php on line 1316

Preventing Cross-Site-Scripting Attacks

Cross-Site-Scripting allows an attacker to inject malicious code into your website - in particular Javascript code, and have that code executed with the privileges of a visiting user. This can be used to obtain data, or perform actions on behalf of that visiting user.

In order to prevent this, make sure to escape all user-provided data:

// for HTML
$sanitized = htmlentities($tainted, ENT_QUOTES);

// for URLs
$sanitized = urlencode($tainted);

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
1317
1318
			}
1319
			wp_die();
1320
		}
1321
1322
		/**
1323
		 * Output the shortcode.
1324
		 *
1325
		 * @param array $args
1326
		 * @param string $content
1327
		 *
1328
		 * @return string
1329
		 */
1330
		public function shortcode_output( $args = array(), $content = '' ) {
1331
			$args = $this->argument_values( $args );
1332
1333
			// add extra argument so we know its a output to gutenberg
1334
			//$args
1335
			$args = $this->string_to_bool( $args );
1336
1337
			// if we have a enclosed shortcode we add it to the special `html` argument
1338
			if ( ! empty( $content ) ) {
1339
				$args['html'] = $content;
1340
			}
1341
1342
			$class = isset( $this->options['widget_ops']['classname'] ) ? esc_attr( $this->options['widget_ops']['classname'] ) : '';
1343
			$class .= " sdel-".$this->get_instance_hash();
1344
1345
			$class = apply_filters( 'wp_super_duper_div_classname', $class, $args, $this );
1346
			$class = apply_filters( 'wp_super_duper_div_classname_' . $this->base_id, $class, $args, $this );
1347
1348
			$attrs = apply_filters( 'wp_super_duper_div_attrs', '', $args, $this );
0 ignored issues
show
Unused Code introduced by
The assignment to $attrs is dead and can be removed.
Loading history...
1349
			$attrs = apply_filters( 'wp_super_duper_div_attrs_' . $this->base_id, '', $args, $this );
1350
1351
			$shortcode_args = array();
1352
			$output         = '';
1353
			$no_wrap        = isset( $this->options['no_wrap'] ) && $this->options['no_wrap'] ? true : false;
1354
			if ( isset( $args['no_wrap'] ) && $args['no_wrap'] ) {
1355
				$no_wrap = true;
1356
			}
1357
			$main_content = $this->output( $args, $shortcode_args, $content );
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $main_content is correct as $this->output($args, $shortcode_args, $content) targeting WP_Super_Duper::output() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
1358
			if ( $main_content && ! $no_wrap ) {
0 ignored issues
show
introduced by
$main_content is defined implicitly as null, thus it is always evaluated to false.
Loading history...
1359
				// wrap the shortcode in a div with the same class as the widget
1360
				$output .= '<div class="' . $class . '" ' . $attrs . '>';
1361
				if ( ! empty( $args['title'] ) ) {
1362
					// if its a shortcode and there is a title try to grab the title wrappers
1363
					$shortcode_args = array( 'before_title' => '', 'after_title' => '' );
1364
					if ( empty( $instance ) ) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $instance seems to never exist and therefore empty should always be true.
Loading history...
1365
						global $wp_registered_sidebars;
1366
						if ( ! empty( $wp_registered_sidebars ) ) {
1367
							foreach ( $wp_registered_sidebars as $sidebar ) {
1368
								if ( ! empty( $sidebar['before_title'] ) ) {
1369
									$shortcode_args['before_title'] = $sidebar['before_title'];
1370
									$shortcode_args['after_title']  = $sidebar['after_title'];
1371
									break;
1372
								}
1373
							}
1374
						}
1375
					}
1376
					$output .= $this->output_title( $shortcode_args, $args );
1377
				}
1378
				$output .= $main_content;
1379
				$output .= '</div>';
1380
			} elseif ( $main_content && $no_wrap ) {
0 ignored issues
show
introduced by
$main_content is defined implicitly as null, thus it is always evaluated to false.
Loading history...
1381
				$output .= $main_content;
1382
			}
1383
1384
			// if preview show a placeholder if empty
1385
			if ( $this->is_preview() && $output == '' ) {
1386
				$output = $this->preview_placeholder_text( "{{" . $this->base_id . "}}" );
1387
			}
1388
1389
			return apply_filters( 'wp_super_duper_widget_output', $output, $args, $shortcode_args, $this );
1390
		}
1391
1392
		/**
1393
		 * Placeholder text to show if output is empty and we are on a preview/builder page.
1394
		 *
1395
		 * @param string $name
1396
		 *
1397
		 * @return string
1398
		 */
1399
		public function preview_placeholder_text( $name = '' ) {
1400
			return "<div style='background:#0185ba33;padding: 10px;border: 4px #ccc dashed;'>" . sprintf( __( 'Placeholder for: %s' ), $name ) . "</div>";
1401
		}
1402
1403
		/**
1404
		 * Sometimes booleans values can be turned to strings, so we fix that.
1405
		 *
1406
		 * @param $options
1407
		 *
1408
		 * @return mixed
1409
		 */
1410
		public function string_to_bool( $options ) {
1411
			// convert bool strings to booleans
1412
			foreach ( $options as $key => $val ) {
1413
				if ( $val == 'false' ) {
1414
					$options[ $key ] = false;
1415
				} elseif ( $val == 'true' ) {
1416
					$options[ $key ] = true;
1417
				}
1418
			}
1419
1420
			return $options;
1421
		}
1422
1423
		/**
1424
		 * Get the argument values that are also filterable.
1425
		 *
1426
		 * @param $instance
1427
		 *
1428
		 * @since 1.0.12 Don't set checkbox default value if the value is empty.
1429
		 *
1430
		 * @return array
1431
		 */
1432
		public function argument_values( $instance ) {
1433
			$argument_values = array();
1434
1435
			// set widget instance
1436
			$this->instance = $instance;
1437
1438
			if ( empty( $this->arguments ) ) {
1439
				$this->arguments = $this->get_arguments();
1440
			}
1441
1442
			if ( ! empty( $this->arguments ) ) {
1443
				foreach ( $this->arguments as $key => $args ) {
1444
					// set the input name from the key
1445
					$args['name'] = $key;
1446
					//
1447
					$argument_values[ $key ] = isset( $instance[ $key ] ) ? $instance[ $key ] : '';
1448
					if ( $args['type'] == 'checkbox' && $argument_values[ $key ] == '' ) {
1449
						// don't set default for an empty checkbox
1450
					} elseif ( $argument_values[ $key ] == '' && isset( $args['default'] ) ) {
1451
						$argument_values[ $key ] = $args['default'];
1452
					}
1453
				}
1454
			}
1455
1456
			return $argument_values;
1457
		}
1458
1459
		/**
1460
		 * Set arguments in super duper.
1461
		 *
1462
		 * @since 1.0.0
1463
		 *
1464
		 * @return array Set arguments.
1465
		 */
1466
		public function set_arguments() {
1467
			return $this->arguments;
1468
		}
1469
1470
		/**
1471
		 * Get arguments in super duper.
1472
		 *
1473
		 * @since 1.0.0
1474
		 *
1475
		 * @return array Get arguments.
1476
		 */
1477
		public function get_arguments() {
1478
			if ( empty( $this->arguments ) ) {
1479
				$this->arguments = $this->set_arguments();
1480
			}
1481
1482
			$this->arguments = apply_filters( 'wp_super_duper_arguments', $this->arguments, $this->options, $this->instance );
1483
			$this->arguments = $this->add_name_from_key( $this->arguments, true );
1484
1485
			return $this->arguments;
1486
		}
1487
1488
		/**
1489
		 * This is the main output class for all 3 items, widget, shortcode and block, it is extended in the calling class.
1490
		 *
1491
		 * @param array $args
1492
		 * @param array $widget_args
1493
		 * @param string $content
1494
		 */
1495
		public function output( $args = array(), $widget_args = array(), $content = '' ) {
0 ignored issues
show
Unused Code introduced by
The parameter $widget_args is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

1495
		public function output( $args = array(), /** @scrutinizer ignore-unused */ $widget_args = array(), $content = '' ) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1496
1497
		}
1498
1499
		/**
1500
		 * Add the dynamic block code inline when the wp-block in enqueued.
1501
		 */
1502
		public function register_block() {
1503
			wp_add_inline_script( 'wp-blocks', $this->block() );
1504
			if ( class_exists( 'SiteOrigin_Panels' ) ) {
1505
				wp_add_inline_script( 'wp-blocks', $this->siteorigin_js() );
1506
			}
1507
		}
1508
1509
		/**
1510
		 * Check if we need to show advanced options.
1511
		 *
1512
		 * @return bool
1513
		 */
1514
		public function block_show_advanced() {
1515
1516
			$show      = false;
1517
			$arguments = $this->arguments;
1518
1519
			if ( empty( $arguments ) ) {
1520
				$arguments = $this->get_arguments();
1521
			}
1522
1523
			if ( ! empty( $arguments ) ) {
1524
				foreach ( $arguments as $argument ) {
1525
					if ( isset( $argument['advanced'] ) && $argument['advanced'] ) {
1526
						$show = true;
1527
						break; // no need to continue if we know we have it
1528
					}
1529
				}
1530
			}
1531
1532
			return $show;
1533
		}
1534
1535
		/**
1536
		 * Get the url path to the current folder.
1537
		 *
1538
		 * @return string
1539
		 */
1540
		public function get_url() {
1541
1542
			$url = $this->url;
1543
1544
			if ( ! $url ) {
1545
				// check if we are inside a plugin
1546
				$file_dir = str_replace( "/includes", "", dirname( __FILE__ ) );
1547
1548
				$dir_parts = explode( "/wp-content/", $file_dir );
1549
				$url_parts = explode( "/wp-content/", plugins_url() );
1550
1551
				if ( ! empty( $url_parts[0] ) && ! empty( $dir_parts[1] ) ) {
1552
					$url       = trailingslashit( $url_parts[0] . "/wp-content/" . $dir_parts[1] );
1553
					$this->url = $url;
1554
				}
1555
			}
1556
1557
1558
			return $url;
1559
		}
1560
1561
		/**
1562
		 * Generate the block icon.
1563
		 *
1564
		 * Enables the use of Font Awesome icons.
1565
		 *
1566
		 * @note xlink:href is actually deprecated but href is not supported by all so we use both.
1567
		 *
1568
		 * @param $icon
1569
		 *
1570
		 * @since 1.1.0
1571
		 * @return string
1572
		 */
1573
		public function get_block_icon( $icon ) {
1574
1575
			// check if we have a Font Awesome icon
1576
			$fa_type = '';
1577
			if ( substr( $icon, 0, 7 ) === "fas fa-" ) {
1578
				$fa_type = 'solid';
1579
			} elseif ( substr( $icon, 0, 7 ) === "far fa-" ) {
1580
				$fa_type = 'regular';
1581
			} elseif ( substr( $icon, 0, 7 ) === "fab fa-" ) {
1582
				$fa_type = 'brands';
1583
			} else {
1584
				$icon = "'" . $icon . "'";
1585
			}
1586
1587
			// set the icon if we found one
1588
			if ( $fa_type ) {
1589
				$fa_icon = str_replace( array( "fas fa-", "far fa-", "fab fa-" ), "", $icon );
1590
				$icon    = "el('svg',{width: 20, height: 20, viewBox: '0 0 20 20'},el('use', {'xlink:href': '" . $this->get_url() . "icons/" . $fa_type . ".svg#" . $fa_icon . "','href': '" . $this->get_url() . "icons/" . $fa_type . ".svg#" . $fa_icon . "'}))";
1591
			}
1592
1593
			return $icon;
1594
		}
1595
1596
		public function group_arguments( $arguments ) {
1597
//			echo '###';print_r($arguments);
1598
			if ( ! empty( $arguments ) ) {
1599
				$temp_arguments = array();
1600
				$general        = __( "General" );
1601
				$add_sections   = false;
1602
				foreach ( $arguments as $key => $args ) {
1603
					if ( isset( $args['group'] ) ) {
1604
						$temp_arguments[ $args['group'] ][ $key ] = $args;
1605
						$add_sections                             = true;
1606
					} else {
1607
						$temp_arguments[ $general ][ $key ] = $args;
1608
					}
1609
				}
1610
1611
				// only add sections if more than one
1612
				if ( $add_sections ) {
1613
					$arguments = $temp_arguments;
1614
				}
1615
			}
1616
1617
//			echo '###';print_r($arguments);
1618
			return $arguments;
1619
		}
1620
1621
1622
		/**
1623
		 * Output the JS for building the dynamic Guntenberg block.
1624
		 *
1625
		 * @since 1.0.4 Added block_wrap property which will set the block wrapping output element ie: div, span, p or empty for no wrap.
1626
		 * @since 1.0.9 Save numbers as numbers and not strings.
1627
		 * @since 1.1.0 Font Awesome classes can be used for icons.
1628
		 * @return mixed
1629
		 */
1630
		public function block() {
1631
			ob_start();
1632
1633
			$show_advanced = $this->block_show_advanced();
1634
			?>
1635
			<script>
1636
				/**
1637
				 * BLOCK: Basic
1638
				 *
1639
				 * Registering a basic block with Gutenberg.
1640
				 * Simple block, renders and saves the same content without any interactivity.
1641
				 *
1642
				 * Styles:
1643
				 *        editor.css — Editor styles for the block.
1644
				 *        style.css  — Editor & Front end styles for the block.
1645
				 */
1646
				(function () {
1647
					var __ = wp.i18n.__; // The __() for internationalization.
1648
					var el = wp.element.createElement; // The wp.element.createElement() function to create elements.
1649
					var editable = wp.blocks.Editable;
1650
					var blocks = wp.blocks;
1651
					var registerBlockType = wp.blocks.registerBlockType; // The registerBlockType() to register blocks.
1652
					var is_fetching = false;
1653
					var prev_attributes = [];
1654
1655
					var term_query_type = '';
1656
					var post_type_rest_slugs = <?php if(! empty( $this->arguments ) && isset($this->arguments['post_type']['onchange_rest']['values'])){echo "[".json_encode($this->arguments['post_type']['onchange_rest']['values'])."]";}else{echo "[]";} ?>;
1657
					const taxonomies_<?php echo str_replace("-","_", $this->id);?> = [{label: "Please wait", value: 0}];
1658
					const sort_by_<?php echo str_replace("-","_", $this->id);?> = [{label: "Please wait", value: 0}];
1659
1660
					/**
1661
					 * Register Basic Block.
1662
					 *
1663
					 * Registers a new block provided a unique name and an object defining its
1664
					 * behavior. Once registered, the block is made available as an option to any
1665
					 * editor interface where blocks are implemented.
1666
					 *
1667
					 * @param  {string}   name     Block name.
1668
					 * @param  {Object}   settings Block settings.
1669
					 * @return {?WPBlock}          The block, if it has been successfully
1670
					 *                             registered; otherwise `undefined`.
1671
					 */
1672
					registerBlockType('<?php echo str_replace( "_", "-", sanitize_title_with_dashes( $this->options['textdomain'] ) . '/' . sanitize_title_with_dashes( $this->options['class_name'] ) );  ?>', { // Block name. Block names must be string that contains a namespace prefix. Example: my-plugin/my-custom-block.
1673
						title: '<?php echo addslashes( $this->options['name'] ); ?>', // Block title.
1674
						description: '<?php echo addslashes( $this->options['widget_ops']['description'] )?>', // Block title.
1675
						icon: <?php echo $this->get_block_icon( $this->options['block-icon'] );?>,//'<?php echo isset( $this->options['block-icon'] ) ? esc_attr( $this->options['block-icon'] ) : 'shield-alt';?>', // Block icon from Dashicons → https://developer.wordpress.org/resource/dashicons/.
1676
						supports: {
1677
							<?php
1678
							if ( isset( $this->options['block-supports'] ) ) {
1679
								echo $this->array_to_attributes( $this->options['block-supports'] );
1680
							}
1681
							?>
1682
						},
1683
						category: '<?php echo isset( $this->options['block-category'] ) ? esc_attr( $this->options['block-category'] ) : 'common';?>', // Block category — Group blocks together based on common traits E.g. common, formatting, layout widgets, embed.
1684
						<?php if ( isset( $this->options['block-keywords'] ) ) {
1685
						echo "keywords : " . $this->options['block-keywords'] . ",";
1686
					}?>
1687
1688
						<?php
1689
1690
						// maybe set no_wrap
1691
						$no_wrap = isset( $this->options['no_wrap'] ) && $this->options['no_wrap'] ? true : false;
1692
						if ( isset( $this->arguments['no_wrap'] ) && $this->arguments['no_wrap'] ) {
1693
							$no_wrap = true;
1694
						}
1695
						if ( $no_wrap ) {
1696
							$this->options['block-wrap'] = '';
1697
						}
1698
1699
1700
1701
						$show_alignment = false;
1702
						// align feature
1703
						/*echo "supports: {";
1704
						echo "	align: true,";
1705
						echo "  html: false";
1706
						echo "},";*/
1707
1708
						if ( ! empty( $this->arguments ) ) {
1709
							echo "attributes : {";
1710
1711
							if ( $show_advanced ) {
1712
								echo "show_advanced: {";
1713
								echo "	type: 'boolean',";
1714
								echo "  default: false,";
1715
								echo "},";
1716
							}
1717
1718
							// block wrap element
1719
							if ( ! empty( $this->options['block-wrap'] ) ) { //@todo we should validate this?
1720
								echo "block_wrap: {";
1721
								echo "	type: 'string',";
1722
								echo "  default: '" . esc_attr( $this->options['block-wrap'] ) . "',";
1723
								echo "},";
1724
							}
1725
1726
							foreach ( $this->arguments as $key => $args ) {
1727
1728
								// set if we should show alignment
1729
								if ( $key == 'alignment' ) {
1730
									$show_alignment = true;
1731
								}
1732
1733
								$extra = '';
0 ignored issues
show
Unused Code introduced by
The assignment to $extra is dead and can be removed.
Loading history...
1734
1735
								if ( $args['type'] == 'checkbox' ) {
1736
									$type    = 'boolean';
1737
									$default = isset( $args['default'] ) && $args['default'] ? 'true' : 'false';
1738
								} elseif ( $args['type'] == 'number' ) {
1739
									$type    = 'number';
1740
									$default = isset( $args['default'] ) ? "'" . $args['default'] . "'" : "''";
1741
								} elseif ( $args['type'] == 'select' && ! empty( $args['multiple'] ) ) {
1742
									$type = 'array';
1743
									if ( isset( $args['default'] ) && is_array( $args['default'] ) ) {
1744
										$default = ! empty( $args['default'] ) ? "['" . implode( "','", $args['default'] ) . "']" : "[]";
1745
									} else {
1746
										$default = isset( $args['default'] ) ? "'" . $args['default'] . "'" : "''";
1747
									}
1748
								} elseif ( $args['type'] == 'multiselect' ) {
1749
									$type    = 'array';
1750
									$default = isset( $args['default'] ) ? "'" . $args['default'] . "'" : "''";
1751
								} else {
1752
									$type    = 'string';
1753
									$default = isset( $args['default'] ) ? "'" . $args['default'] . "'" : "''";
1754
								}
1755
								echo $key . " : {";
1756
								echo "type : '$type',";
1757
								echo "default : $default,";
1758
								echo "},";
1759
							}
1760
1761
							echo "content : {type : 'string',default: 'Please select the attributes in the block settings'},";
1762
							echo "className: { type: 'string', default: '' },";
1763
1764
							echo "},";
1765
1766
						}
1767
1768
						?>
1769
1770
						// The "edit" property must be a valid function.
1771
						edit: function (props) {
1772
1773
1774
							var $value = '';
1775
							<?php
1776
							// if we have a post_type and a category then link them
1777
							if( isset($this->arguments['post_type']) && isset($this->arguments['category']) && !empty($this->arguments['category']['post_type_linked']) ){
1778
							?>
1779
							if(typeof(prev_attributes[props.id]) != 'undefined' ){
1780
								$pt = props.attributes.post_type;
1781
								if(post_type_rest_slugs.length){
1782
									$value = post_type_rest_slugs[0][$pt];
1783
								}
1784
								var run = false;
1785
1786
								if($pt != term_query_type){
1787
									run = true;
1788
									term_query_type = $pt;
1789
								}
1790
1791
								// taxonomies
1792
								if( $value && 'post_type' in prev_attributes[props.id] && 'category' in prev_attributes[props.id] && run ){
1793
									wp.apiFetch({path: "<?php if(isset($this->arguments['post_type']['onchange_rest']['path'])){echo $this->arguments['post_type']['onchange_rest']['path'];}else{'/wp/v2/"+$value+"/categories/?per_page=100';} ?>"}).then(terms => {
1794
										while (taxonomies_<?php echo str_replace("-","_", $this->id);?>.length) {
1795
										taxonomies_<?php echo str_replace("-","_", $this->id);?>.pop();
1796
									}
1797
									taxonomies_<?php echo str_replace("-","_", $this->id);?>.push({label: "All", value: 0});
1798
									jQuery.each( terms, function( key, val ) {
1799
										taxonomies_<?php echo str_replace("-","_", $this->id);?>.push({label: val.name, value: val.id});
1800
									});
1801
1802
									// setting the value back and fourth fixes the no update issue that sometimes happens where it won't update the options.
1803
									var $old_cat_value = props.attributes.category
1804
									props.setAttributes({category: [0] });
1805
									props.setAttributes({category: $old_cat_value });
1806
1807
									return taxonomies_<?php echo str_replace("-","_", $this->id);?>;
1808
								});
1809
								}
1810
1811
								// sort_by
1812
								if( $value && 'post_type' in prev_attributes[props.id] && 'sort_by' in prev_attributes[props.id] && run ){
1813
									var data = {
1814
										'action': 'geodir_get_sort_options',
1815
										'post_type': $pt
1816
									};
1817
									jQuery.post(ajaxurl, data, function(response) {
1818
										response = JSON.parse(response);
1819
										while (sort_by_<?php echo str_replace("-","_", $this->id);?>.length) {
1820
											sort_by_<?php echo str_replace("-","_", $this->id);?>.pop();
1821
										}
1822
1823
										jQuery.each( response, function( key, val ) {
1824
											sort_by_<?php echo str_replace("-","_", $this->id);?>.push({label: val, value: key});
1825
										});
1826
1827
										// setting the value back and fourth fixes the no update issue that sometimes happens where it won't update the options.
1828
										var $old_sort_by_value = props.attributes.sort_by
1829
										props.setAttributes({sort_by: [0] });
1830
										props.setAttributes({sort_by: $old_sort_by_value });
1831
1832
										return sort_by_<?php echo str_replace("-","_", $this->id);?>;
1833
									});
1834
1835
								}
1836
							}
1837
							<?php }?>
1838
1839
1840
							var content = props.attributes.content;
1841
1842
							function onChangeContent() {
1843
1844
								$refresh = false;
1845
1846
								// Set the old content the same as the new one so we only compare all other attributes
1847
								if(typeof(prev_attributes[props.id]) != 'undefined'){
1848
									prev_attributes[props.id].content = props.attributes.content;
1849
								}else if(props.attributes.content === ""){
1850
									// if first load and content empty then refresh
1851
									$refresh = true;
1852
								}
1853
1854
								if ( ( !is_fetching &&  JSON.stringify(prev_attributes[props.id]) != JSON.stringify(props.attributes) ) || $refresh  ) {
1855
1856
									is_fetching = true;
1857
									var data = {
1858
										'action': 'super_duper_output_shortcode',
1859
										'shortcode': '<?php echo $this->options['base_id'];?>',
1860
										'attributes': props.attributes,
1861
										'post_id': <?php global $post; if ( isset( $post->ID ) ) {
1862
										echo $post->ID;
1863
									}else{echo '0';}?>,
1864
										'_ajax_nonce': '<?php echo wp_create_nonce( 'super_duper_output_shortcode' );?>'
1865
									};
1866
1867
									jQuery.post(ajaxurl, data, function (response) {
1868
										return response;
1869
									}).then(function (env) {
1870
1871
										// if the content is empty then we place some placeholder text
1872
										if (env == '') {
1873
											env = "<div style='background:#0185ba33;padding: 10px;border: 4px #ccc dashed;'>" + "<?php _e( 'Placeholder for: ' );?>" + props.name + "</div>";
1874
										}
1875
1876
										props.setAttributes({content: env});
1877
										is_fetching = false;
1878
										prev_attributes[props.id] = props.attributes;
1879
1880
										// if AUI is active call the js init function
1881
										if (typeof aui_init === "function") {
1882
											aui_init();
1883
										}
1884
									});
1885
1886
1887
								}
1888
1889
								return props.attributes.content;
1890
1891
							}
1892
1893
							return [
1894
1895
								el(wp.blockEditor.BlockControls, {key: 'controls'},
1896
1897
									<?php if($show_alignment){?>
1898
									el(
1899
										wp.blockEditor.AlignmentToolbar,
1900
										{
1901
											value: props.attributes.alignment,
1902
											onChange: function (alignment) {
1903
												props.setAttributes({alignment: alignment})
1904
											}
1905
										}
1906
									)
1907
									<?php }?>
1908
1909
								),
1910
1911
								el(wp.blockEditor.InspectorControls, {key: 'inspector'},
1912
1913
									<?php
1914
1915
									if(! empty( $this->arguments )){
1916
1917
									if ( $show_advanced ) {
1918
									?>
1919
									el('div', {
1920
											style: {'padding-left': '16px','padding-right': '16px'}
1921
										},
1922
										el(
1923
											wp.components.ToggleControl,
1924
											{
1925
												label: 'Show Advanced Settings?',
1926
												checked: props.attributes.show_advanced,
1927
												onChange: function (show_advanced) {
1928
													props.setAttributes({show_advanced: !props.attributes.show_advanced})
1929
												}
1930
											}
1931
										)
1932
									)
1933
									,
1934
									<?php
1935
1936
									}
1937
1938
									$arguments = $this->group_arguments( $this->arguments );
1939
1940
									// Do we have sections?
1941
									$has_sections = $arguments == $this->arguments ? false : true;
1942
1943
1944
									if($has_sections){
1945
									$panel_count = 0;
1946
									foreach($arguments as $key => $args){
1947
									?>
1948
									el(wp.components.PanelBody, {
1949
											title: '<?php esc_attr_e( $key ); ?>',
1950
											initialOpen: <?php if ( $panel_count ) {
1951
											echo "false";
1952
										} else {
1953
											echo "true";
1954
										}?>
1955
										},
1956
										<?php
1957
1958
1959
1960
										foreach ( $args as $k => $a ) {
1961
1962
											$this->block_row_start( $k, $a );
1963
											$this->build_block_arguments( $k, $a );
1964
											$this->block_row_end( $k, $a );
1965
										}
1966
										?>
1967
									),
1968
									<?php
1969
									$panel_count ++;
1970
1971
									}
1972
									}else {
1973
									?>
1974
									el(wp.components.PanelBody, {
1975
											title: '<?php esc_attr_e( "Settings" ); ?>',
1976
											initialOpen: true
1977
										},
1978
										<?php
1979
										foreach ( $this->arguments as $key => $args ) {
1980
											$this->block_row_start( $key, $args );
1981
											$this->build_block_arguments( $key, $args );
1982
											$this->block_row_end( $key, $args );
1983
										}
1984
										?>
1985
									),
1986
									<?php
1987
									}
1988
1989
									}
1990
									?>
1991
1992
								),
1993
1994
								<?php
1995
								// If the user sets block-output array then build it
1996
								if ( ! empty( $this->options['block-output'] ) ) {
1997
								$this->block_element( $this->options['block-output'] );
1998
							}else{
1999
								// if no block-output is set then we try and get the shortcode html output via ajax.
2000
								?>
2001
								el('div', {
2002
									dangerouslySetInnerHTML: {__html: onChangeContent()},
2003
									className: props.className,
2004
									style: {'minHeight': '30px'}
2005
								})
2006
								<?php
2007
								}
2008
								?>
2009
							]; // end return
2010
						},
2011
2012
						// The "save" property must be specified and must be a valid function.
2013
						save: function (props) {
2014
2015
							//console.log(props);
2016
2017
2018
							var attr = props.attributes;
2019
							var align = '';
2020
2021
							// build the shortcode.
2022
							var content = "[<?php echo $this->options['base_id'];?>";
2023
							$html = '';
2024
							<?php
2025
2026
							if(! empty( $this->arguments )){
2027
2028
							foreach($this->arguments as $key => $args){
2029
							?>
2030
							if (attr.hasOwnProperty("<?php echo esc_attr( $key );?>")) {
2031
								if ('<?php echo esc_attr( $key );?>' == 'html') {
2032
									$html = attr.<?php echo esc_attr( $key );?>;
2033
								} else {
2034
									content += " <?php echo esc_attr( $key );?>='" + attr.<?php echo esc_attr( $key );?>+ "' ";
2035
								}
2036
							}
2037
							<?php
2038
							}
2039
							}
2040
2041
							?>
2042
							content += "]";
2043
2044
							// if has html element
2045
							if ($html) {
2046
								content += $html + "[/<?php echo $this->options['base_id'];?>]";
2047
							}
2048
2049
2050
							// @todo should we add inline style here or just css classes?
2051
							if (attr.alignment) {
2052
								if (attr.alignment == 'left') {
2053
									align = 'alignleft';
2054
								}
2055
								if (attr.alignment == 'center') {
2056
									align = 'aligncenter';
2057
								}
2058
								if (attr.alignment == 'right') {
2059
									align = 'alignright';
2060
								}
2061
							}
2062
2063
							<?php
2064
							if(isset( $this->options['block-wrap'] ) && $this->options['block-wrap'] == ''){
2065
							?>
2066
							return content;
2067
							<?php
2068
							}else{
2069
							?>
2070
							var block_wrap = 'div';
2071
							if (attr.hasOwnProperty("block_wrap")) {
2072
								block_wrap = attr.block_wrap;
2073
							}
2074
							return el(block_wrap, {dangerouslySetInnerHTML: {__html: content}, className: align});
2075
							<?php
2076
							}
2077
							?>
2078
2079
2080
						}
2081
					});
2082
				})();
2083
			</script>
2084
			<?php
2085
			$output = ob_get_clean();
2086
2087
			/*
2088
			 * We only add the <script> tags for code highlighting, so we strip them from the output.
2089
			 */
2090
2091
			return str_replace( array(
2092
				'<script>',
2093
				'</script>'
2094
			), '', $output );
2095
		}
2096
2097
		public function block_row_start($key, $args){
0 ignored issues
show
Unused Code introduced by
The parameter $key is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

2097
		public function block_row_start(/** @scrutinizer ignore-unused */ $key, $args){

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
2098
2099
			// check for row
2100
			if(!empty($args['row'])){
2101
2102
				if(!empty($args['row']['open'])){
2103
2104
				// element require
2105
				$element_require = ! empty( $args['element_require'] ) ? $this->block_props_replace( $args['element_require'], true ) . " && " : "";
2106
				echo $element_require;
2107
2108
					if(false){?><script><?php }?>
2109
						el('div', {
2110
								className: 'bsui components-base-control',
2111
							},
2112
							<?php if(!empty($args['row']['title'])){ ?>
2113
							el('label', {
2114
									className: 'components-base-control__label',
2115
								},
2116
								'<?php echo addslashes( $args['row']['title'] ); ?>'
2117
							),
2118
							<?php }?>
2119
							<?php if(!empty($args['row']['desc'])){ ?>
2120
							el('p', {
2121
									className: 'components-base-control__help mb-0',
2122
								},
2123
								'<?php echo addslashes( $args['row']['desc'] ); ?>'
2124
							),
2125
							<?php }?>
2126
							el(
2127
								'div',
2128
								{
2129
									className: 'row mb-n2 <?php if(!empty($args['row']['class'])){ echo esc_attr($args['row']['class']);} ?>',
2130
								},
2131
								el(
2132
									'div',
2133
									{
2134
										className: 'col pr-2',
2135
									},
2136
2137
					<?php
2138
					if(false){?></script><?php }
2139
				}elseif(!empty($args['row']['close'])){
2140
					if(false){?><script><?php }?>
2141
						el(
2142
							'div',
2143
							{
2144
								className: 'col pl-0',
2145
							},
2146
					<?php
2147
					if(false){?></script><?php }
2148
				}else{
2149
					if(false){?><script><?php }?>
2150
						el(
2151
							'div',
2152
							{
2153
								className: 'col pl-0 pr-2',
2154
							},
2155
					<?php
2156
					if(false){?></script><?php }
2157
				}
2158
2159
			}
2160
2161
		}
2162
2163
		public function block_row_end($key, $args){
0 ignored issues
show
Unused Code introduced by
The parameter $key is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

2163
		public function block_row_end(/** @scrutinizer ignore-unused */ $key, $args){

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
2164
2165
			if(!empty($args['row'])){
2166
				// maybe close
2167
				if(!empty($args['row']['close'])){
2168
					echo "))";
2169
				}
2170
2171
				echo "),";
2172
			}
2173
		}
2174
2175
		public function build_block_arguments( $key, $args ) {
2176
			$custom_attributes = ! empty( $args['custom_attributes'] ) ? $this->array_to_attributes( $args['custom_attributes'] ) : '';
2177
			$options           = '';
2178
			$extra             = '';
2179
			$require           = '';
0 ignored issues
show
Unused Code introduced by
The assignment to $require is dead and can be removed.
Loading history...
2180
2181
			// `content` is a protected and special argument
2182
			if ( $key == 'content' ) {
2183
				return;
2184
			}
2185
2186
2187
			// icon
2188
			$icon = '';
2189
			if( !empty( $args['icon'] ) ){
2190
				$icon .= "el('div', {";
2191
									$icon .= "dangerouslySetInnerHTML: {__html: '".self::get_widget_icon( esc_attr($args['icon']))."'},";
0 ignored issues
show
Bug Best Practice introduced by
The method WP_Super_Duper::get_widget_icon() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2191
									$icon .= "dangerouslySetInnerHTML: {__html: '".self::/** @scrutinizer ignore-call */ get_widget_icon( esc_attr($args['icon']))."'},";
Loading history...
2192
									$icon .= "className: 'text-center',";
2193
									$icon .= "title: '".addslashes( $args['title'] )."',";
2194
								$icon .= "}),";
2195
2196
				// blank title as its added to the icon.
2197
				$args['title'] = '';
2198
			}
2199
2200
			// require advanced
2201
			$require_advanced = ! empty( $args['advanced'] ) ? "props.attributes.show_advanced && " : "";
2202
2203
			// element require
2204
			$element_require = ! empty( $args['element_require'] ) ? $this->block_props_replace( $args['element_require'], true ) . " && " : "";
2205
2206
2207
			$onchange  = "props.setAttributes({ $key: $key } )";
2208
			$onchangecomplete  = "";
2209
			$value     = "props.attributes.$key";
2210
			$text_type = array( 'text', 'password', 'number', 'email', 'tel', 'url', 'colorx' );
2211
			if ( in_array( $args['type'], $text_type ) ) {
2212
				$type = 'TextControl';
2213
				// Save numbers as numbers and not strings
2214
				if ( $args['type'] == 'number' ) {
2215
					$onchange = "props.setAttributes({ $key: Number($key) } )";
2216
				}
2217
			}
2218
			/*
2219
			 * https://www.wptricks.com/question/set-current-tab-on-a-gutenberg-tabpanel-component-from-outside-that-component/ es5 layout
2220
						elseif($args['type']=='tabs'){
2221
							?>
2222
							<script>
2223
								el(
2224
									wp.components.TabPanel,
2225
									{
2226
										tabs: [
2227
											{
2228
												name: 'show',
2229
												title: __( 'Show', 'my-textdomain' ),
2230
											},
2231
											{
2232
												name: 'edit',
2233
												title: __( 'Edit', 'my-textdomain' ),
2234
											},
2235
										],
2236
									},
2237
									( tab ) => {
2238
2239
									if('show' === tab.name){
2240
									return 123;
2241
								}else if ( 'edit' === tab.name ) {
2242
									return 321;
2243
								}
2244
2245
								}
2246
								),
2247
							</script>
2248
							<?php
2249
							return;
2250
						}
2251
			*/
2252
			elseif ( $args['type'] == 'color' ) {
2253
				$type = 'ColorPicker';
2254
				$onchange = "";
2255
				$extra = "color: $value,";
2256
				if(!empty($args['disable_alpha'])){
2257
					$extra .= "disableAlpha: true,";
2258
				}
2259
				$onchangecomplete = "onChangeComplete: function($key) {
2260
				value =  $key.rgb.a && $key.rgb.a < 1 ? \"rgba(\"+$key.rgb.r+\",\"+$key.rgb.g+\",\"+$key.rgb.b+\",\"+$key.rgb.a+\")\" : $key.hex;
2261
                        props.setAttributes({
2262
                            $key: value
2263
                        });
2264
                    },";
2265
			}
2266
			elseif ( $args['type'] == 'checkbox' ) {
2267
				$type = 'CheckboxControl';
2268
				$extra .= "checked: props.attributes.$key,";
2269
				$onchange = "props.setAttributes({ $key: ! props.attributes.$key } )";
2270
			} elseif ( $args['type'] == 'textarea' ) {
2271
				$type = 'TextareaControl';
2272
			} elseif ( $args['type'] == 'select' || $args['type'] == 'multiselect' ) {
2273
				$type = 'SelectControl';
2274
2275
				if($args['name'] == 'category' && !empty($args['post_type_linked'])){
2276
					$options .= "options: taxonomies_".str_replace("-","_", $this->id).",";
2277
				}elseif($args['name'] == 'sort_by' && !empty($args['post_type_linked'])){
2278
					$options .= "options: sort_by_".str_replace("-","_", $this->id).",";
2279
				}else {
2280
2281
					if ( ! empty( $args['options'] ) ) {
2282
						$options .= "options: [";
2283
						foreach ( $args['options'] as $option_val => $option_label ) {
2284
							$options .= "{ value: '" . esc_attr( $option_val ) . "', label: '" . addslashes( $option_label ) . "' },";
2285
						}
2286
						$options .= "],";
2287
					}
2288
				}
2289
				if ( isset( $args['multiple'] ) && $args['multiple'] ) { //@todo multiselect does not work at the moment: https://github.com/WordPress/gutenberg/issues/5550
2290
					$extra .= ' multiple: true, ';
2291
				}
2292
			} elseif ( $args['type'] == 'alignment' ) {
2293
				$type = 'AlignmentToolbar'; // @todo this does not seem to work but cant find a example
2294
			}elseif ( $args['type'] == 'margins' ) {
2295
2296
			} else {
2297
				return;// if we have not implemented the control then don't break the JS.
2298
			}
2299
2300
2301
2302
			// color input does not show the labels so we add them
2303
			if($args['type']=='color'){
2304
				// add show only if advanced
2305
				echo $require_advanced;
2306
				// add setting require if defined
2307
				echo $element_require;
2308
				echo "el('div', {style: {'marginBottom': '8px'}}, '".addslashes( $args['title'] )."'),";
2309
			}
2310
2311
			// add show only if advanced
2312
			echo $require_advanced;
2313
			// add setting require if defined
2314
			echo $element_require;
2315
2316
			// icon
2317
			echo $icon;
2318
			?>
2319
			el( wp.components.<?php echo $type; ?>, {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $type does not seem to be defined for all execution paths leading up to this point.
Loading history...
2320
			label: '<?php echo addslashes( $args['title'] ); ?>',
2321
			help: '<?php if ( isset( $args['desc'] ) ) {
2322
				echo addslashes( $args['desc'] );
2323
			} ?>',
2324
			value: <?php echo $value; ?>,
2325
			<?php if ( $type == 'TextControl' && $args['type'] != 'text' ) {
2326
				echo "type: '" . addslashes( $args['type'] ) . "',";
2327
			} ?>
2328
			<?php if ( ! empty( $args['placeholder'] ) ) {
2329
				echo "placeholder: '" . addslashes( $args['placeholder'] ) . "',";
2330
			} ?>
2331
			<?php echo $options; ?>
2332
			<?php echo $extra; ?>
2333
			<?php echo $custom_attributes; ?>
2334
			<?php echo $onchangecomplete;?>
2335
			onChange: function ( <?php echo $key; ?> ) {
2336
			<?php echo $onchange; ?>
2337
			}
2338
			} ),
2339
			<?php
2340
2341
2342
		}
2343
2344
		/**
2345
		 * Convert an array of attributes to block string.
2346
		 *
2347
		 * @todo there is prob a faster way to do this, also we could add some validation here.
2348
		 *
2349
		 * @param $custom_attributes
2350
		 *
2351
		 * @return string
2352
		 */
2353
		public function array_to_attributes( $custom_attributes, $html = false ) {
2354
			$attributes = '';
2355
			if ( ! empty( $custom_attributes ) ) {
2356
2357
				if ( $html ) {
2358
					foreach ( $custom_attributes as $key => $val ) {
2359
						$attributes .= " $key='$val' ";
2360
					}
2361
				} else {
2362
					foreach ( $custom_attributes as $key => $val ) {
2363
						$attributes .= "'$key': '$val',";
2364
					}
2365
				}
2366
			}
2367
2368
			return $attributes;
2369
		}
2370
2371
		/**
2372
		 * A self looping function to create the output for JS block elements.
2373
		 *
2374
		 * This is what is output in the WP Editor visual view.
2375
		 *
2376
		 * @param $args
2377
		 */
2378
		public function block_element( $args ) {
2379
2380
2381
			if ( ! empty( $args ) ) {
2382
				foreach ( $args as $element => $new_args ) {
2383
2384
					if ( is_array( $new_args ) ) { // its an element
2385
2386
2387
						if ( isset( $new_args['element'] ) ) {
2388
2389
							if ( isset( $new_args['element_require'] ) ) {
2390
								echo str_replace( array(
2391
										"'+",
2392
										"+'"
2393
									), '', $this->block_props_replace( $new_args['element_require'] ) ) . " &&  ";
2394
								unset( $new_args['element_require'] );
2395
							}
2396
2397
							echo "\n el( '" . $new_args['element'] . "', {";
2398
2399
							// get the attributes
2400
							foreach ( $new_args as $new_key => $new_value ) {
2401
2402
2403
								if ( $new_key == 'element' || $new_key == 'content' || $new_key == 'element_require' || $new_key == 'element_repeat' || is_array( $new_value ) ) {
2404
									// do nothing
2405
								} else {
2406
									echo $this->block_element( array( $new_key => $new_value ) );
2407
								}
2408
							}
2409
2410
							echo "},";// end attributes
2411
2412
							// get the content
2413
							$first_item = 0;
2414
							foreach ( $new_args as $new_key => $new_value ) {
2415
								if ( $new_key === 'content' || is_array( $new_value ) ) {
2416
2417
									if ( $new_key === 'content' ) {
2418
										echo "'" . $this->block_props_replace( wp_slash( $new_value ) ) . "'";
2419
									}
2420
2421
									if ( is_array( $new_value ) ) {
2422
2423
										if ( isset( $new_value['element_require'] ) ) {
2424
											echo str_replace( array(
2425
													"'+",
2426
													"+'"
2427
												), '', $this->block_props_replace( $new_value['element_require'] ) ) . " &&  ";
2428
											unset( $new_value['element_require'] );
2429
										}
2430
2431
										if ( isset( $new_value['element_repeat'] ) ) {
2432
											$x = 1;
2433
											while ( $x <= absint( $new_value['element_repeat'] ) ) {
2434
												$this->block_element( array( '' => $new_value ) );
2435
												$x ++;
2436
											}
2437
										} else {
2438
											$this->block_element( array( '' => $new_value ) );
2439
										}
2440
									}
2441
									$first_item ++;
2442
								}
2443
							}
2444
2445
							echo ")";// end content
2446
2447
							echo ", \n";
2448
2449
						}
2450
					} else {
2451
2452
						if ( substr( $element, 0, 3 ) === "if_" ) {
2453
							echo str_replace( "if_", "", $element ) . ": " . $this->block_props_replace( $new_args, true ) . ",";
2454
						} elseif ( $element == 'style' ) {
2455
							echo $element . ": " . $this->block_props_replace( $new_args ) . ",";
2456
						} else {
2457
							echo $element . ": '" . $this->block_props_replace( $new_args ) . "',";
2458
						}
2459
2460
					}
2461
				}
2462
			}
2463
		}
2464
2465
		/**
2466
		 * Replace block attributes placeholders with the proper naming.
2467
		 *
2468
		 * @param $string
2469
		 *
2470
		 * @return mixed
2471
		 */
2472
		public function block_props_replace( $string, $no_wrap = false ) {
2473
2474
			if ( $no_wrap ) {
2475
				$string = str_replace( array( "[%", "%]" ), array( "props.attributes.", "" ), $string );
2476
			} else {
2477
				$string = str_replace( array( "[%", "%]" ), array( "'+props.attributes.", "+'" ), $string );
2478
			}
2479
2480
			return $string;
2481
		}
2482
2483
		/**
2484
		 * Outputs the content of the widget
2485
		 *
2486
		 * @param array $args
2487
		 * @param array $instance
2488
		 */
2489
		public function widget( $args, $instance ) {
2490
2491
			// get the filtered values
2492
			$argument_values = $this->argument_values( $instance );
2493
			$argument_values = $this->string_to_bool( $argument_values );
2494
			$output          = $this->output( $argument_values, $args );
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $output is correct as $this->output($argument_values, $args) targeting WP_Super_Duper::output() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
2495
2496
			$no_wrap = false;
2497
			if ( isset( $argument_values['no_wrap'] ) && $argument_values['no_wrap'] ) {
2498
				$no_wrap = true;
2499
			}
2500
2501
			ob_start();
2502
			if ( $output && ! $no_wrap ) {
0 ignored issues
show
introduced by
$output is defined implicitly as null, thus it is always evaluated to false.
Loading history...
2503
2504
				$class_original = $this->options['widget_ops']['classname'];
2505
				$class = $this->options['widget_ops']['classname']." sdel-".$this->get_instance_hash();
2506
2507
				// Before widget
2508
				$before_widget = $args['before_widget'];
2509
				$before_widget = str_replace($class_original,$class,$before_widget);
2510
				$before_widget = apply_filters( 'wp_super_duper_before_widget', $before_widget, $args, $instance, $this );
2511
				$before_widget = apply_filters( 'wp_super_duper_before_widget_' . $this->base_id, $before_widget, $args, $instance, $this );
2512
2513
				// After widget
2514
				$after_widget = $args['after_widget'];
2515
				$after_widget = apply_filters( 'wp_super_duper_after_widget', $after_widget, $args, $instance, $this );
2516
				$after_widget = apply_filters( 'wp_super_duper_after_widget_' . $this->base_id, $after_widget, $args, $instance, $this );
2517
2518
				echo $before_widget;
2519
				// elementor strips the widget wrapping div so we check for and add it back if needed
2520
				if ( $this->is_elementor_widget_output() ) {
2521
					// Filter class & attrs for elementor widget output.
2522
					$class = apply_filters( 'wp_super_duper_div_classname', $class, $args, $this );
2523
					$class = apply_filters( 'wp_super_duper_div_classname_' . $this->base_id, $class, $args, $this );
2524
2525
					$attrs = apply_filters( 'wp_super_duper_div_attrs', '', $args, $this );
0 ignored issues
show
Unused Code introduced by
The assignment to $attrs is dead and can be removed.
Loading history...
2526
					$attrs = apply_filters( 'wp_super_duper_div_attrs_' . $this->base_id, '', $args, $this );
2527
2528
					echo "<span class='" . esc_attr( $class  ) . "' " . $attrs . ">";
2529
				}
2530
				echo $this->output_title( $args, $instance );
2531
				echo $output;
2532
				if ( $this->is_elementor_widget_output() ) {
2533
					echo "</span>";
2534
				}
2535
				echo $after_widget;
2536
			} elseif ( $this->is_preview() && $output == '' ) {// if preview show a placeholder if empty
2537
				$output = $this->preview_placeholder_text( "{{" . $this->base_id . "}}" );
2538
				echo $output;
2539
			} elseif ( $output && $no_wrap ) {
0 ignored issues
show
introduced by
$output is defined implicitly as null, thus it is always evaluated to false.
Loading history...
2540
				echo $output;
2541
			}
2542
			$output = ob_get_clean();
2543
2544
			$output = apply_filters( 'wp_super_duper_widget_output', $output, $instance, $args, $this );
2545
2546
			echo $output;
2547
		}
2548
2549
		/**
2550
		 * Tests if the current output is inside a elementor container.
2551
		 *
2552
		 * @since 1.0.4
2553
		 * @return bool
2554
		 */
2555
		public function is_elementor_widget_output() {
2556
			$result = false;
2557
			if ( defined( 'ELEMENTOR_VERSION' ) && isset( $this->number ) && $this->number == 'REPLACE_TO_ID' ) {
2558
				$result = true;
2559
			}
2560
2561
			return $result;
2562
		}
2563
2564
		/**
2565
		 * Tests if the current output is inside a elementor preview.
2566
		 *
2567
		 * @since 1.0.4
2568
		 * @return bool
2569
		 */
2570
		public function is_elementor_preview() {
2571
			$result = false;
2572
			if ( isset( $_REQUEST['elementor-preview'] ) || ( is_admin() && isset( $_REQUEST['action'] ) && $_REQUEST['action'] == 'elementor' ) || ( isset( $_REQUEST['action'] ) && $_REQUEST['action'] == 'elementor_ajax' ) ) {
2573
				$result = true;
2574
			}
2575
2576
			return $result;
2577
		}
2578
2579
		/**
2580
		 * Tests if the current output is inside a Divi preview.
2581
		 *
2582
		 * @since 1.0.6
2583
		 * @return bool
2584
		 */
2585
		public function is_divi_preview() {
2586
			$result = false;
2587
			if ( isset( $_REQUEST['et_fb'] ) || isset( $_REQUEST['et_pb_preview'] ) || ( is_admin() && isset( $_REQUEST['action'] ) && $_REQUEST['action'] == 'elementor' ) ) {
2588
				$result = true;
2589
			}
2590
2591
			return $result;
2592
		}
2593
2594
		/**
2595
		 * Tests if the current output is inside a Beaver builder preview.
2596
		 *
2597
		 * @since 1.0.6
2598
		 * @return bool
2599
		 */
2600
		public function is_beaver_preview() {
2601
			$result = false;
2602
			if ( isset( $_REQUEST['fl_builder'] ) ) {
2603
				$result = true;
2604
			}
2605
2606
			return $result;
2607
		}
2608
2609
		/**
2610
		 * Tests if the current output is inside a siteorigin builder preview.
2611
		 *
2612
		 * @since 1.0.6
2613
		 * @return bool
2614
		 */
2615
		public function is_siteorigin_preview() {
2616
			$result = false;
2617
			if ( ! empty( $_REQUEST['siteorigin_panels_live_editor'] ) ) {
2618
				$result = true;
2619
			}
2620
2621
			return $result;
2622
		}
2623
2624
		/**
2625
		 * Tests if the current output is inside a cornerstone builder preview.
2626
		 *
2627
		 * @since 1.0.8
2628
		 * @return bool
2629
		 */
2630
		public function is_cornerstone_preview() {
2631
			$result = false;
2632
			if ( ! empty( $_REQUEST['cornerstone_preview'] ) || basename( $_SERVER['REQUEST_URI'] ) == 'cornerstone-endpoint' ) {
2633
				$result = true;
2634
			}
2635
2636
			return $result;
2637
		}
2638
2639
		/**
2640
		 * Tests if the current output is inside a fusion builder preview.
2641
		 *
2642
		 * @since 1.1.0
2643
		 * @return bool
2644
		 */
2645
		public function is_fusion_preview() {
2646
			$result = false;
2647
			if ( ! empty( $_REQUEST['fb-edit'] ) || ! empty( $_REQUEST['fusion_load_nonce'] ) ) {
2648
				$result = true;
2649
			}
2650
2651
			return $result;
2652
		}
2653
2654
		/**
2655
		 * Tests if the current output is inside a Oxygen builder preview.
2656
		 *
2657
		 * @since 1.0.18
2658
		 * @return bool
2659
		 */
2660
		public function is_oxygen_preview() {
2661
			$result = false;
2662
			if ( ! empty( $_REQUEST['ct_builder'] ) || ( ! empty( $_REQUEST['action'] ) && ( substr( $_REQUEST['action'], 0, 11 ) === "oxy_render_" || substr( $_REQUEST['action'], 0, 10 ) === "ct_render_" ) ) ) {
2663
				$result = true;
2664
			}
2665
2666
			return $result;
2667
		}
2668
2669
		/**
2670
		 * General function to check if we are in a preview situation.
2671
		 *
2672
		 * @since 1.0.6
2673
		 * @return bool
2674
		 */
2675
		public function is_preview() {
2676
			$preview = false;
2677
			if ( $this->is_divi_preview() ) {
2678
				$preview = true;
2679
			} elseif ( $this->is_elementor_preview() ) {
2680
				$preview = true;
2681
			} elseif ( $this->is_beaver_preview() ) {
2682
				$preview = true;
2683
			} elseif ( $this->is_siteorigin_preview() ) {
2684
				$preview = true;
2685
			} elseif ( $this->is_cornerstone_preview() ) {
2686
				$preview = true;
2687
			} elseif ( $this->is_fusion_preview() ) {
2688
				$preview = true;
2689
			} elseif ( $this->is_oxygen_preview() ) {
2690
				$preview = true;
2691
			} elseif( $this->is_block_content_call() ) {
2692
				$preview = true;
2693
			}
2694
2695
			return $preview;
2696
		}
2697
2698
		/**
2699
		 * Output the super title.
2700
		 *
2701
		 * @param $args
2702
		 * @param array $instance
2703
		 *
2704
		 * @return string
2705
		 */
2706
		public function output_title( $args, $instance = array() ) {
2707
			$output = '';
2708
			if ( ! empty( $instance['title'] ) ) {
2709
				/** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */
2710
				$title  = apply_filters( 'widget_title', $instance['title'], $instance, $this->id_base );
2711
2712
				if(empty($instance['widget_title_tag'])){
2713
					$output = $args['before_title'] . $title . $args['after_title'];
2714
				}else{
2715
					$title_tag = esc_attr( $instance['widget_title_tag'] );
2716
2717
					// classes
2718
					$title_classes = array();
2719
					$title_classes[] = !empty( $instance['widget_title_size_class'] ) ? sanitize_html_class( $instance['widget_title_size_class'] ) : '';
2720
					$title_classes[] = !empty( $instance['widget_title_align_class'] ) ? sanitize_html_class( $instance['widget_title_align_class'] ) : '';
2721
					$title_classes[] = !empty( $instance['widget_title_color_class'] ) ? "text-".sanitize_html_class( $instance['widget_title_color_class'] ) : '';
2722
					$title_classes[] = !empty( $instance['widget_title_border_class'] ) ? sanitize_html_class( $instance['widget_title_border_class'] ) : '';
2723
					$title_classes[] = !empty( $instance['widget_title_border_color_class'] ) ? "border-".sanitize_html_class( $instance['widget_title_border_color_class'] ) : '';
2724
					$title_classes[] = !empty( $instance['widget_title_mt_class'] ) ? "mt-".absint( $instance['widget_title_mt_class'] ) : '';
2725
					$title_classes[] = !empty( $instance['widget_title_mr_class'] ) ? "mr-".absint( $instance['widget_title_mr_class'] ) : '';
2726
					$title_classes[] = !empty( $instance['widget_title_mb_class'] ) ? "mb-".absint( $instance['widget_title_mb_class'] ) : '';
2727
					$title_classes[] = !empty( $instance['widget_title_ml_class'] ) ? "ml-".absint( $instance['widget_title_ml_class'] ) : '';
2728
					$title_classes[] = !empty( $instance['widget_title_pt_class'] ) ? "pt-".absint( $instance['widget_title_pt_class'] ) : '';
2729
					$title_classes[] = !empty( $instance['widget_title_pr_class'] ) ? "pr-".absint( $instance['widget_title_pr_class'] ) : '';
2730
					$title_classes[] = !empty( $instance['widget_title_pb_class'] ) ? "pb-".absint( $instance['widget_title_pb_class'] ) : '';
2731
					$title_classes[] = !empty( $instance['widget_title_pl_class'] ) ? "pl-".absint( $instance['widget_title_pl_class'] ) : '';
2732
2733
					$class = !empty( $title_classes ) ? implode(" ",$title_classes) : '';
2734
					$output = "<$title_tag class='$class' >$title</$title_tag>";
2735
				}
2736
2737
			}
2738
2739
			return $output;
2740
		}
2741
2742
		/**
2743
		 * Outputs the options form inputs for the widget.
2744
		 *
2745
		 * @param array $instance The widget options.
2746
		 */
2747
		public function form( $instance ) {
2748
2749
			// set widget instance
2750
			$this->instance = $instance;
2751
2752
			// set it as a SD widget
2753
			echo $this->widget_advanced_toggle();
2754
2755
			echo "<p>" . esc_attr( $this->options['widget_ops']['description'] ) . "</p>";
2756
			$arguments_raw = $this->get_arguments();
2757
2758
			if ( is_array( $arguments_raw ) ) {
0 ignored issues
show
introduced by
The condition is_array($arguments_raw) is always true.
Loading history...
2759
2760
				$arguments = $this->group_arguments( $arguments_raw );
2761
2762
				// Do we have sections?
2763
				$has_sections = $arguments == $arguments_raw ? false : true;
2764
2765
2766
				if ( $has_sections ) {
2767
					$panel_count = 0;
2768
					foreach ( $arguments as $key => $args ) {
2769
2770
						?>
2771
						<script>
2772
							//							jQuery(this).find("i").toggleClass("fas fa-chevron-up fas fa-chevron-down");jQuery(this).next().toggle();
2773
						</script>
2774
						<?php
2775
2776
						$hide       = $panel_count ? ' style="display:none;" ' : '';
2777
						$icon_class = $panel_count ? 'fas fa-chevron-up' : 'fas fa-chevron-down';
2778
						echo "<button onclick='jQuery(this).find(\"i\").toggleClass(\"fas fa-chevron-up fas fa-chevron-down\");jQuery(this).next().slideToggle();' type='button' class='sd-toggle-group-button sd-input-group-toggle" . sanitize_title_with_dashes( $key ) . "'>" . esc_attr( $key ) . " <i style='float:right;' class='" . $icon_class . "'></i></button>";
2779
						echo "<div class='sd-toggle-group sd-input-group-" . sanitize_title_with_dashes( $key ) . "' $hide>";
2780
2781
						foreach ( $args as $k => $a ) {
2782
2783
							$this->widget_inputs_row_start($k, $a);
2784
							$this->widget_inputs( $a, $instance );
2785
							$this->widget_inputs_row_end($k, $a);
2786
2787
						}
2788
2789
						echo "</div>";
2790
2791
						$panel_count ++;
2792
2793
					}
2794
				} else {
2795
					foreach ( $arguments as $key => $args ) {
2796
						$this->widget_inputs_row_start($key, $args);
2797
						$this->widget_inputs( $args, $instance );
2798
						$this->widget_inputs_row_end($key, $args);
2799
					}
2800
				}
2801
2802
			}
2803
		}
2804
2805
		public function widget_inputs_row_start($key, $args){
0 ignored issues
show
Unused Code introduced by
The parameter $key is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

2805
		public function widget_inputs_row_start(/** @scrutinizer ignore-unused */ $key, $args){

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
2806
			if(!empty($args['row'])){
2807
				// maybe open
2808
				if(!empty($args['row']['open'])){
2809
					?>
2810
					<div class='bsui sd-argument ' data-argument='<?php echo esc_attr( $args['row']['key'] ); ?>' data-element_require='<?php if ( !empty($args['row']['element_require'])) {
2811
						echo $this->convert_element_require( $args['row']['element_require'] );
2812
					} ?>'>
2813
					<?php if(!empty($args['row']['title'])){ ?>
2814
					<label class="mb-0 "><?php echo esc_attr( $args['row']['title'] ); ?><?php echo $this->widget_field_desc( $args['row'] ); ?></label>
2815
					<?php }?>
2816
					<div class='row <?php if(!empty($args['row']['class'])){ echo esc_attr($args['row']['class']);} ?>'>
2817
					<div class='col pr-2'>
2818
					<?php
2819
				}elseif(!empty($args['row']['close'])){
2820
					echo "<div class='col pl-0'>";
2821
				}else{
2822
					echo "<div class='col pl-0 pr-2'>";
2823
				}
2824
			}
2825
		}
2826
2827
		public function widget_inputs_row_end($key, $args){
0 ignored issues
show
Unused Code introduced by
The parameter $key is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

2827
		public function widget_inputs_row_end(/** @scrutinizer ignore-unused */ $key, $args){

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
2828
2829
			if(!empty($args['row'])){
2830
				// maybe close
2831
				if(!empty($args['row']['close'])){
2832
					echo "</div></div>";
2833
				}
2834
2835
				echo "</div>";
2836
			}
2837
		}
2838
2839
		/**
2840
		 * Get the hidden input that when added makes the advanced button show on widget settings.
2841
		 *
2842
		 * @return string
2843
		 */
2844
		public function widget_advanced_toggle() {
2845
2846
			$output = '';
2847
			if ( $this->block_show_advanced() ) {
2848
				$val = 1;
2849
			} else {
2850
				$val = 0;
2851
			}
2852
2853
			$output .= "<input type='hidden'  class='sd-show-advanced' value='$val' />";
2854
2855
			return $output;
2856
		}
2857
2858
		/**
2859
		 * Convert require element.
2860
		 *
2861
		 * @since 1.0.0
2862
		 *
2863
		 * @param string $input Input element.
2864
		 *
2865
		 * @return string $output
2866
		 */
2867
		public function convert_element_require( $input ) {
2868
2869
			$input = str_replace( "'", '"', $input );// we only want double quotes
2870
2871
			$output = esc_attr( str_replace( array( "[%", "%]" ), array(
2872
				"jQuery(form).find('[data-argument=\"",
2873
				"\"]').find('input,select,textarea').val()"
2874
			), $input ) );
2875
2876
			return $output;
2877
		}
2878
2879
		/**
2880
		 * Builds the inputs for the widget options.
2881
		 *
2882
		 * @param $args
2883
		 * @param $instance
2884
		 */
2885
		public function widget_inputs( $args, $instance ) {
2886
2887
			$class             = "";
2888
			$element_require   = "";
2889
			$custom_attributes = "";
2890
2891
			// get value
2892
			if ( isset( $instance[ $args['name'] ] ) ) {
2893
				$value = $instance[ $args['name'] ];
2894
			} elseif ( ! isset( $instance[ $args['name'] ] ) && ! empty( $args['default'] ) ) {
2895
				$value = is_array( $args['default'] ) ? array_map( "esc_html", $args['default'] ) : esc_html( $args['default'] );
2896
			} else {
2897
				$value = '';
2898
			}
2899
2900
			// get placeholder
2901
			if ( ! empty( $args['placeholder'] ) ) {
2902
				$placeholder = "placeholder='" . esc_html( $args['placeholder'] ) . "'";
2903
			} else {
2904
				$placeholder = '';
2905
			}
2906
2907
			// get if advanced
2908
			if ( isset( $args['advanced'] ) && $args['advanced'] ) {
2909
				$class .= " sd-advanced-setting ";
2910
			}
2911
2912
			// element_require
2913
			if ( isset( $args['element_require'] ) && $args['element_require'] ) {
2914
				$element_require = $args['element_require'];
2915
			}
2916
2917
			// custom_attributes
2918
			if ( isset( $args['custom_attributes'] ) && $args['custom_attributes'] ) {
2919
				$custom_attributes = $this->array_to_attributes( $args['custom_attributes'], true );
2920
			}
2921
2922
2923
			// before wrapper
2924
			?>
2925
			<p class="sd-argument <?php echo esc_attr( $class ); ?>"
2926
			data-argument='<?php echo esc_attr( $args['name'] ); ?>'
2927
			data-element_require='<?php if ( $element_require ) {
2928
				echo $this->convert_element_require( $element_require );
2929
			} ?>'
2930
			>
2931
			<?php
2932
2933
2934
			switch ( $args['type'] ) {
2935
				//array('text','password','number','email','tel','url','color')
2936
				case "text":
2937
				case "password":
2938
				case "number":
2939
				case "email":
2940
				case "tel":
2941
				case "url":
2942
				case "color":
2943
					?>
2944
					<label
2945
						for="<?php echo esc_attr( $this->get_field_id( $args['name'] ) ); ?>"><?php echo $this->widget_field_title( $args );?><?php echo $this->widget_field_desc( $args ); ?></label>
2946
					<input <?php echo $placeholder; ?> class="widefat"
2947
						<?php echo $custom_attributes; ?>
2948
						                               id="<?php echo esc_attr( $this->get_field_id( $args['name'] ) ); ?>"
2949
						                               name="<?php echo esc_attr( $this->get_field_name( $args['name'] ) ); ?>"
2950
						                               type="<?php echo esc_attr( $args['type'] ); ?>"
2951
						                               value="<?php echo esc_attr( $value ); ?>">
2952
					<?php
2953
2954
					break;
2955
				case "select":
2956
					$multiple = isset( $args['multiple'] ) && $args['multiple'] ? true : false;
2957
					if ( $multiple ) {
2958
						if ( empty( $value ) ) {
2959
							$value = array();
2960
						}
2961
					}
2962
					?>
2963
					<label
2964
						for="<?php echo esc_attr( $this->get_field_id( $args['name'] ) ); ?>"><?php echo $this->widget_field_title( $args ); ?><?php echo $this->widget_field_desc( $args ); ?></label>
2965
					<select <?php echo $placeholder; ?> class="widefat"
2966
						<?php echo $custom_attributes; ?>
2967
						                                id="<?php echo esc_attr( $this->get_field_id( $args['name'] ) ); ?>"
2968
						                                name="<?php echo esc_attr( $this->get_field_name( $args['name'] ) );
2969
						                                if ( $multiple ) {
2970
							                                echo "[]";
2971
						                                } ?>"
2972
						<?php if ( $multiple ) {
2973
							echo "multiple";
2974
						} //@todo not implemented yet due to gutenberg not supporting it
2975
						?>
2976
					>
2977
						<?php
2978
2979
						if ( ! empty( $args['options'] ) ) {
2980
							foreach ( $args['options'] as $val => $label ) {
2981
								if ( $multiple ) {
2982
									$selected = in_array( $val, $value ) ? 'selected="selected"' : '';
2983
								} else {
2984
									$selected = selected( $value, $val, false );
2985
								}
2986
								echo "<option value='$val' " . $selected . ">$label</option>";
2987
							}
2988
						}
2989
						?>
2990
					</select>
2991
					<?php
2992
					break;
2993
				case "checkbox":
2994
					?>
2995
					<input <?php echo $placeholder; ?>
2996
						<?php checked( 1, $value, true ) ?>
2997
						<?php echo $custom_attributes; ?>
2998
						class="widefat" id="<?php echo esc_attr( $this->get_field_id( $args['name'] ) ); ?>"
2999
						name="<?php echo esc_attr( $this->get_field_name( $args['name'] ) ); ?>" type="checkbox"
3000
						value="1">
3001
					<label
3002
						for="<?php echo esc_attr( $this->get_field_id( $args['name'] ) ); ?>"><?php echo $this->widget_field_title( $args );?><?php echo $this->widget_field_desc( $args ); ?></label>
3003
					<?php
3004
					break;
3005
				case "textarea":
3006
					?>
3007
					<label
3008
						for="<?php echo esc_attr( $this->get_field_id( $args['name'] ) ); ?>"><?php echo $this->widget_field_title( $args ); ?><?php echo $this->widget_field_desc( $args ); ?></label>
3009
					<textarea <?php echo $placeholder; ?> class="widefat"
3010
						<?php echo $custom_attributes; ?>
3011
						                                  id="<?php echo esc_attr( $this->get_field_id( $args['name'] ) ); ?>"
3012
						                                  name="<?php echo esc_attr( $this->get_field_name( $args['name'] ) ); ?>"
3013
					><?php echo esc_attr( $value ); ?></textarea>
3014
					<?php
3015
3016
					break;
3017
				case "hidden":
3018
					?>
3019
					<input id="<?php echo esc_attr( $this->get_field_id( $args['name'] ) ); ?>"
3020
					       name="<?php echo esc_attr( $this->get_field_name( $args['name'] ) ); ?>" type="hidden"
3021
					       value="<?php echo esc_attr( $value ); ?>">
3022
					<?php
3023
					break;
3024
				default:
3025
					echo "No input type found!"; // @todo we need to add more input types.
3026
			}
3027
3028
			// after wrapper
3029
			?>
3030
			</p>
3031
			<?php
3032
3033
3034
		}
3035
3036
		public function get_widget_icon($icon = 'box-top', $title = ''){
3037
			if($icon=='box-top'){
3038
				return '<svg title="'.esc_attr($title).'" width="20px" height="20px" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.414" role="img" aria-hidden="true" focusable="false"><rect x="2.714" y="5.492" width="1.048" height="9.017" fill="#555D66"></rect><rect x="16.265" y="5.498" width="1.023" height="9.003" fill="#555D66"></rect><rect x="5.518" y="2.186" width="8.964" height="2.482" fill="#272B2F"></rect><rect x="5.487" y="16.261" width="9.026" height="1.037" fill="#555D66"></rect></svg>';
3039
			}elseif($icon=='box-right'){
3040
				return '<svg title="'.esc_attr($title).'" width="20px" height="20px" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.414" role="img" aria-hidden="true" focusable="false"><rect x="2.714" y="5.492" width="1.046" height="9.017" fill="#555D66"></rect><rect x="15.244" y="5.498" width="2.518" height="9.003" fill="#272B2F"></rect><rect x="5.518" y="2.719" width="8.964" height="0.954" fill="#555D66"></rect><rect x="5.487" y="16.308" width="9.026" height="0.99" fill="#555D66"></rect></svg>';
3041
			}elseif($icon=='box-bottom'){
3042
				return '<svg title="'.esc_attr($title).'" width="20px" height="20px" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.414" role="img" aria-hidden="true" focusable="false"><rect x="2.714" y="5.492" width="1" height="9.017" fill="#555D66"></rect><rect x="16.261" y="5.498" width="1.027" height="9.003" fill="#555D66"></rect><rect x="5.518" y="2.719" width="8.964" height="0.968" fill="#555D66"></rect><rect x="5.487" y="15.28" width="9.026" height="2.499" fill="#272B2F"></rect></svg>';
3043
			}elseif($icon=='box-left'){
3044
				return '<svg title="'.esc_attr($title).'" width="20px" height="20px" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.414" role="img" aria-hidden="true" focusable="false"><rect x="2.202" y="5.492" width="2.503" height="9.017" fill="#272B2F"></rect><rect x="16.276" y="5.498" width="1.012" height="9.003" fill="#555D66"></rect><rect x="5.518" y="2.719" width="8.964" height="0.966" fill="#555D66"></rect><rect x="5.487" y="16.303" width="9.026" height="0.995" fill="#555D66"></rect></svg>';
3045
			}
3046
		}
3047
3048
		/**
3049
		 * Get the widget input description html.
3050
		 *
3051
		 * @param $args
3052
		 *
3053
		 * @return string
3054
		 * @todo, need to make its own tooltip script
3055
		 */
3056
		public function widget_field_desc( $args ) {
3057
3058
			$description = '';
3059
			if ( isset( $args['desc'] ) && $args['desc'] ) {
3060
				if ( isset( $args['desc_tip'] ) && $args['desc_tip'] ) {
3061
					$description = $this->desc_tip( $args['desc'] );
3062
				} else {
3063
					$description = '<span class="description">' . wp_kses_post( $args['desc'] ) . '</span>';
3064
				}
3065
			}
3066
3067
			return $description;
3068
		}
3069
3070
		/**
3071
		 * Get the widget input title html.
3072
		 *
3073
		 * @param $args
3074
		 *
3075
		 * @return string
3076
		 */
3077
		public function widget_field_title( $args ) {
3078
3079
			$title = '';
3080
			if ( isset( $args['title'] ) && $args['title'] ) {
3081
				if ( isset( $args['icon'] ) && $args['icon'] ) {
3082
					$title = self::get_widget_icon( $args['icon'], $args['title']  );
0 ignored issues
show
Bug Best Practice introduced by
The method WP_Super_Duper::get_widget_icon() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

3082
					/** @scrutinizer ignore-call */ 
3083
     $title = self::get_widget_icon( $args['icon'], $args['title']  );
Loading history...
3083
				} else {
3084
					$title = esc_attr($args['title']);
3085
				}
3086
			}
3087
3088
			return $title;
3089
		}
3090
3091
		/**
3092
		 * Get the tool tip html.
3093
		 *
3094
		 * @param $tip
3095
		 * @param bool $allow_html
3096
		 *
3097
		 * @return string
3098
		 */
3099
		function desc_tip( $tip, $allow_html = false ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
3100
			if ( $allow_html ) {
3101
				$tip = $this->sanitize_tooltip( $tip );
3102
			} else {
3103
				$tip = esc_attr( $tip );
3104
			}
3105
3106
			return '<span class="gd-help-tip dashicons dashicons-editor-help" title="' . $tip . '"></span>';
3107
		}
3108
3109
		/**
3110
		 * Sanitize a string destined to be a tooltip.
3111
		 *
3112
		 * @param string $var
3113
		 *
3114
		 * @return string
3115
		 */
3116
		public function sanitize_tooltip( $var ) {
3117
			return htmlspecialchars( wp_kses( html_entity_decode( $var ), array(
3118
				'br'     => array(),
3119
				'em'     => array(),
3120
				'strong' => array(),
3121
				'small'  => array(),
3122
				'span'   => array(),
3123
				'ul'     => array(),
3124
				'li'     => array(),
3125
				'ol'     => array(),
3126
				'p'      => array(),
3127
			) ) );
3128
		}
3129
3130
		/**
3131
		 * Processing widget options on save
3132
		 *
3133
		 * @param array $new_instance The new options
3134
		 * @param array $old_instance The previous options
3135
		 *
3136
		 * @return array
3137
		 * @todo we should add some sanitation here.
3138
		 */
3139
		public function update( $new_instance, $old_instance ) {
3140
3141
			//save the widget
3142
			$instance = array_merge( (array) $old_instance, (array) $new_instance );
3143
3144
			// set widget instance
3145
			$this->instance = $instance;
3146
3147
			if ( empty( $this->arguments ) ) {
3148
				$this->get_arguments();
3149
			}
3150
3151
			// check for checkboxes
3152
			if ( ! empty( $this->arguments ) ) {
3153
				foreach ( $this->arguments as $argument ) {
3154
					if ( isset( $argument['type'] ) && $argument['type'] == 'checkbox' && ! isset( $new_instance[ $argument['name'] ] ) ) {
3155
						$instance[ $argument['name'] ] = '0';
3156
					}
3157
				}
3158
			}
3159
3160
			return $instance;
3161
		}
3162
3163
		/**
3164
		 * Checks if the current call is a ajax call to get the block content.
3165
		 *
3166
		 * This can be used in your widget to return different content as the block content.
3167
		 *
3168
		 * @since 1.0.3
3169
		 * @return bool
3170
		 */
3171
		public function is_block_content_call() {
3172
			$result = false;
3173
			if ( wp_doing_ajax() && isset( $_REQUEST['action'] ) && $_REQUEST['action'] == 'super_duper_output_shortcode' ) {
3174
				$result = true;
3175
			}
3176
3177
			return $result;
3178
		}
3179
3180
		/**
3181
		 * Get an instance hash that will be unique to the type and settings.
3182
		 *
3183
		 * @since 1.0.20
3184
		 * @return string
3185
		 */
3186
		public function get_instance_hash(){
3187
			$instance_string = $this->base_id.serialize($this->instance);
3188
			return hash('crc32b',$instance_string);
3189
		}
3190
3191
		/**
3192
		 * Generate and return inline styles from CSS rules that will match the unique class of the instance.
3193
		 *
3194
		 * @param array $rules
3195
		 *
3196
		 * @since 1.0.20
3197
		 * @return string
3198
		 */
3199
		public function get_instance_style($rules = array()){
3200
			$css = '';
3201
3202
			if(!empty($rules)){
3203
				$rules = array_unique($rules);
3204
				$instance_hash = $this->get_instance_hash();
3205
				$css .= "<style>";
3206
				foreach($rules as $rule){
3207
					$css .= ".sdel-$instance_hash $rule";
3208
				}
3209
				$css .= "</style>";
3210
			}
3211
3212
			return $css;
3213
		}
3214
	}
3215
}
3216