Passed
Push — master ( 6acded...886f0c )
by Brian
04:23
created

WP_Super_Duper::is_elementor_widget_output()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 4
nc 2
nop 0
dl 0
loc 7
rs 10
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( $this, '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 function render_shortcode() {
1286
			check_ajax_referer( 'super_duper_output_shortcode', '_ajax_nonce', true );
1287
			if ( ! current_user_can( 'manage_options' ) ) {
1288
				wp_die();
1289
			}
1290
1291
			// we might need the $post value here so lets set it.
1292
			if ( isset( $_POST['post_id'] ) && $_POST['post_id'] ) {
1293
				$post_obj = get_post( absint( $_POST['post_id'] ) );
1294
				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...
1295
					global $post;
1296
					$post = $post_obj;
1297
				}
1298
			}
1299
1300
			if ( isset( $_POST['shortcode'] ) && $_POST['shortcode'] ) {
1301
				$is_preview = $this->is_preview();
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
1311
						if ( ! empty( $value ) ) {
1312
							$value = wp_unslash( $value );
1313
1314
							// Encode [ and ].
1315
							if ( $is_preview ) {
1316
								$value = $this->encode_shortcodes( $value );
1317
							}
1318
						}
1319
						$attributes .= " " . sanitize_title_with_dashes( $key ) . "='" . esc_attr( $value ) . "' ";
1320
					}
1321
				}
1322
1323
				$shortcode = "[" . $shortcode_name . " " . $attributes . "]";
1324
1325
				$content = do_shortcode( $shortcode );
1326
1327
				// Decode [ and ].
1328
				if ( ! empty( $content ) && $is_preview ) {
1329
					$content = $this->decode_shortcodes( $content );
1330
				}
1331
1332
				echo $content;
0 ignored issues
show
Security Cross-Site Scripting introduced by
$content 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 1323
  3. Data is passed through do_shortcode(), and do_shortcode($shortcode) is assigned to $content
    in vendor/ayecode/wp-super-duper/wp-super-duper.php on line 1325
  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) . '='' . esc_attr($value) . '' ' is assigned to $attributes
    in vendor/ayecode/wp-super-duper/wp-super-duper.php on line 1319
  4. '[' . $shortcode_name . ' ' . $attributes . ']' is assigned to $shortcode
    in vendor/ayecode/wp-super-duper/wp-super-duper.php on line 1323
  5. Data is passed through do_shortcode(), and do_shortcode($shortcode) is assigned to $content
    in vendor/ayecode/wp-super-duper/wp-super-duper.php on line 1325

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...
1333
			}
1334
			wp_die();
1335
		}
1336
1337
		/**
1338
		 * Output the shortcode.
1339
		 *
1340
		 * @param array $args
1341
		 * @param string $content
1342
		 *
1343
		 * @return string
1344
		 */
1345
		public function shortcode_output( $args = array(), $content = '' ) {
1346
			$args = $this->argument_values( $args );
1347
1348
			// add extra argument so we know its a output to gutenberg
1349
			//$args
1350
			$args = $this->string_to_bool( $args );
1351
1352
			// if we have a enclosed shortcode we add it to the special `html` argument
1353
			if ( ! empty( $content ) ) {
1354
				$args['html'] = $content;
1355
			}
1356
1357
			$class = isset( $this->options['widget_ops']['classname'] ) ? esc_attr( $this->options['widget_ops']['classname'] ) : '';
1358
			$class .= " sdel-".$this->get_instance_hash();
1359
1360
			$class = apply_filters( 'wp_super_duper_div_classname', $class, $args, $this );
1361
			$class = apply_filters( 'wp_super_duper_div_classname_' . $this->base_id, $class, $args, $this );
1362
1363
			$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...
1364
			$attrs = apply_filters( 'wp_super_duper_div_attrs_' . $this->base_id, '', $args, $this );
1365
1366
			$shortcode_args = array();
1367
			$output         = '';
1368
			$no_wrap        = isset( $this->options['no_wrap'] ) && $this->options['no_wrap'] ? true : false;
1369
			if ( isset( $args['no_wrap'] ) && $args['no_wrap'] ) {
1370
				$no_wrap = true;
1371
			}
1372
			$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...
1373
			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...
1374
				// wrap the shortcode in a div with the same class as the widget
1375
				$output .= '<div class="' . $class . '" ' . $attrs . '>';
1376
				if ( ! empty( $args['title'] ) ) {
1377
					// if its a shortcode and there is a title try to grab the title wrappers
1378
					$shortcode_args = array( 'before_title' => '', 'after_title' => '' );
1379
					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...
1380
						global $wp_registered_sidebars;
1381
						if ( ! empty( $wp_registered_sidebars ) ) {
1382
							foreach ( $wp_registered_sidebars as $sidebar ) {
1383
								if ( ! empty( $sidebar['before_title'] ) ) {
1384
									$shortcode_args['before_title'] = $sidebar['before_title'];
1385
									$shortcode_args['after_title']  = $sidebar['after_title'];
1386
									break;
1387
								}
1388
							}
1389
						}
1390
					}
1391
					$output .= $this->output_title( $shortcode_args, $args );
1392
				}
1393
				$output .= $main_content;
1394
				$output .= '</div>';
1395
			} 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...
1396
				$output .= $main_content;
1397
			}
1398
1399
			// if preview show a placeholder if empty
1400
			if ( $this->is_preview() && $output == '' ) {
1401
				$output = $this->preview_placeholder_text( "{{" . $this->base_id . "}}" );
1402
			}
1403
1404
			return apply_filters( 'wp_super_duper_widget_output', $output, $args, $shortcode_args, $this );
1405
		}
1406
1407
		/**
1408
		 * Placeholder text to show if output is empty and we are on a preview/builder page.
1409
		 *
1410
		 * @param string $name
1411
		 *
1412
		 * @return string
1413
		 */
1414
		public function preview_placeholder_text( $name = '' ) {
1415
			return "<div style='background:#0185ba33;padding: 10px;border: 4px #ccc dashed;'>" . sprintf( __( 'Placeholder for: %s' ), $name ) . "</div>";
1416
		}
1417
1418
		/**
1419
		 * Sometimes booleans values can be turned to strings, so we fix that.
1420
		 *
1421
		 * @param $options
1422
		 *
1423
		 * @return mixed
1424
		 */
1425
		public function string_to_bool( $options ) {
1426
			// convert bool strings to booleans
1427
			foreach ( $options as $key => $val ) {
1428
				if ( $val == 'false' ) {
1429
					$options[ $key ] = false;
1430
				} elseif ( $val == 'true' ) {
1431
					$options[ $key ] = true;
1432
				}
1433
			}
1434
1435
			return $options;
1436
		}
