Passed
Push — master ( 9f729e...3066b5 )
by Brian
12:17
created

WP_Super_Duper::shortcode_insert_button_script()   C

Complexity

Conditions 9
Paths 32

Size

Total Lines 479
Code Lines 236

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 236
nc 32
nop 2
dl 0
loc 479
rs 6.4444
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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.29";
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
				/* Load script on Divi theme builder page */
96
				if ( function_exists( 'et_builder_is_tb_admin_screen' ) && et_builder_is_tb_admin_screen() ) {
97
					add_thickbox();
98
					add_action( 'admin_footer', array( $this, 'shortcode_insert_button_script' ) );
99
				}
100
101
				if ( $this->is_preview() ) {
102
					add_action( 'wp_footer', array( $this, 'shortcode_insert_button_script' ) );
103
					// this makes the insert button work for elementor
104
					add_action( 'elementor/editor/after_enqueue_scripts', array(
105
						$this,
106
						'shortcode_insert_button_script'
107
					) ); // for elementor
108
				}
109
				// this makes the insert button work for cornerstone
110
				add_action( 'wp_print_footer_scripts', array( __CLASS__, 'maybe_cornerstone_builder' ) );
111
112
				add_action( 'wp_ajax_super_duper_get_widget_settings', array( __CLASS__, 'get_widget_settings' ) );
113
				add_action( 'wp_ajax_super_duper_get_picker', array( __CLASS__, 'get_picker' ) );
114
115
				// add generator text to admin head
116
				add_action( 'admin_head', array( $this, 'generator' ) );
117
			}
118
119
			do_action( 'wp_super_duper_widget_init', $options, $this );
120
		}
121
122
		/**
123
		 * Add our widget CSS to elementor editor.
124
		 */
125
		public function elementor_editor_styles() {
126
			wp_add_inline_style( 'elementor-editor', $this->widget_css( false ) );
127
		}
128
129
		public function register_fusion_element() {
130
131
			$options = $this->options;
132
133
			if ( $this->base_id ) {
134
135
				$params = $this->get_fusion_params();
136
137
				$args = array(
138
					'name'            => $options['name'],
139
					'shortcode'       => $this->base_id,
140
					'icon'            => $options['block-icon'] ? $options['block-icon'] : 'far fa-square',
141
					'allow_generator' => true,
142
				);
143
144
				if ( ! empty( $params ) ) {
145
					$args['params'] = $params;
146
				}
147
148
				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

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

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

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

2136
		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...
2137
2138
			// check for row
2139
			if(!empty($args['row'])){
2140
2141
				if(!empty($args['row']['open'])){
2142
2143
				// element require
2144
				$element_require = ! empty( $args['element_require'] ) ? $this->block_props_replace( $args['element_require'], true ) . " && " : "";
2145
				echo $element_require;
2146
2147
					if(false){?><script><?php }?>
2148
						el('div', {
2149
								className: 'bsui components-base-control',
2150
							},
2151
							<?php if(!empty($args['row']['title'])){ ?>
2152
							el('label', {
2153
									className: 'components-base-control__label',
2154
								},
2155
								'<?php echo addslashes( $args['row']['title'] ); ?>'
2156
							),
2157
							<?php }?>
2158
							<?php if(!empty($args['row']['desc'])){ ?>
2159
							el('p', {
2160
									className: 'components-base-control__help mb-0',
2161
								},
2162
								'<?php echo addslashes( $args['row']['desc'] ); ?>'
2163
							),
2164
							<?php }?>
2165
							el(
2166
								'div',
2167
								{
2168
									className: 'row mb-n2 <?php if(!empty($args['row']['class'])){ echo esc_attr($args['row']['class']);} ?>',
2169
								},
2170
								el(
2171
									'div',
2172
									{
2173
										className: 'col pr-2',
2174
									},
2175
2176
					<?php
2177
					if(false){?></script><?php }
2178
				}elseif(!empty($args['row']['close'])){
2179
					if(false){?><script><?php }?>
2180
						el(
2181
							'div',
2182
							{
2183
								className: 'col pl-0',
2184
							},
2185
					<?php
2186
					if(false){?></script><?php }
2187
				}else{
2188
					if(false){?><script><?php }?>
2189
						el(
2190
							'div',
2191
							{
2192
								className: 'col pl-0 pr-2',
2193
							},
2194
					<?php
2195
					if(false){?></script><?php }
2196
				}
2197
2198
			}
2199
2200
		}
2201
2202
		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

2202
		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...
2203
2204
			if(!empty($args['row'])){
2205
				// maybe close
2206
				if(!empty($args['row']['close'])){
2207
					echo "))";
2208
				}
2209
2210
				echo "),";
2211
			}
2212
		}
2213
2214
		public function build_block_arguments( $key, $args ) {
2215
			$custom_attributes = ! empty( $args['custom_attributes'] ) ? $this->array_to_attributes( $args['custom_attributes'] ) : '';
2216
			$options           = '';
2217
			$extra             = '';
2218
			$require           = '';
0 ignored issues
show
Unused Code introduced by
The assignment to $require is dead and can be removed.
Loading history...
2219
2220
			// `content` is a protected and special argument
2221
			if ( $key == 'content' ) {
2222
				return;
2223
			}
2224
2225
2226
			// icon
2227
			$icon = '';
2228
			if( !empty( $args['icon'] ) ){
2229
				$icon .= "el('div', {";
2230
									$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

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

2844
		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...
2845
			if(!empty($args['row'])){
2846
				// maybe open
2847
				if(!empty($args['row']['open'])){
2848
					?>
2849
					<div class='bsui sd-argument ' data-argument='<?php echo esc_attr( $args['row']['key'] ); ?>' data-element_require='<?php if ( !empty($args['row']['element_require'])) {
2850
						echo $this->convert_element_require( $args['row']['element_require'] );
2851
					} ?>'>
2852
					<?php if(!empty($args['row']['title'])){ ?>
2853
					<label class="mb-0 "><?php echo esc_attr( $args['row']['title'] ); ?><?php echo $this->widget_field_desc( $args['row'] ); ?></label>
2854
					<?php }?>
2855
					<div class='row <?php if(!empty($args['row']['class'])){ echo esc_attr($args['row']['class']);} ?>'>
2856
					<div class='col pr-2'>
2857
					<?php
2858
				}elseif(!empty($args['row']['close'])){
2859
					echo "<div class='col pl-0'>";
2860
				}else{
2861
					echo "<div class='col pl-0 pr-2'>";
2862
				}
2863
			}
2864
		}
2865
2866
		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

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

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