1437
1438
		/**
1439
		 * Get the argument values that are also filterable.
1440
		 *
1441
		 * @param $instance
1442
		 *
1443
		 * @since 1.0.12 Don't set checkbox default value if the value is empty.
1444
		 *
1445
		 * @return array
1446
		 */
1447
		public function argument_values( $instance ) {
1448
			$argument_values = array();
1449
1450
			// set widget instance
1451
			$this->instance = $instance;
1452
1453
			if ( empty( $this->arguments ) ) {
1454
				$this->arguments = $this->get_arguments();
1455
			}
1456
1457
			if ( ! empty( $this->arguments ) ) {
1458
				foreach ( $this->arguments as $key => $args ) {
1459
					// set the input name from the key
1460
					$args['name'] = $key;
1461
					//
1462
					$argument_values[ $key ] = isset( $instance[ $key ] ) ? $instance[ $key ] : '';
1463
					if ( $args['type'] == 'checkbox' && $argument_values[ $key ] == '' ) {
1464
						// don't set default for an empty checkbox
1465
					} elseif ( $argument_values[ $key ] == '' && isset( $args['default'] ) ) {
1466
						$argument_values[ $key ] = $args['default'];
1467
					}
1468
				}
1469
			}
1470
1471
			return $argument_values;
1472
		}
1473
1474
		/**
1475
		 * Set arguments in super duper.
1476
		 *
1477
		 * @since 1.0.0
1478
		 *
1479
		 * @return array Set arguments.
1480
		 */
1481
		public function set_arguments() {
1482
			return $this->arguments;
1483
		}
1484
1485
		/**
1486
		 * Get arguments in super duper.
1487
		 *
1488
		 * @since 1.0.0
1489
		 *
1490
		 * @return array Get arguments.
1491
		 */
1492
		public function get_arguments() {
1493
			if ( empty( $this->arguments ) ) {
1494
				$this->arguments = $this->set_arguments();
1495
			}
1496
1497
			$this->arguments = apply_filters( 'wp_super_duper_arguments', $this->arguments, $this->options, $this->instance );
1498
			$this->arguments = $this->add_name_from_key( $this->arguments, true );
1499
1500
			return $this->arguments;
1501
		}
1502
1503
		/**
1504
		 * This is the main output class for all 3 items, widget, shortcode and block, it is extended in the calling class.
1505
		 *
1506
		 * @param array $args
1507
		 * @param array $widget_args
1508
		 * @param string $content
1509
		 */
1510
		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

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

2112
		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...
2113
2114
			// check for row
2115
			if(!empty($args['row'])){
2116
2117
				if(!empty($args['row']['open'])){
2118
2119
				// element require
2120
				$element_require = ! empty( $args['element_require'] ) ? $this->block_props_replace( $args['element_require'], true ) . " && " : "";
2121
				echo $element_require;
2122
2123
					if(false){?><script><?php }?>
2124
						el('div', {
2125
								className: 'bsui components-base-control',
2126
							},
2127
							<?php if(!empty($args['row']['title'])){ ?>
2128
							el('label', {
2129
									className: 'components-base-control__label',
2130
								},
2131
								'<?php echo addslashes( $args['row']['title'] ); ?>'
2132
							),
2133
							<?php }?>
2134
							<?php if(!empty($args['row']['desc'])){ ?>
2135
							el('p', {
2136
									className: 'components-base-control__help mb-0',
2137
								},
2138
								'<?php echo addslashes( $args['row']['desc'] ); ?>'
2139
							),
2140
							<?php }?>
2141
							el(
2142
								'div',
2143
								{
2144
									className: 'row mb-n2 <?php if(!empty($args['row']['class'])){ echo esc_attr($args['row']['class']);} ?>',
2145
								},
2146
								el(
2147
									'div',
2148
									{
2149
										className: 'col pr-2',
2150
									},
2151
2152
					<?php
2153
					if(false){?></script><?php }
2154
				}elseif(!empty($args['row']['close'])){
2155
					if(false){?><script><?php }?>
2156
						el(
2157
							'div',
2158
							{
2159
								className: 'col pl-0',
2160
							},
2161
					<?php
2162
					if(false){?></script><?php }
2163
				}else{
2164
					if(false){?><script><?php }?>
2165
						el(
2166
							'div',
2167
							{
2168
								className: 'col pl-0 pr-2',
2169
							},
2170
					<?php
2171
					if(false){?></script><?php }
2172
				}
2173
2174
			}
2175
2176
		}
2177
2178
		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

2178
		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...
2179
2180
			if(!empty($args['row'])){
2181
				// maybe close
2182
				if(!empty($args['row']['close'])){
2183
					echo "))";
2184
				}
2185
2186
				echo "),";
2187
			}
2188
		}
2189
2190
		public function build_block_arguments( $key, $args ) {
2191
			$custom_attributes = ! empty( $args['custom_attributes'] ) ? $this->array_to_attributes( $args['custom_attributes'] ) : '';
2192
			$options           = '';
2193
			$extra             = '';
2194
			$require           = '';
0 ignored issues
show
Unused Code introduced by
The assignment to $require is dead and can be removed.
Loading history...
2195
2196
			// `content` is a protected and special argument
2197
			if ( $key == 'content' ) {
2198
				return;
2199
			}
2200
2201
2202
			// icon
2203
			$icon = '';
2204
			if( !empty( $args['icon'] ) ){
2205
				$icon .= "el('div', {";
2206
									$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

2206
									$icon .= "dangerouslySetInnerHTML: {__html: '".self::/** @scrutinizer ignore-call */ get_widget_icon( esc_attr($args['icon']))."'},";
Loading history...
2207
									$icon .= "className: 'text-center',";
2208
									$icon .= "title: '".addslashes( $args['title'] )."',";
2209
								$icon .= "}),";
2210
2211
				// blank title as its added to the icon.
2212
				$args['title'] = '';
2213
			}
2214
2215
			// require advanced
2216
			$require_advanced = ! empty( $args['advanced'] ) ? "props.attributes.show_advanced && " : "";
2217
2218
			// element require
2219
			$element_require = ! empty( $args['element_require'] ) ? $this->block_props_replace( $args['element_require'], true ) . " && " : "";
2220
2221
2222
			$onchange  = "props.setAttributes({ $key: $key } )";
2223
			$onchangecomplete  = "";
2224
			$value     = "props.attributes.$key";
2225
			$text_type = array( 'text', 'password', 'number', 'email', 'tel', 'url', 'colorx' );
2226
			if ( in_array( $args['type'], $text_type ) ) {
2227
				$type = 'TextControl';
2228
				// Save numbers as numbers and not strings
2229
				if ( $args['type'] == 'number' ) {
2230
					$onchange = "props.setAttributes({ $key: Number($key) } )";
2231
				}
2232
			}
2233
			/*
2234
			 * https://www.wptricks.com/question/set-current-tab-on-a-gutenberg-tabpanel-component-from-outside-that-component/ es5 layout
2235
						elseif($args['type']=='tabs'){
2236
							?>
2237
							<script>
2238
								el(
2239
									wp.components.TabPanel,
2240
									{
2241
										tabs: [
2242
											{
2243
												name: 'show',
2244
												title: __( 'Show', 'my-textdomain' ),
2245
											},
2246
											{
2247
												name: 'edit',
2248
												title: __( 'Edit', 'my-textdomain' ),
2249
											},
2250
										],
2251
									},
2252
									( tab ) => {
2253
2254
									if('show' === tab.name){
2255
									return 123;
2256
								}else if ( 'edit' === tab.name ) {
2257
									return 321;
2258
								}
2259
2260
								}
2261
								),
2262
							</script>
2263
							<?php
2264
							return;
2265
						}
2266
			*/
2267
			elseif ( $args['type'] == 'color' ) {
2268
				$type = 'ColorPicker';
2269
				$onchange = "";
2270
				$extra = "color: $value,";
2271
				if(!empty($args['disable_alpha'])){
2272
					$extra .= "disableAlpha: true,";
2273
				}
2274
				$onchangecomplete = "onChangeComplete: function($key) {
2275
				value =  $key.rgb.a && $key.rgb.a < 1 ? \"rgba(\"+$key.rgb.r+\",\"+$key.rgb.g+\",\"+$key.rgb.b+\",\"+$key.rgb.a+\")\" : $key.hex;
2276
                        props.setAttributes({
2277
                            $key: value
2278
                        });
2279
                    },";
2280
			}
2281
			elseif ( $args['type'] == 'checkbox' ) {
2282
				$type = 'CheckboxControl';
2283
				$extra .= "checked: props.attributes.$key,";
2284
				$onchange = "props.setAttributes({ $key: ! props.attributes.$key } )";
2285
			} elseif ( $args['type'] == 'textarea' ) {
2286
				$type = 'TextareaControl';
2287
			} elseif ( $args['type'] == 'select' || $args['type'] == 'multiselect' ) {
2288
				$type = 'SelectControl';
2289
2290
				if($args['name'] == 'category' && !empty($args['post_type_linked'])){
2291
					$options .= "options: taxonomies_".str_replace("-","_", $this->id).",";
2292
				}elseif($args['name'] == 'sort_by' && !empty($args['post_type_linked'])){
2293
					$options .= "options: sort_by_".str_replace("-","_", $this->id).",";
2294
				}else {
2295
2296
					if ( ! empty( $args['options'] ) ) {
2297
						$options .= "options: [";
2298
						foreach ( $args['options'] as $option_val => $option_label ) {
2299
							$options .= "{ value: '" . esc_attr( $option_val ) . "', label: '" . addslashes( $option_label ) . "' },";
2300
						}
2301
						$options .= "],";
2302
					}
2303
				}
2304
				if ( isset( $args['multiple'] ) && $args['multiple'] ) { //@todo multiselect does not work at the moment: https://github.com/WordPress/gutenberg/issues/5550
2305
					$extra .= ' multiple: true, ';
2306
				}
2307
			} elseif ( $args['type'] == 'alignment' ) {
2308
				$type = 'AlignmentToolbar'; // @todo this does not seem to work but cant find a example
2309
			}elseif ( $args['type'] == 'margins' ) {
2310
2311
			} else {
2312
				return;// if we have not implemented the control then don't break the JS.
2313
			}
2314
2315
2316
2317
			// color input does not show the labels so we add them
2318
			if($args['type']=='color'){
2319
				// add show only if advanced
2320
				echo $require_advanced;
2321
				// add setting require if defined
2322
				echo $element_require;
2323
				echo "el('div', {style: {'marginBottom': '8px'}}, '".addslashes( $args['title'] )."'),";
2324
			}
2325
2326
			// add show only if advanced
2327
			echo $require_advanced;
2328
			// add setting require if defined
2329
			echo $element_require;
2330
2331
			// icon
2332
			echo $icon;
2333
			?>
2334
			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...
2335
			label: '<?php echo addslashes( $args['title'] ); ?>',
2336
			help: '<?php if ( isset( $args['desc'] ) ) {
2337
				echo addslashes( $args['desc'] );
2338
			} ?>',
2339
			value: <?php echo $value; ?>,
2340
			<?php if ( $type == 'TextControl' && $args['type'] != 'text' ) {
2341
				echo "type: '" . addslashes( $args['type'] ) . "',";
2342
			} ?>
2343
			<?php if ( ! empty( $args['placeholder'] ) ) {
2344
				echo "placeholder: '" . addslashes( $args['placeholder'] ) . "',";
2345
			} ?>
2346
			<?php echo $options; ?>
2347
			<?php echo $extra; ?>
2348
			<?php echo $custom_attributes; ?>
2349
			<?php echo $onchangecomplete;?>
2350
			onChange: function ( <?php echo $key; ?> ) {
2351
			<?php echo $onchange; ?>
2352
			}
2353
			} ),
2354
			<?php
2355
2356
2357
		}
2358
2359
		/**
2360
		 * Convert an array of attributes to block string.
2361
		 *
2362
		 * @todo there is prob a faster way to do this, also we could add some validation here.
2363
		 *
2364
		 * @param $custom_attributes
2365
		 *
2366
		 * @return string
2367
		 */
2368
		public function array_to_attributes( $custom_attributes, $html = false ) {
2369
			$attributes = '';
2370
			if ( ! empty( $custom_attributes ) ) {
2371
2372
				if ( $html ) {
2373
					foreach ( $custom_attributes as $key => $val ) {
2374
						$attributes .= " $key='$val' ";
2375
					}
2376
				} else {
2377
					foreach ( $custom_attributes as $key => $val ) {
2378
						$attributes .= "'$key': '$val',";
2379
					}
2380
				}
2381
			}
2382
2383
			return $attributes;
2384
		}
2385
2386
		/**
2387
		 * A self looping function to create the output for JS block elements.
2388
		 *
2389
		 * This is what is output in the WP Editor visual view.
2390
		 *
2391
		 * @param $args
2392
		 */
2393
		public function block_element( $args ) {
2394
2395
2396
			if ( ! empty( $args ) ) {
2397
				foreach ( $args as $element => $new_args ) {
2398
2399
					if ( is_array( $new_args ) ) { // its an element
2400
2401
2402
						if ( isset( $new_args['element'] ) ) {
2403
2404
							if ( isset( $new_args['element_require'] ) ) {
2405
								echo str_replace( array(
2406
										"'+",
2407
										"+'"
2408
									), '', $this->block_props_replace( $new_args['element_require'] ) ) . " &&  ";
2409
								unset( $new_args['element_require'] );
2410
							}
2411
2412
							echo "\n el( '" . $new_args['element'] . "', {";
2413
2414
							// get the attributes
2415
							foreach ( $new_args as $new_key => $new_value ) {
2416
2417
2418
								if ( $new_key == 'element' || $new_key == 'content' || $new_key == 'element_require' || $new_key == 'element_repeat' || is_array( $new_value ) ) {
2419
									// do nothing
2420
								} else {
2421
									echo $this->block_element( array( $new_key => $new_value ) );
2422
								}
2423
							}
2424
2425
							echo "},";// end attributes
2426
2427
							// get the content
2428
							$first_item = 0;
2429
							foreach ( $new_args as $new_key => $new_value ) {
2430
								if ( $new_key === 'content' || is_array( $new_value ) ) {
2431
2432
									if ( $new_key === 'content' ) {
2433
										echo "'" . $this->block_props_replace( wp_slash( $new_value ) ) . "'";
2434
									}
2435
2436
									if ( is_array( $new_value ) ) {
2437
2438
										if ( isset( $new_value['element_require'] ) ) {
2439
											echo str_replace( array(
2440
													"'+",
2441
													"+'"
2442
												), '', $this->block_props_replace( $new_value['element_require'] ) ) . " &&  ";
2443
											unset( $new_value['element_require'] );
2444
										}
2445
2446
										if ( isset( $new_value['element_repeat'] ) ) {
2447
											$x = 1;
2448
											while ( $x <= absint( $new_value['element_repeat'] ) ) {
2449
												$this->block_element( array( '' => $new_value ) );
2450
												$x ++;
2451
											}
2452
										} else {
2453
											$this->block_element( array( '' => $new_value ) );
2454
										}
2455
									}
2456
									$first_item ++;
2457
								}
2458
							}
2459
2460
							echo ")";// end content
2461
2462
							echo ", \n";
2463
2464
						}
2465
					} else {
2466
2467
						if ( substr( $element, 0, 3 ) === "if_" ) {
2468
							echo str_replace( "if_", "", $element ) . ": " . $this->block_props_replace( $new_args, true ) . ",";
2469
						} elseif ( $element == 'style' ) {
2470
							echo $element . ": " . $this->block_props_replace( $new_args ) . ",";
2471
						} else {
2472
							echo $element . ": '" . $this->block_props_replace( $new_args ) . "',";
2473
						}
2474
2475
					}
2476
				}
2477
			}
2478
		}
2479
2480
		/**
2481
		 * Replace block attributes placeholders with the proper naming.
2482
		 *
2483
		 * @param $string
2484
		 *
2485
		 * @return mixed
2486
		 */
2487
		public function block_props_replace( $string, $no_wrap = false ) {
2488
2489
			if ( $no_wrap ) {
2490
				$string = str_replace( array( "[%", "%]" ), array( "props.attributes.", "" ), $string );
2491
			} else {
2492
				$string = str_replace( array( "[%", "%]" ), array( "'+props.attributes.", "+'" ), $string );
2493
			}
2494
2495
			return $string;
2496
		}
2497
2498
		/**
2499
		 * Outputs the content of the widget
2500
		 *
2501
		 * @param array $args
2502
		 * @param array $instance
2503
		 */
2504
		public function widget( $args, $instance ) {
2505
2506
			// get the filtered values
2507
			$argument_values = $this->argument_values( $instance );
2508
			$argument_values = $this->string_to_bool( $argument_values );
2509
			$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...
2510
2511
			$no_wrap = false;
2512
			if ( isset( $argument_values['no_wrap'] ) && $argument_values['no_wrap'] ) {
2513
				$no_wrap = true;
2514
			}
2515
2516
			ob_start();
2517
			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...
2518
2519
				$class_original = $this->options['widget_ops']['classname'];
2520
				$class = $this->options['widget_ops']['classname']." sdel-".$this->get_instance_hash();
2521
2522
				// Before widget
2523
				$before_widget = $args['before_widget'];
2524
				$before_widget = str_replace($class_original,$class,$before_widget);
2525
				$before_widget = apply_filters( 'wp_super_duper_before_widget', $before_widget, $args, $instance, $this );
2526
				$before_widget = apply_filters( 'wp_super_duper_before_widget_' . $this->base_id, $before_widget, $args, $instance, $this );
2527
2528
				// After widget
2529
				$after_widget = $args['after_widget'];
2530
				$after_widget = apply_filters( 'wp_super_duper_after_widget', $after_widget, $args, $instance, $this );
2531
				$after_widget = apply_filters( 'wp_super_duper_after_widget_' . $this->base_id, $after_widget, $args, $instance, $this );
2532
2533
				echo $before_widget;
2534
				// elementor strips the widget wrapping div so we check for and add it back if needed
2535
				if ( $this->is_elementor_widget_output() ) {
2536
					// Filter class & attrs for elementor widget output.
2537
					$class = apply_filters( 'wp_super_duper_div_classname', $class, $args, $this );
2538
					$class = apply_filters( 'wp_super_duper_div_classname_' . $this->base_id, $class, $args, $this );
2539
2540
					$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...
2541
					$attrs = apply_filters( 'wp_super_duper_div_attrs_' . $this->base_id, '', $args, $this );
2542
2543
					echo "<span class='" . esc_attr( $class  ) . "' " . $attrs . ">";
2544
				}
2545
				echo $this->output_title( $args, $instance );
2546
				echo $output;
2547
				if ( $this->is_elementor_widget_output() ) {
2548
					echo "</span>";
2549
				}
2550
				echo $after_widget;
2551
			} elseif ( $this->is_preview() && $output == '' ) {// if preview show a placeholder if empty
2552
				$output = $this->preview_placeholder_text( "{{" . $this->base_id . "}}" );
2553
				echo $output;
2554
			} 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...
2555
				echo $output;
2556
			}
2557
			$output = ob_get_clean();
2558
2559
			$output = apply_filters( 'wp_super_duper_widget_output', $output, $instance, $args, $this );
2560
2561
			echo $output;
2562
		}
2563
2564
		/**
2565
		 * Tests if the current output is inside a elementor container.
2566
		 *
2567
		 * @since 1.0.4
2568
		 * @return bool
2569
		 */
2570
		public function is_elementor_widget_output() {
2571
			$result = false;
2572
			if ( defined( 'ELEMENTOR_VERSION' ) && isset( $this->number ) && $this->number == 'REPLACE_TO_ID' ) {
2573
				$result = true;
2574
			}
2575
2576
			return $result;
2577
		}
2578
2579
		/**
2580
		 * Tests if the current output is inside a elementor preview.
2581
		 *
2582
		 * @since 1.0.4
2583
		 * @return bool
2584
		 */
2585
		public function is_elementor_preview() {
2586
			$result = false;
2587
			if ( isset( $_REQUEST['elementor-preview'] ) || ( is_admin() && isset( $_REQUEST['action'] ) && $_REQUEST['action'] == 'elementor' ) || ( isset( $_REQUEST['action'] ) && $_REQUEST['action'] == 'elementor_ajax' ) ) {
2588
				$result = true;
2589
			}
2590
2591
			return $result;
2592
		}
2593
2594
		/**
2595
		 * Tests if the current output is inside a Divi preview.
2596
		 *
2597
		 * @since 1.0.6
2598
		 * @return bool
2599
		 */
2600
		public function is_divi_preview() {
2601
			$result = false;
2602
			if ( isset( $_REQUEST['et_fb'] ) || isset( $_REQUEST['et_pb_preview'] ) || ( is_admin() && isset( $_REQUEST['action'] ) && $_REQUEST['action'] == 'elementor' ) ) {
2603
				$result = true;
2604
			}
2605
2606
			return $result;
2607
		}
2608
2609
		/**
2610
		 * Tests if the current output is inside a Beaver builder preview.
2611
		 *
2612
		 * @since 1.0.6
2613
		 * @return bool
2614
		 */
2615
		public function is_beaver_preview() {
2616
			$result = false;
2617
			if ( isset( $_REQUEST['fl_builder'] ) ) {
2618
				$result = true;
2619
			}
2620
2621
			return $result;
2622
		}
2623
2624
		/**
2625
		 * Tests if the current output is inside a siteorigin builder preview.
2626
		 *
2627
		 * @since 1.0.6
2628
		 * @return bool
2629
		 */
2630
		public function is_siteorigin_preview() {
2631
			$result = false;
2632
			if ( ! empty( $_REQUEST['siteorigin_panels_live_editor'] ) ) {
2633
				$result = true;
2634
			}
2635
2636
			return $result;
2637
		}
2638
2639
		/**
2640
		 * Tests if the current output is inside a cornerstone builder preview.
2641
		 *
2642
		 * @since 1.0.8
2643
		 * @return bool
2644
		 */
2645
		public function is_cornerstone_preview() {
2646
			$result = false;
2647
			if ( ! empty( $_REQUEST['cornerstone_preview'] ) || basename( $_SERVER['REQUEST_URI'] ) == 'cornerstone-endpoint' ) {
2648
				$result = true;
2649
			}
2650
2651
			return $result;
2652
		}
2653
2654
		/**
2655
		 * Tests if the current output is inside a fusion builder preview.
2656
		 *
2657
		 * @since 1.1.0
2658
		 * @return bool
2659
		 */
2660
		public function is_fusion_preview() {
2661
			$result = false;
2662
			if ( ! empty( $_REQUEST['fb-edit'] ) || ! empty( $_REQUEST['fusion_load_nonce'] ) ) {
2663
				$result = true;
2664
			}
2665
2666
			return $result;
2667
		}
2668
2669
		/**
2670
		 * Tests if the current output is inside a Oxygen builder preview.
2671
		 *
2672
		 * @since 1.0.18
2673
		 * @return bool
2674
		 */
2675
		public function is_oxygen_preview() {
2676
			$result = false;
2677
			if ( ! empty( $_REQUEST['ct_builder'] ) || ( ! empty( $_REQUEST['action'] ) && ( substr( $_REQUEST['action'], 0, 11 ) === "oxy_render_" || substr( $_REQUEST['action'], 0, 10 ) === "ct_render_" ) ) ) {
2678
				$result = true;
2679
			}
2680
2681
			return $result;
2682
		}
2683
2684
		/**
2685
		 * General function to check if we are in a preview situation.
2686
		 *
2687
		 * @since 1.0.6
2688
		 * @return bool
2689
		 */
2690
		public function is_preview() {
2691
			$preview = false;
2692
			if ( $this->is_divi_preview() ) {
2693
				$preview = true;
2694
			} elseif ( $this->is_elementor_preview() ) {
2695
				$preview = true;
2696
			} elseif ( $this->is_beaver_preview() ) {
2697
				$preview = true;
2698
			} elseif ( $this->is_siteorigin_preview() ) {
2699
				$preview = true;
2700
			} elseif ( $this->is_cornerstone_preview() ) {
2701
				$preview = true;
2702
			} elseif ( $this->is_fusion_preview() ) {
2703
				$preview = true;
2704
			} elseif ( $this->is_oxygen_preview() ) {
2705
				$preview = true;
2706
			} elseif( $this->is_block_content_call() ) {
2707
				$preview = true;
2708
			}
2709
2710
			return $preview;
2711
		}
2712
2713
		/**
2714
		 * Output the super title.
2715
		 *
2716
		 * @param $args
2717
		 * @param array $instance
2718
		 *
2719
		 * @return string
2720
		 */
2721
		public function output_title( $args, $instance = array() ) {
2722
			$output = '';
2723
			if ( ! empty( $instance['title'] ) ) {
2724
				/** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */
2725
				$title  = apply_filters( 'widget_title', $instance['title'], $instance, $this->id_base );
2726
2727
				if(empty($instance['widget_title_tag'])){
2728
					$output = $args['before_title'] . $title . $args['after_title'];
2729
				}else{
2730
					$title_tag = esc_attr( $instance['widget_title_tag'] );
2731
2732
					// classes
2733
					$title_classes = array();
2734
					$title_classes[] = !empty( $instance['widget_title_size_class'] ) ? sanitize_html_class( $instance['widget_title_size_class'] ) : '';
2735
					$title_classes[] = !empty( $instance['widget_title_align_class'] ) ? sanitize_html_class( $instance['widget_title_align_class'] ) : '';
2736
					$title_classes[] = !empty( $instance['widget_title_color_class'] ) ? "text-".sanitize_html_class( $instance['widget_title_color_class'] ) : '';
2737
					$title_classes[] = !empty( $instance['widget_title_border_class'] ) ? sanitize_html_class( $instance['widget_title_border_class'] ) : '';
2738
					$title_classes[] = !empty( $instance['widget_title_border_color_class'] ) ? "border-".sanitize_html_class( $instance['widget_title_border_color_class'] ) : '';
2739
					$title_classes[] = !empty( $instance['widget_title_mt_class'] ) ? "mt-".absint( $instance['widget_title_mt_class'] ) : '';
2740
					$title_classes[] = !empty( $instance['widget_title_mr_class'] ) ? "mr-".absint( $instance['widget_title_mr_class'] ) : '';
2741
					$title_classes[] = !empty( $instance['widget_title_mb_class'] ) ? "mb-".absint( $instance['widget_title_mb_class'] ) : '';
2742
					$title_classes[] = !empty( $instance['widget_title_ml_class'] ) ? "ml-".absint( $instance['widget_title_ml_class'] ) : '';
2743
					$title_classes[] = !empty( $instance['widget_title_pt_class'] ) ? "pt-".absint( $instance['widget_title_pt_class'] ) : '';
2744
					$title_classes[] = !empty( $instance['widget_title_pr_class'] ) ? "pr-".absint( $instance['widget_title_pr_class'] ) : '';
2745
					$title_classes[] = !empty( $instance['widget_title_pb_class'] ) ? "pb-".absint( $instance['widget_title_pb_class'] ) : '';
2746
					$title_classes[] = !empty( $instance['widget_title_pl_class'] ) ? "pl-".absint( $instance['widget_title_pl_class'] ) : '';
2747
2748
					$class = !empty( $title_classes ) ? implode(" ",$title_classes) : '';
2749
					$output = "<$title_tag class='$class' >$title</$title_tag>";
2750
				}
2751
2752
			}
2753
2754
			return $output;
2755
		}
2756
2757
		/**
2758
		 * Outputs the options form inputs for the widget.
2759
		 *
2760
		 * @param array $instance The widget options.
2761
		 */
2762
		public function form( $instance ) {
2763
2764
			// set widget instance
2765
			$this->instance = $instance;
2766
2767
			// set it as a SD widget
2768
			echo $this->widget_advanced_toggle();
2769
2770
			echo "<p>" . esc_attr( $this->options['widget_ops']['description'] ) . "</p>";
2771
			$arguments_raw = $this->get_arguments();
2772
2773
			if ( is_array( $arguments_raw ) ) {
0 ignored issues
show
introduced by
The condition is_array($arguments_raw) is always true.
Loading history...
2774
2775
				$arguments = $this->group_arguments( $arguments_raw );
2776
2777
				// Do we have sections?
2778
				$has_sections = $arguments == $arguments_raw ? false : true;
2779
2780
2781
				if ( $has_sections ) {
2782
					$panel_count = 0;
2783
					foreach ( $arguments as $key => $args ) {
2784
2785
						?>
2786
						<script>
2787
							//							jQuery(this).find("i").toggleClass("fas fa-chevron-up fas fa-chevron-down");jQuery(this).next().toggle();
2788
						</script>
2789
						<?php
2790
2791
						$hide       = $panel_count ? ' style="display:none;" ' : '';
2792
						$icon_class = $panel_count ? 'fas fa-chevron-up' : 'fas fa-chevron-down';
2793
						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>";
2794
						echo "<div class='sd-toggle-group sd-input-group-" . sanitize_title_with_dashes( $key ) . "' $hide>";
2795
2796
						foreach ( $args as $k => $a ) {
2797
2798
							$this->widget_inputs_row_start($k, $a);
2799
							$this->widget_inputs( $a, $instance );
2800
							$this->widget_inputs_row_end($k, $a);
2801
2802
						}
2803
2804
						echo "</div>";
2805
2806
						$panel_count ++;
2807
2808
					}
2809
				} else {
2810
					foreach ( $arguments as $key => $args ) {
2811
						$this->widget_inputs_row_start($key, $args);
2812
						$this->widget_inputs( $args, $instance );
2813
						$this->widget_inputs_row_end($key, $args);
2814
					}
2815
				}
2816
2817
			}
2818
		}
2819
2820
		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

2820
		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...
2821
			if(!empty($args['row'])){
2822
				// maybe open
2823
				if(!empty($args['row']['open'])){
2824
					?>
2825
					<div class='bsui sd-argument ' data-argument='<?php echo esc_attr( $args['row']['key'] ); ?>' data-element_require='<?php if ( !empty($args['row']['element_require'])) {
2826
						echo $this->convert_element_require( $args['row']['element_require'] );
2827
					} ?>'>
2828
					<?php if(!empty($args['row']['title'])){ ?>
2829
					<label class="mb-0 "><?php echo esc_attr( $args['row']['title'] ); ?><?php echo $this->widget_field_desc( $args['row'] ); ?></label>
2830
					<?php }?>
2831
					<div class='row <?php if(!empty($args['row']['class'])){ echo esc_attr($args['row']['class']);} ?>'>
2832
					<div class='col pr-2'>
2833
					<?php
2834
				}elseif(!empty($args['row']['close'])){
2835
					echo "<div class='col pl-0'>";
2836
				}else{
2837
					echo "<div class='col pl-0 pr-2'>";
2838
				}
2839
			}
2840
		}
2841
2842
		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

2842
		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...
2843
2844
			if(!empty($args['row'])){
2845
				// maybe close
2846
				if(!empty($args['row']['close'])){
2847
					echo "</div></div>";
2848
				}
2849
2850
				echo "</div>";
2851
			}
2852
		}
2853
2854
		/**
2855
		 * Get the hidden input that when added makes the advanced button show on widget settings.
2856
		 *
2857
		 * @return string
2858
		 */
2859
		public function widget_advanced_toggle() {
2860
2861
			$output = '';
2862
			if ( $this->block_show_advanced() ) {
2863
				$val = 1;
2864
			} else {
2865
				$val = 0;
2866
			}
2867
2868
			$output .= "<input type='hidden'  class='sd-show-advanced' value='$val' />";
2869
2870
			return $output;
2871
		}
2872
2873
		/**
2874
		 * Convert require element.
2875
		 *
2876
		 * @since 1.0.0
2877
		 *
2878
		 * @param string $input Input element.
2879
		 *
2880
		 * @return string $output
2881
		 */
2882
		public function convert_element_require( $input ) {
2883
2884
			$input = str_replace( "'", '"', $input );// we only want double quotes
2885
2886
			$output = esc_attr( str_replace( array( "[%", "%]" ), array(
2887
				"jQuery(form).find('[data-argument=\"",
2888
				"\"]').find('input,select,textarea').val()"
2889
			), $input ) );
2890
2891
			return $output;
2892
		}
2893
2894
		/**
2895
		 * Builds the inputs for the widget options.
2896
		 *
2897
		 * @param $args
2898
		 * @param $instance
2899
		 */
2900
		public function widget_inputs( $args, $instance ) {
2901
2902
			$class             = "";
2903
			$element_require   = "";
2904
			$custom_attributes = "";
2905
2906
			// get value
2907
			if ( isset( $instance[ $args['name'] ] ) ) {
2908
				$value = $instance[ $args['name'] ];
2909
			} elseif ( ! isset( $instance[ $args['name'] ] ) && ! empty( $args['default'] ) ) {
2910
				$value = is_array( $args['default'] ) ? array_map( "esc_html", $args['default'] ) : esc_html( $args['default'] );
2911
			} else {
2912
				$value = '';
2913
			}
2914
2915
			// get placeholder
2916
			if ( ! empty( $args['placeholder'] ) ) {
2917
				$placeholder = "placeholder='" . esc_html( $args['placeholder'] ) . "'";
2918
			} else {
2919
				$placeholder = '';
2920
			}
2921
2922
			// get if advanced
2923
			if ( isset( $args['advanced'] ) && $args['advanced'] ) {
2924
				$class .= " sd-advanced-setting ";
2925
			}
2926
2927
			// element_require
2928
			if ( isset( $args['element_require'] ) && $args['element_require'] ) {
2929
				$element_require = $args['element_require'];
2930
			}
2931
2932
			// custom_attributes
2933
			if ( isset( $args['custom_attributes'] ) && $args['custom_attributes'] ) {
2934
				$custom_attributes = $this->array_to_attributes( $args['custom_attributes'], true );
2935
			}
2936
2937
2938
			// before wrapper
2939
			?>
2940
			<p class="sd-argument <?php echo esc_attr( $class ); ?>"
2941
			data-argument='<?php echo esc_attr( $args['name'] ); ?>'
2942
			data-element_require='<?php if ( $element_require ) {
2943
				echo $this->convert_element_require( $element_require );
2944
			} ?>'
2945
			>
2946
			<?php
2947
2948
2949
			switch ( $args['type'] ) {
2950
				//array('text','password','number','email','tel','url','color')
2951
				case "text":
2952
				case "password":
2953
				case "number":
2954
				case "email":
2955
				case "tel":
2956
				case "url":
2957
				case "color":
2958
					?>
2959
					<label
2960
						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>
2961
					<input <?php echo $placeholder; ?> class="widefat"
2962
						<?php echo $custom_attributes; ?>
2963
						                               id="<?php echo esc_attr( $this->get_field_id( $args['name'] ) ); ?>"
2964
						                               name="<?php echo esc_attr( $this->get_field_name( $args['name'] ) ); ?>"
2965
						                               type="<?php echo esc_attr( $args['type'] ); ?>"
2966
						                               value="<?php echo esc_attr( $value ); ?>">
2967
					<?php
2968
2969
					break;
2970
				case "select":
2971
					$multiple = isset( $args['multiple'] ) && $args['multiple'] ? true : false;
2972
					if ( $multiple ) {
2973
						if ( empty( $value ) ) {
2974
							$value = array();
2975
						}
2976
					}
2977
					?>
2978
					<label
2979
						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>
2980
					<select <?php echo $placeholder; ?> class="widefat"
2981
						<?php echo $custom_attributes; ?>
2982
						                                id="<?php echo esc_attr( $this->get_field_id( $args['name'] ) ); ?>"
2983
						                                name="<?php echo esc_attr( $this->get_field_name( $args['name'] ) );
2984
						                                if ( $multiple ) {
2985
							                                echo "[]";
2986
						                                } ?>"
2987
						<?php if ( $multiple ) {
2988
							echo "multiple";
2989
						} //@todo not implemented yet due to gutenberg not supporting it
2990
						?>
2991
					>
2992
						<?php
2993
2994
						if ( ! empty( $args['options'] ) ) {
2995
							foreach ( $args['options'] as $val => $label ) {
2996
								if ( $multiple ) {
2997
									$selected = in_array( $val, $value ) ? 'selected="selected"' : '';
2998
								} else {
2999
									$selected = selected( $value, $val, false );
3000
								}
3001
								echo "<option value='$val' " . $selected . ">$label</option>";
3002
							}
3003
						}
3004
						?>
3005
					</select>
3006
					<?php
3007
					break;
3008
				case "checkbox":
3009
					?>
3010
					<input <?php echo $placeholder; ?>
3011
						<?php checked( 1, $value, true ) ?>
3012
						<?php echo $custom_attributes; ?>
3013
						class="widefat" id="<?php echo esc_attr( $this->get_field_id( $args['name'] ) ); ?>"
3014
						name="<?php echo esc_attr( $this->get_field_name( $args['name'] ) ); ?>" type="checkbox"
3015
						value="1">
3016
					<label
3017
						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>
3018
					<?php
3019
					break;
3020
				case "textarea":
3021
					?>
3022
					<label
3023
						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>
3024
					<textarea <?php echo $placeholder; ?> class="widefat"
3025
						<?php echo $custom_attributes; ?>
3026
						                                  id="<?php echo esc_attr( $this->get_field_id( $args['name'] ) ); ?>"
3027
						                                  name="<?php echo esc_attr( $this->get_field_name( $args['name'] ) ); ?>"
3028
					><?php echo esc_attr( $value ); ?></textarea>
3029
					<?php
3030
3031
					break;
3032
				case "hidden":
3033
					?>
3034
					<input id="<?php echo esc_attr( $this->get_field_id( $args['name'] ) ); ?>"
3035
					       name="<?php echo esc_attr( $this->get_field_name( $args['name'] ) ); ?>" type="hidden"
3036
					       value="<?php echo esc_attr( $value ); ?>">
3037
					<?php
3038
					break;
3039
				default:
3040
					echo "No input type found!"; // @todo we need to add more input types.
3041
			}
3042
3043
			// after wrapper
3044
			?>
3045
			</p>
3046
			<?php
3047
3048
3049
		}
3050
3051
		public function get_widget_icon($icon = 'box-top', $title = ''){
3052
			if($icon=='box-top'){
3053
				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>';
3054
			}elseif($icon=='box-right'){
3055
				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>';
3056
			}elseif($icon=='box-bottom'){
3057
				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>';
3058
			}elseif($icon=='box-left'){
3059
				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>';
3060
			}
3061
		}
3062
3063
		/**
3064
		 * Get the widget input description html.
3065
		 *
3066
		 * @param $args
3067
		 *
3068
		 * @return string
3069
		 * @todo, need to make its own tooltip script
3070
		 */
3071
		public function widget_field_desc( $args ) {
3072
3073
			$description = '';
3074
			if ( isset( $args['desc'] ) && $args['desc'] ) {
3075
				if ( isset( $args['desc_tip'] ) && $args['desc_tip'] ) {
3076
					$description = $this->desc_tip( $args['desc'] );
3077
				} else {
3078
					$description = '<span class="description">' . wp_kses_post( $args['desc'] ) . '</span>';
3079
				}
3080
			}
3081
3082
			return $description;
3083
		}
3084
3085
		/**
3086
		 * Get the widget input title html.
3087
		 *
3088
		 * @param $args
3089
		 *
3090
		 * @return string
3091
		 */
3092
		public function widget_field_title( $args ) {
3093
3094
			$title = '';
3095
			if ( isset( $args['title'] ) && $args['title'] ) {
3096
				if ( isset( $args['icon'] ) && $args['icon'] ) {
3097
					$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

3097
					/** @scrutinizer ignore-call */ 
3098
     $title = self::get_widget_icon( $args['icon'], $args['title']  );
Loading history...
3098
				} else {
3099
					$title = esc_attr($args['title']);
3100
				}
3101
			}
3102
3103
			return $title;
3104
		}
3105
3106
		/**
3107
		 * Get the tool tip html.
3108
		 *
3109
		 * @param $tip
3110
		 * @param bool $allow_html
3111
		 *
3112
		 * @return string
3113
		 */
3114
		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...
3115
			if ( $allow_html ) {
3116
				$tip = $this->sanitize_tooltip( $tip );
3117
			} else {
3118
				$tip = esc_attr( $tip );
3119
			}
3120
3121
			return '<span class="gd-help-tip dashicons dashicons-editor-help" title="' . $tip . '"></span>';
3122
		}
3123
3124
		/**
3125
		 * Sanitize a string destined to be a tooltip.
3126
		 *
3127
		 * @param string $var
3128
		 *
3129
		 * @return string
3130
		 */
3131
		public function sanitize_tooltip( $var ) {
3132
			return htmlspecialchars( wp_kses( html_entity_decode( $var ), array(
3133
				'br'     => array(),
3134
				'em'     => array(),
3135
				'strong' => array(),
3136
				'small'  => array(),
3137
				'span'   => array(),
3138
				'ul'     => array(),
3139
				'li'     => array(),
3140
				'ol'     => array(),
3141
				'p'      => array(),
3142
			) ) );
3143
		}
3144
3145
		/**
3146
		 * Processing widget options on save
3147
		 *
3148
		 * @param array $new_instance The new options
3149
		 * @param array $old_instance The previous options
3150
		 *
3151
		 * @return array
3152
		 * @todo we should add some sanitation here.
3153
		 */
3154
		public function update( $new_instance, $old_instance ) {
3155
3156
			//save the widget
3157
			$instance = array_merge( (array) $old_instance, (array) $new_instance );
3158
3159
			// set widget instance
3160
			$this->instance = $instance;
3161
3162
			if ( empty( $this->arguments ) ) {
3163
				$this->get_arguments();
3164
			}
3165
3166
			// check for checkboxes
3167
			if ( ! empty( $this->arguments ) ) {
3168
				foreach ( $this->arguments as $argument ) {
3169
					if ( isset( $argument['type'] ) && $argument['type'] == 'checkbox' && ! isset( $new_instance[ $argument['name'] ] ) ) {
3170
						$instance[ $argument['name'] ] = '0';
3171
					}
3172
				}
3173
			}
3174
3175
			return $instance;
3176
		}
3177
3178
		/**
3179
		 * Checks if the current call is a ajax call to get the block content.
3180
		 *
3181
		 * This can be used in your widget to return different content as the block content.
3182
		 *
3183
		 * @since 1.0.3
3184
		 * @return bool
3185
		 */
3186
		public function is_block_content_call() {
3187
			$result = false;
3188
			if ( wp_doing_ajax() && isset( $_REQUEST['action'] ) && $_REQUEST['action'] == 'super_duper_output_shortcode' ) {
3189
				$result = true;
3190
			}
3191
3192
			return $result;
3193
		}
3194
3195
		/**
3196
		 * Get an instance hash that will be unique to the type and settings.
3197
		 *
3198
		 * @since 1.0.20
3199
		 * @return string
3200
		 */
3201
		public function get_instance_hash(){
3202
			$instance_string = $this->base_id.serialize($this->instance);
3203
			return hash('crc32b',$instance_string);
3204
		}
3205
3206
		/**
3207
		 * Generate and return inline styles from CSS rules that will match the unique class of the instance.
3208
		 *
3209
		 * @param array $rules
3210
		 *
3211
		 * @since 1.0.20
3212
		 * @return string
3213
		 */
3214
		public function get_instance_style($rules = array()){
3215
			$css = '';
3216
3217
			if(!empty($rules)){
3218
				$rules = array_unique($rules);
3219
				$instance_hash = $this->get_instance_hash();
3220
				$css .= "<style>";
3221
				foreach($rules as $rule){
3222
					$css .= ".sdel-$instance_hash $rule";
3223
				}
3224
				$css .= "</style>";
3225
			}
3226
3227
			return $css;
3228
		}
3229
3230
		/**
3231
		 * Encode shortcodes tags.
3232
		 *
3233
		 * @since 1.0.28
3234
		 *
3235
		 * @param string $content Content to search for shortcode tags.
3236
		 * @return string Content with shortcode tags removed.
3237
		 */
3238
		public function encode_shortcodes( $content ) {
3239
			// Avoids existing encoded tags.
3240
			$trans   = array(
3241
				'&#91;' => '&#091;',
3242
				'&#93;' => '&#093;',
3243
				'&amp;#91;' => '&#091;',
3244
				'&amp;#93;' => '&#093;',
3245
				'&lt;' => '&0lt;',
3246
				'&gt;' => '&0gt;',
3247
				'&amp;lt;' => '&0lt;',
3248
				'&amp;gt;' => '&0gt;',
3249
			);
3250
3251
			$content = strtr( $content, $trans );
3252
3253
			$trans   = array(
3254
				'[' => '&#91;',
3255
				']' => '&#93;',
3256
				'<' => '&lt;',
3257
				'>' => '&gt;',
3258
				'"' => '&quot;',
3259
				"'" => '&apos;',
3260
			);
3261
3262
			$content = strtr( $content, $trans );
3263
3264
			return $content;
3265
		}
3266
3267
		/**
3268
		 * Remove encoded shortcod tags.
3269
		 *
3270
		 * @since 1.0.28
3271
		 *
3272
		 * @param string $content Content to search for shortcode tags.
3273
		 * @return string Content with decoded shortcode tags.
3274
		 */
3275
		public function decode_shortcodes( $content ) {
3276
			$trans   = array(
3277
				'&#91;' => '[',
3278
				'&#93;' => ']',
3279
				'&amp;#91;' => '[',
3280
				'&amp;#93;' => ']',
3281
				'&lt;' => '<',
3282
				'&gt;' => '>',
3283
				'&amp;lt;' => '<',
3284
				'&amp;gt;' => '>',
3285
				'&quot;' => '"',
3286
				'&apos;' => "'",
3287
			);
3288
3289
			$content = strtr( $content, $trans );
3290
3291
			$trans   = array(
3292
				'&#091;' => '&#91;',
3293
				'&#093;' => '&#93;',
3294
				'&amp;#091;' => '&#91;',
3295
				'&amp;#093;' => '&#93;',
3296
				'&0lt;' => '&lt;',
3297
				'&0gt;' => '&gt;',
3298
				'&amp;0lt;' => '&lt;',
3299
				'&amp;0gt;' => '&gt;',
3300
			);
3301
3302
			$content = strtr( $content, $trans );
3303
3304
			return $content;
3305
		}
3306
	}
3307
}