Passed
Branch master (50908e)
by Stiofan
07:01
created

WP_Super_Duper   F

Complexity

Total Complexity 332

Size/Duplication

Total Lines 2647
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 1315
c 2
b 0
f 0
dl 0
loc 2647
rs 0.8
wmc 332

52 Methods

Rating   Name   Duplication   Size   Complexity  
C render_shortcode() 0 32 12
D block_element() 0 80 22
A register_block() 0 5 2
A is_elementor_widget_output() 0 7 4
B update() 0 22 7
A block_props_replace() 0 9 2
A desc_tip() 0 8 2
B add_name_from_key() 0 12 7
A register_fusion_element() 0 20 4
A get_arguments() 0 9 2
B is_preview() 0 17 7
A block_show_advanced() 0 19 6
B widget_js() 0 167 1
A output() 0 1 1
A group_arguments() 0 22 5
A widget_css() 0 47 1
A is_fusion_preview() 0 7 3
A register_shortcode() 0 3 1
B argument_values() 0 26 9
A maybe_cornerstone_builder() 0 3 2
A is_cornerstone_preview() 0 7 3
A get_url() 0 19 4
A is_siteorigin_preview() 0 7 2
A is_beaver_preview() 0 7 2
B is_elementor_preview() 0 7 7
B siteorigin_js() 0 90 1
C shortcode_output() 0 52 15
A widget_advanced_toggle() 0 12 2
F widget_inputs() 0 132 33
A widget_field_desc() 0 12 5
F build_block_arguments() 0 71 18
A generator() 0 2 1
B shortcode_insert_button() 0 30 8
A shortcode_button() 0 22 2
A set_arguments() 0 2 1
A string_to_bool() 0 11 4
B widget() 0 39 8
B get_picker() 0 72 11
C get_widget_settings() 0 28 9
A array_to_attributes() 0 16 5
A preview_placeholder_text() 0 2 1
F block() 0 325 36
A is_divi_preview() 0 7 6
A output_title() 0 9 2
B __construct() 0 69 7
A convert_element_require() 0 10 1
B shortcode_insert_button_script() 0 463 7
A sanitize_tooltip() 0 11 1
A get_block_icon() 0 21 5
A is_block_content_call() 0 7 4
C get_fusion_params() 0 63 12
B form() 0 46 9

How to fix   Complexity   

Complex Class

Complex classes like WP_Super_Duper often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use WP_Super_Duper, and based on these observations, apply Extract Interface, too.

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.3 is_block_content_call() method added.
16
	 * @since 1.0.3 Placeholder text will be shown for widget that return no block content.
17
	 * @since 1.0.4 is_elementor_widget_output() method added.
18
	 * @since 1.0.4 is_elementor_preview() method added.
19
	 * @since 1.0.5 Block checkbox options are set as true by default even when set as false - FIXED
20
	 * @since 1.0.6 Some refactoring for page builders - CHANGED
21
	 * @since 1.0.7 Some refactoring for page builders - CHANGED
22
	 * @since 1.0.8 Some refactoring for page builders ( cornerstone builder now supported ) - CHANGED
23
	 * @since 1.0.9 Numbers saving as strings and not numbers which can cause block render issues on refresh - FIXED
24
	 * @since 1.0.10 Some refactoring for page builders ( Avia builder for Enfold theme now supported ) - CHANGED
25
	 * @since 1.0.11 Some refactoring for page builders - CHANGED
26
	 * @since 1.0.12 A checkbox default value can make a argument true even when unchecked - FIXED
27
	 * @since 1.0.13 Block values can break JS if contains a comma - FIXED
28
	 * @since 1.0.14 Use of additional css class in block editor breaks the block html - FIXED
29
	 * @since 1.0.15 Fix conflicts with GeneratePress sections - FIXED
30
	 * @since 1.0.15 `group` setting option added to be able to group settings - ADDED
31
	 * @since 1.0.15 `block-supports` options array now supported - ADDED
32
	 * @since 1.0.15 `block-icon` now supports Font Awesome class - ADDED
33
	 * @since 1.0.15 Fusion builder (Avada) elements automatically created - ADDED
34
	 * @ver 1.0.15
35
	 */
36
	class WP_Super_Duper extends WP_Widget {
37
38
		public $version = "1.0.15";
39
		public $font_awesome_icon_version = "5.11.2";
40
		public $block_code;
41
		public $options;
42
		public $base_id;
43
		public $arguments = array();
44
		public $instance = array();
45
		private $class_name;
46
47
		/**
48
		 * The relative url to the current folder.
49
		 *
50
		 * @var string
51
		 */
52
		public $url = '';
53
54
		/**
55
		 * Take the array options and use them to build.
56
		 */
57
		public function __construct( $options ) {
58
			global $sd_widgets;
59
60
			$sd_widgets[ $options['base_id'] ] = array(
61
				'name'       => $options['name'],
62
				'class_name' => $options['class_name']
63
			);
64
			$this->base_id                     = $options['base_id'];
65
			// lets filter the options before we do anything
66
			$options       = apply_filters( "wp_super_duper_options", $options );
67
			$options       = apply_filters( "wp_super_duper_options_{$this->base_id}", $options );
68
			$options       = $this->add_name_from_key( $options );
69
			$this->options = $options;
70
71
			$this->base_id   = $options['base_id'];
72
			$this->arguments = isset( $options['arguments'] ) ? $options['arguments'] : array();
73
74
			// init parent
75
			parent::__construct( $options['base_id'], $options['name'], $options['widget_ops'] );
76
77
			if ( isset( $options['class_name'] ) ) {
78
				// register widget
79
				$this->class_name = $options['class_name'];
80
81
				// register shortcode
82
				$this->register_shortcode();
83
84
				// Fusion Builder (avada) support
85
				if( function_exists('fusion_builder_map') ){ $this->register_fusion_element(); }
86
87
				// register block
88
				add_action( 'admin_enqueue_scripts', array( $this, 'register_block' ) );
89
			}
90
91
			// add the CSS and JS we need ONCE
92
			global $sd_widget_scripts;
93
94
			if ( ! $sd_widget_scripts ) {
95
				wp_add_inline_script( 'admin-widgets', $this->widget_js() );
96
				wp_add_inline_script( 'customize-controls', $this->widget_js() );
97
				wp_add_inline_style( 'widgets', $this->widget_css() );
98
99
				$sd_widget_scripts = true;
100
101
				// add shortcode insert button once
102
				add_action( 'media_buttons', array( $this, 'shortcode_insert_button' ) );
103
				// generatepress theme sections compatibility
104
				if ( function_exists( 'generate_sections_sections_metabox' ) ) {
105
					add_action( 'generate_sections_metabox', array( $this, 'shortcode_insert_button_script' ) );
106
				}
107
				if ( $this->is_preview() ) {
108
					add_action( 'wp_footer', array( $this, 'shortcode_insert_button_script' ) );
109
					// this makes the insert button work for elementor
110
					add_action( 'elementor/editor/after_enqueue_scripts', array(
111
						$this,
112
						'shortcode_insert_button_script'
113
					) ); // for elementor
114
				}
115
				// this makes the insert button work for cornerstone
116
				add_action('wp_print_footer_scripts',array( __CLASS__, 'maybe_cornerstone_builder' ));
117
118
				add_action( 'wp_ajax_super_duper_get_widget_settings', array( __CLASS__, 'get_widget_settings' ) );
119
				add_action( 'wp_ajax_super_duper_get_picker', array( __CLASS__, 'get_picker' ) );
120
121
				// add generator text to admin head
122
				add_action( 'admin_head', array( $this, 'generator' ) );
123
			}
124
125
			do_action( 'wp_super_duper_widget_init', $options, $this );
126
		}
127
128
		public function register_fusion_element(){
129
130
			$options = $this->options;
131
132
			if($this->base_id){
133
134
				$params = $this->get_fusion_params();
135
136
				$args = array(
137
					'name'            => $options['name'],
138
					'shortcode'       => $this->base_id,
139
					'icon'            => $options['block-icon'] ? $options['block-icon'] : 'far fa-square',
140
					'allow_generator' => true,
141
				);
142
143
				if(!empty($params)){
144
					$args['params'] = $params;
145
				}
146
147
				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

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

2 paths for user data to reach this point

  1. Path: Read from $_POST, and Data is passed through sanitize_title_with_dashes(), and sanitize_title_with_dashes($_POST['shortcode']) is assigned to $shortcode_name in vendor/ayecode/wp-super-duper/wp-super-duper.php on line 1280
  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 1280
  2. '[' . $shortcode_name . ' ' . $attributes . ']' is assigned to $shortcode
    in vendor/ayecode/wp-super-duper/wp-super-duper.php on line 1289
  3. Data is passed through do_shortcode()
    in vendor/ayecode/wp-super-duper/wp-super-duper.php on line 1291
  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 1281
  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 1281
  2. $attributes_array is assigned to $key
    in vendor/ayecode/wp-super-duper/wp-super-duper.php on line 1284
  3. Data is passed through sanitize_title_with_dashes(), and ' ' . sanitize_title_with_dashes($key) . '='' . wp_slash($value) . '' ' is assigned to $attributes
    in vendor/ayecode/wp-super-duper/wp-super-duper.php on line 1285
  4. '[' . $shortcode_name . ' ' . $attributes . ']' is assigned to $shortcode
    in vendor/ayecode/wp-super-duper/wp-super-duper.php on line 1289
  5. Data is passed through do_shortcode()
    in vendor/ayecode/wp-super-duper/wp-super-duper.php on line 1291

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...
1292
1293
			}
1294
			wp_die();
1295
		}
1296
1297
		/**
1298
		 * Output the shortcode.
1299
		 *
1300
		 * @param array $args
1301
		 * @param string $content
1302
		 *
1303
		 * @return string
1304
		 */
1305
		public function shortcode_output( $args = array(), $content = '' ) {
1306
			$args = self::argument_values( $args );
0 ignored issues
show
Bug Best Practice introduced by
The method WP_Super_Duper::argument_values() 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

1306
			/** @scrutinizer ignore-call */ 
1307
   $args = self::argument_values( $args );
Loading history...
1307
1308
			// add extra argument so we know its a output to gutenberg
1309
			//$args
1310
			$args = $this->string_to_bool( $args );
1311
1312
1313
			$calss = isset( $this->options['widget_ops']['classname'] ) ? esc_attr( $this->options['widget_ops']['classname'] ) : '';
1314
1315
			$calss = apply_filters( 'wp_super_duper_div_classname', $calss, $args, $this );
1316
			$calss = apply_filters( 'wp_super_duper_div_classname_' . $this->base_id, $calss, $args, $this );
1317
1318
			$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...
1319
			$attrs = apply_filters( 'wp_super_duper_div_attrs_' . $this->base_id, '', $args, $this );
1320
1321
			$shortcode_args = array();
1322
			$output         = '';
1323
			$no_wrap        = isset( $this->options['no_wrap'] ) && $this->options['no_wrap'] ? true : false;
1324
			$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...
1325
			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...
1326
				// wrap the shortcode in a dive with the same class as the widget
1327
				$output .= '<div class="' . $calss . '" ' . $attrs . '>';
1328
				if ( ! empty( $args['title'] ) ) {
1329
					// if its a shortcode and there is a title try to grab the title wrappers
1330
					$shortcode_args = array( 'before_title' => '', 'after_title' => '' );
1331
					if ( empty( $instance ) ) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $instance seems to never exist and therefore empty should always be true.
Loading history...
1332
						global $wp_registered_sidebars;
1333
						if ( ! empty( $wp_registered_sidebars ) ) {
1334
							foreach ( $wp_registered_sidebars as $sidebar ) {
1335
								if ( ! empty( $sidebar['before_title'] ) ) {
1336
									$shortcode_args['before_title'] = $sidebar['before_title'];
1337
									$shortcode_args['after_title']  = $sidebar['after_title'];
1338
									break;
1339
								}
1340
							}
1341
						}
1342
					}
1343
					$output .= $this->output_title( $shortcode_args, $args );
1344
				}
1345
				$output .= $main_content;
1346
				$output .= '</div>';
1347
			} 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...
1348
				$output .= $main_content;
1349
			}
1350
1351
			// if preview show a placeholder if empty
1352
			if ( $this->is_preview() && $output == '' ) {
1353
				$output = $this->preview_placeholder_text( "[{" . $this->base_id . "}]" );
1354
			}
1355
1356
			return apply_filters( 'wp_super_duper_widget_output', $output, $args, $shortcode_args, $this );
1357
		}
1358
1359
		/**
1360
		 * Placeholder text to show if output is empty and we are on a preview/builder page.
1361
		 *
1362
		 * @param string $name
1363
		 *
1364
		 * @return string
1365
		 */
1366
		public function preview_placeholder_text( $name = '' ) {
1367
			return "<div style='background:#0185ba33;padding: 10px;border: 4px #ccc dashed;'>" . sprintf( __( 'Placeholder for: %s' ), $name ) . "</div>";
1368
		}
1369
1370
		/**
1371
		 * Sometimes booleans values can be turned to strings, so we fix that.
1372
		 *
1373
		 * @param $options
1374
		 *
1375
		 * @return mixed
1376
		 */
1377
		public function string_to_bool( $options ) {
1378
			// convert bool strings to booleans
1379
			foreach ( $options as $key => $val ) {
1380
				if ( $val == 'false' ) {
1381
					$options[ $key ] = false;
1382
				} elseif ( $val == 'true' ) {
1383
					$options[ $key ] = true;
1384
				}
1385
			}
1386
1387
			return $options;
1388
		}
1389
1390
		/**
1391
		 * Get the argument values that are also filterable.
1392
		 *
1393
		 * @param $instance
1394
		 *
1395
		 * @since 1.0.12 Don't set checkbox default value if the value is empty.
1396
		 *
1397
		 * @return array
1398
		 */
1399
		public function argument_values( $instance ) {
1400
			$argument_values = array();
1401
1402
			// set widget instance
1403
			$this->instance = $instance;
1404
1405
			if ( empty( $this->arguments ) ) {
1406
				$this->arguments = $this->get_arguments();
1407
			}
1408
1409
			if ( ! empty( $this->arguments ) ) {
1410
				foreach ( $this->arguments as $key => $args ) {
1411
					// set the input name from the key
1412
					$args['name'] = $key;
1413
					//
1414
					$argument_values[ $key ] = isset( $instance[ $key ] ) ? $instance[ $key ] : '';
1415
					if($args['type']=='checkbox' && $argument_values[ $key ] == ''){
1416
						// don't set default for an empty checkbox
1417
					}
1418
					elseif ( $argument_values[ $key ] == '' && isset( $args['default'] ) ) {
1419
						$argument_values[ $key ] = $args['default'];
1420
					}
1421
				}
1422
			}
1423
1424
			return $argument_values;
1425
		}
1426
1427
		/**
1428
		 * Set arguments in super duper.
1429
		 *
1430
		 * @since 1.0.0
1431
		 *
1432
		 * @return array Set arguments.
1433
		 */
1434
		public function set_arguments() {
1435
			return $this->arguments;
1436
		}
1437
1438
		/**
1439
		 * Get arguments in super duper.
1440
		 *
1441
		 * @since 1.0.0
1442
		 *
1443
		 * @return array Get arguments.
1444
		 */
1445
		public function get_arguments() {
1446
			if ( empty( $this->arguments ) ) {
1447
				$this->arguments = $this->set_arguments();
1448
			}
1449
1450
			$this->arguments = apply_filters( 'wp_super_duper_arguments', $this->arguments, $this->options, $this->instance );
1451
			$this->arguments = $this->add_name_from_key( $this->arguments, true );
1452
1453
			return $this->arguments;
1454
		}
1455
1456
		/**
1457
		 * This is the main output class for all 3 items, widget, shortcode and block, it is extended in the calling class.
1458
		 *
1459
		 * @param array $args
1460
		 * @param array $widget_args
1461
		 * @param string $content
1462
		 */
1463
		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

1463
		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...
1464
1465
		}
1466
1467
		/**
1468
		 * Add the dynamic block code inline when the wp-block in enqueued.
1469
		 */
1470
		public function register_block() {
1471
			wp_add_inline_script( 'wp-blocks', $this->block() );
1472
			if ( class_exists( 'SiteOrigin_Panels' ) ) {
1473
1474
				wp_add_inline_script( 'wp-blocks', $this->siteorigin_js() );
1475
1476
			}
1477
		}
1478
1479
		/**
1480
		 * Check if we need to show advanced options.
1481
		 *
1482
		 * @return bool
1483
		 */
1484
		public function block_show_advanced() {
1485
1486
			$show      = false;
1487
			$arguments = $this->arguments;
1488
1489
			if ( empty( $arguments ) ) {
1490
				$arguments = $this->get_arguments();
1491
			}
1492
1493
			if ( ! empty( $arguments ) ) {
1494
				foreach ( $arguments as $argument ) {
1495
					if ( isset( $argument['advanced'] ) && $argument['advanced'] ) {
1496
						$show = true;
1497
						break; // no need to continue if we know we have it
1498
					}
1499
				}
1500
			}
1501
1502
			return $show;
1503
		}
1504
1505
		/**
1506
		 * Get the url path to the current folder.
1507
		 *
1508
		 * @return string
1509
		 */
1510
		public function get_url() {
1511
1512
			$url = $this->url;
1513
1514
			if(!$url){
1515
				// check if we are inside a plugin
1516
				$file_dir = str_replace("/includes","", dirname( __FILE__ ));
1517
1518
				$dir_parts = explode("/wp-content/",$file_dir);
1519
				$url_parts = explode("/wp-content/",plugins_url());
1520
1521
				if(!empty($url_parts[0]) && !empty($dir_parts[1])){
1522
					$url = trailingslashit( $url_parts[0]."/wp-content/".$dir_parts[1] );
1523
					$this->url = $url;
1524
				}
1525
			}
1526
1527
1528
			return $url;
1529
		}
1530
1531
		/**
1532
		 * Generate the block icon.
1533
		 *
1534
		 * Enables the use of Font Awesome icons.
1535
		 *
1536
		 * @note xlink:href is actually deprecated but href is not supported by all so we use both.
1537
		 * @param $icon
1538
		 * @since 1.1.0
1539
		 * @return string
1540
		 */
1541
		public function get_block_icon($icon){
1542
1543
			// check if we have a Font Awesome icon
1544
			$fa_type = '';
1545
			if(substr( $icon, 0, 7 ) === "fas fa-"){
1546
				$fa_type = 'solid';
1547
			}elseif(substr( $icon, 0, 7 ) === "far fa-"){
1548
				$fa_type = 'regular';
1549
			}elseif(substr( $icon, 0, 7 ) === "fab fa-"){
1550
				$fa_type = 'brands';
1551
			}else{
1552
				$icon = "'".$icon."'";
1553
			}
1554
1555
			// set the icon if we found one
1556
			if($fa_type){
1557
				$fa_icon = str_replace(array("fas fa-","far fa-","fab fa-"),"",$icon);
1558
				$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."'}))";
1559
			}
1560
1561
			return $icon;
1562
		}
1563
1564
		public function group_arguments($arguments){
1565
//			echo '###';print_r($arguments);
1566
			if(!empty($arguments)){
1567
				$temp_arguments = array();
1568
				$general = __("General");
1569
				$add_sections = false;
1570
				foreach($arguments as $key => $args){
1571
					if(isset($args['group'])){
1572
						$temp_arguments[$args['group']][$key] = $args;
1573
						$add_sections = true;
1574
					}else{
1575
						$temp_arguments[$general][$key] = $args;
1576
					}
1577
				}
1578
1579
				// only add sections if more than one
1580
				if($add_sections){
1581
					$arguments = $temp_arguments;
1582
				}
1583
			}
1584
//			echo '###';print_r($arguments);
1585
			return $arguments;
1586
		}
1587
1588
1589
		/**
1590
		 * Output the JS for building the dynamic Guntenberg block.
1591
		 *
1592
		 * @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.
1593
		 * @since 1.0.9 Save numbers as numbers and not strings.
1594
		 * @since 1.1.0 Font Awesome classes can be used for icons.
1595
		 * @return mixed
1596
		 */
1597
		public function block() {
1598
			ob_start();
1599
			?>
1600
			<script>
1601
				/**
1602
				 * BLOCK: Basic
1603
				 *
1604
				 * Registering a basic block with Gutenberg.
1605
				 * Simple block, renders and saves the same content without any interactivity.
1606
				 *
1607
				 * Styles:
1608
				 *        editor.css — Editor styles for the block.
1609
				 *        style.css  — Editor & Front end styles for the block.
1610
				 */
1611
				(function () {
1612
					var __ = wp.i18n.__; // The __() for internationalization.
1613
					var el = wp.element.createElement; // The wp.element.createElement() function to create elements.
1614
					var editable = wp.blocks.Editable;
1615
					var blocks = wp.blocks;
1616
					var registerBlockType = wp.blocks.registerBlockType; // The registerBlockType() to register blocks.
1617
					var is_fetching = false;
1618
					var prev_attributes = [];
1619
1620
					/**
1621
					 * Register Basic Block.
1622
					 *
1623
					 * Registers a new block provided a unique name and an object defining its
1624
					 * behavior. Once registered, the block is made available as an option to any
1625
					 * editor interface where blocks are implemented.
1626
					 *
1627
					 * @param  {string}   name     Block name.
1628
					 * @param  {Object}   settings Block settings.
1629
					 * @return {?WPBlock}          The block, if it has been successfully
1630
					 *                             registered; otherwise `undefined`.
1631
					 */
1632
					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.
1633
						title: '<?php echo $this->options['name'];?>', // Block title.
1634
						description: '<?php echo esc_attr( $this->options['widget_ops']['description'] )?>', // Block title.
1635
						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/.
1636
						supports: {
1637
							<?php
1638
							if(isset($this->options['block-supports'])){
1639
								echo $this->array_to_attributes( $this->options['block-supports'] );
1640
							}
1641
							?>
1642
						},
1643
						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.
1644
						<?php if ( isset( $this->options['block-keywords'] ) ) {
1645
						echo "keywords : " . $this->options['block-keywords'] . ",";
1646
					}?>
1647
1648
						<?php
1649
1650
						$show_advanced = $this->block_show_advanced();
1651
1652
						$show_alignment = false;
1653
						// align feature
1654
						/*echo "supports: {";
1655
						echo "	align: true,";
1656
						echo "  html: false";
1657
						echo "},";*/
1658
1659
						if ( ! empty( $this->arguments ) ) {
1660
							echo "attributes : {";
1661
1662
							if ( $show_advanced ) {
1663
								echo "show_advanced: {";
1664
								echo "	type: 'boolean',";
1665
								echo "  default: false,";
1666
								echo "},";
1667
							}
1668
1669
							// block wrap element
1670
							if ( isset( $this->options['block-wrap'] ) ) { //@todo we should validate this?
1671
								echo "block_wrap: {";
1672
								echo "	type: 'string',";
1673
								echo "  default: '" . esc_attr( $this->options['block-wrap'] ) . "',";
1674
								echo "},";
1675
							}
1676
1677
							foreach ( $this->arguments as $key => $args ) {
1678
1679
								// set if we should show alignment
1680
								if ( $key == 'alignment' ) {
1681
									$show_alignment = true;
1682
								}
1683
1684
								$extra = '';
0 ignored issues
show
Unused Code introduced by
The assignment to $extra is dead and can be removed.
Loading history...
1685
1686
								if ( $args['type'] == 'checkbox' ) {
1687
									$type    = 'boolean';
1688
									$default = isset( $args['default'] ) && $args['default'] ? 'true' : 'false';
1689
								} elseif ( $args['type'] == 'number' ) {
1690
									$type    = 'number';
1691
									$default = isset( $args['default'] ) ? "'" . $args['default'] . "'" : "''";
1692
								} elseif ( $args['type'] == 'select' && ! empty( $args['multiple'] ) ) {
1693
									$type = 'array';
1694
									if ( is_array( $args['default'] ) ) {
1695
										$default = isset( $args['default'] ) ? "['" . implode( "','", $args['default'] ) . "']" : "[]";
1696
									} else {
1697
										$default = isset( $args['default'] ) ? "'" . $args['default'] . "'" : "''";
1698
									}
1699
								} elseif ( $args['type'] == 'multiselect' ) {
1700
									$type    = 'array';
1701
									$default = isset( $args['default'] ) ? "'" . $args['default'] . "'" : "''";
1702
								} else {
1703
									$type    = 'string';
1704
									$default = isset( $args['default'] ) ? "'" . $args['default'] . "'" : "''";
1705
								}
1706
								echo $key . " : {";
1707
								echo "type : '$type',";
1708
								echo "default : $default,";
1709
								echo "},";
1710
							}
1711
1712
							echo "content : {type : 'string',default: 'Please select the attributes in the block settings'},";
1713
							echo "className: { type: 'string', default: '' },";
1714
1715
							echo "},";
1716
1717
						}
1718
1719
						?>
1720
1721
						// The "edit" property must be a valid function.
1722
						edit: function (props) {
1723
1724
							var content = props.attributes.content;
1725
1726
							function onChangeContent() {
1727
1728
								if (!is_fetching && prev_attributes[props.id] != props.attributes) {
1729
1730
									//console.log(props);
1731
1732
									is_fetching = true;
1733
									var data = {
1734
										'action': 'super_duper_output_shortcode',
1735
										'shortcode': '<?php echo $this->options['base_id'];?>',
1736
										'attributes': props.attributes,
1737
										'post_id': <?php global $post; if ( isset( $post->ID ) ) {
1738
										echo $post->ID;
1739
									}?>,
1740
										'_ajax_nonce': '<?php echo wp_create_nonce( 'super_duper_output_shortcode' );?>'
1741
									};
1742
1743
									jQuery.post(ajaxurl, data, function (response) {
1744
										return response;
1745
									}).then(function (env) {
1746
1747
										// if the content is empty then we place some placeholder text
1748
										if (env == '') {
1749
											env = "<div style='background:#0185ba33;padding: 10px;border: 4px #ccc dashed;'>" + "<?php _e( 'Placeholder for: ' );?>" + props.name + "</div>";
1750
										}
1751
1752
										props.setAttributes({content: env});
1753
										is_fetching = false;
1754
										prev_attributes[props.id] = props.attributes;
1755
									});
1756
1757
1758
								}
1759
1760
								return props.attributes.content;
1761
1762
							}
1763
1764
							return [
1765
1766
								el(wp.editor.BlockControls, {key: 'controls'},
1767
1768
									<?php if($show_alignment){?>
1769
									el(
1770
										wp.editor.AlignmentToolbar,
1771
										{
1772
											value: props.attributes.alignment,
1773
											onChange: function (alignment) {
1774
												props.setAttributes({alignment: alignment})
1775
											}
1776
										}
1777
									)
1778
									<?php }?>
1779
1780
								),
1781
1782
								el(wp.editor.InspectorControls, {key: 'inspector'},
1783
1784
									<?php
1785
1786
									if(! empty( $this->arguments )){
1787
1788
										if ( $show_advanced ) {
1789
										?>
1790
										el(
1791
											wp.components.ToggleControl,
1792
											{
1793
												label: 'Show Advanced Settings?',
1794
												checked: props.attributes.show_advanced,
1795
												onChange: function (show_advanced) {
1796
													props.setAttributes({show_advanced: !props.attributes.show_advanced})
1797
												}
1798
											}
1799
										),
1800
										<?php
1801
1802
										}
1803
1804
										$arguments = $this->group_arguments($this->arguments);
1805
1806
										// Do we have sections?
1807
										$has_sections = $arguments == $this->arguments ? false : true;
1808
1809
										
1810
									if($has_sections){
1811
										$panel_count = 0;
1812
										foreach($arguments as $key => $args){
1813
											?>
1814
											el(wp.components.PanelBody, {
1815
													title: '<?php esc_attr_e($key); ?>',
1816
													initialOpen: <?php if($panel_count){echo "false";}else{echo "true";}?>
1817
												},
1818
											<?php
1819
1820
											foreach($args as $k => $a){
1821
												$this->build_block_arguments($k, $a);
1822
											}
1823
											?>
1824
											),
1825
											<?php
1826
									$panel_count++;
1827
1828
										}
1829
									}else{
1830
										foreach($this->arguments as $key => $args){
1831
											$this->build_block_arguments($key, $args);
1832
										}
1833
									}
1834
1835
1836
1837
									}
1838
									?>
1839
1840
								),
1841
1842
								<?php
1843
								// If the user sets block-output array then build it
1844
								if ( ! empty( $this->options['block-output'] ) ) {
1845
								$this->block_element( $this->options['block-output'] );
1846
							}else{
1847
								// if no block-output is set then we try and get the shortcode html output via ajax.
1848
								?>
1849
								el('div', {
1850
									dangerouslySetInnerHTML: {__html: onChangeContent()},
1851
									className: props.className,
1852
									style: {'min-height': '30px'}
1853
								})
1854
								<?php
1855
								}
1856
								?>
1857
							]; // end return
1858
						},
1859
1860
						// The "save" property must be specified and must be a valid function.
1861
						save: function (props) {
1862
1863
							//console.log(props);
1864
1865
1866
							var attr = props.attributes;
1867
							var align = '';
1868
1869
							// build the shortcode.
1870
							var content = "[<?php echo $this->options['base_id'];?>";
1871
							<?php
1872
1873
							if(! empty( $this->arguments )){
1874
							foreach($this->arguments as $key => $args){
1875
							?>
1876
							if (attr.hasOwnProperty("<?php echo esc_attr( $key );?>")) {
1877
								content += " <?php echo esc_attr( $key );?>='" + attr.<?php echo esc_attr( $key );?>+ "' ";
1878
							}
1879
							<?php
1880
							}
1881
							}
1882
1883
							?>
1884
							content += "]";
1885
1886
1887
							// @todo should we add inline style here or just css classes?
1888
							if (attr.alignment) {
1889
								if (attr.alignment == 'left') {
1890
									align = 'alignleft';
1891
								}
1892
								if (attr.alignment == 'center') {
1893
									align = 'aligncenter';
1894
								}
1895
								if (attr.alignment == 'right') {
1896
									align = 'alignright';
1897
								}
1898
							}
1899
1900
							//console.log(content);
1901
							var block_wrap = 'div';
1902
							if (attr.hasOwnProperty("block_wrap")) {
1903
								block_wrap = attr.block_wrap;
1904
							}
1905
							return el(block_wrap, {dangerouslySetInnerHTML: {__html: content}, className: align});
1906
1907
						}
1908
					});
1909
				})();
1910
			</script>
1911
			<?php
1912
			$output = ob_get_clean();
1913
1914
			/*
1915
			 * We only add the <script> tags for code highlighting, so we strip them from the output.
1916
			 */
1917
1918
			return str_replace( array(
1919
				'<script>',
1920
				'</script>'
1921
			), '', $output );
1922
		}
1923
1924
		public function build_block_arguments($key,$args){
1925
			$custom_attributes = ! empty( $args['custom_attributes'] ) ? $this->array_to_attributes( $args['custom_attributes'] ) : '';
1926
			$options = '';
1927
			$extra = '';
1928
			$require = '';
0 ignored issues
show
Unused Code introduced by
The assignment to $require is dead and can be removed.
Loading history...
1929
			$onchange = "props.setAttributes({ $key: $key } )";
1930
			$value = "props.attributes.$key";
1931
			$text_type = array( 'text', 'password', 'number', 'email', 'tel', 'url', 'color' );
1932
			if ( in_array( $args['type'], $text_type ) ) {
1933
				$type = 'TextControl';
1934
				// Save numbers as numbers and not strings
1935
				if ( $args['type'] == 'number' ) {
1936
					$onchange = "props.setAttributes({ $key: Number($key) } )";
1937
				}
1938
			}
1939
			//									elseif ( $args['type'] == 'color' ) { //@todo ColorPicker labels are not shown yet, we use html5 color input for now https://github.com/WordPress/gutenberg/issues/14378
1940
			//										$type = 'ColorPicker';
1941
			//									}
1942
			elseif ( $args['type'] == 'checkbox' ) {
1943
				$type = 'CheckboxControl';
1944
				$extra .= "checked: props.attributes.$key,";
1945
				$onchange = "props.setAttributes({ $key: ! props.attributes.$key } )";
1946
			} elseif ( $args['type'] == 'select' || $args['type'] == 'multiselect' ) {
1947
				$type = 'SelectControl';
1948
				if ( ! empty( $args['options'] ) ) {
1949
					$options .= "options  : [";
1950
					foreach ( $args['options'] as $option_val => $option_label ) {
1951
						$options .= "{ value : '" . esc_attr( $option_val ) . "',     label : '" . esc_attr( $option_label ) . "'     },";
1952
					}
1953
					$options .= "],";
1954
				}
1955
				if ( isset( $args['multiple'] ) && $args['multiple'] ) { //@todo multiselect does not work at the moment: https://github.com/WordPress/gutenberg/issues/5550
1956
					$extra .= ' multiple: true, ';
1957
					//$onchange = "props.setAttributes({ $key: ['edit'] } )";
1958
					//$value = "['edit', 'delete']";
1959
				}
1960
			} elseif ( $args['type'] == 'alignment' ) {
1961
				$type = 'AlignmentToolbar'; // @todo this does not seem to work but cant find a example
1962
			} else {
1963
				return;// if we have not implemented the control then don't break the JS.
1964
			}
1965
1966
			// add show only if advanced
1967
			if ( ! empty( $args['advanced'] ) ) {
1968
				echo "props.attributes.show_advanced && ";
1969
			}
1970
			// add setting require if defined
1971
			if ( ! empty( $args['element_require'] ) ) {
1972
				echo $this->block_props_replace( $args['element_require'], true ) . " && ";
1973
			}
1974
			?>
1975
			el(
1976
			wp.components.<?php echo esc_attr( $type );?>,
1977
			{
1978
			label: '<?php echo esc_attr( $args['title'] );?>',
1979
			help: '<?php if ( isset( $args['desc'] ) ) {
1980
				echo esc_attr( $args['desc'] );
1981
			}?>',
1982
			value: <?php echo $value;?>,
1983
			<?php if ( $type == 'TextControl' && $args['type'] != 'text' ) {
1984
				echo "type: '" . esc_attr( $args['type'] ) . "',";
1985
			}?>
1986
			<?php if ( ! empty( $args['placeholder'] ) ) {
1987
				echo "placeholder: '" . esc_attr( $args['placeholder'] ) . "',";
1988
			}?>
1989
			<?php echo $options;?>
1990
			<?php echo $extra;?>
1991
			<?php echo $custom_attributes;?>
1992
			onChange: function ( <?php echo $key;?> ) {
1993
			<?php echo $onchange;?>
1994
			}
1995
			}
1996
			),
1997
			<?php
1998
		}
1999
2000
		/**
2001
		 * Convert an array of attributes to block string.
2002
		 *
2003
		 * @todo there is prob a faster way to do this, also we could add some validation here.
2004
		 *
2005
		 * @param $custom_attributes
2006
		 *
2007
		 * @return string
2008
		 */
2009
		public function array_to_attributes( $custom_attributes, $html = false ) {
2010
			$attributes = '';
2011
			if ( ! empty( $custom_attributes ) ) {
2012
2013
				if ( $html ) {
2014
					foreach ( $custom_attributes as $key => $val ) {
2015
						$attributes .= " $key='$val' ";
2016
					}
2017
				} else {
2018
					foreach ( $custom_attributes as $key => $val ) {
2019
						$attributes .= "'$key': '$val',";
2020
					}
2021
				}
2022
			}
2023
2024
			return $attributes;
2025
		}
2026
2027
		/**
2028
		 * A self looping function to create the output for JS block elements.
2029
		 *
2030
		 * This is what is output in the WP Editor visual view.
2031
		 *
2032
		 * @param $args
2033
		 */
2034
		public function block_element( $args ) {
2035
2036
2037
			if ( ! empty( $args ) ) {
2038
				foreach ( $args as $element => $new_args ) {
2039
2040
					if ( is_array( $new_args ) ) { // its an element
2041
2042
2043
						if ( isset( $new_args['element'] ) ) {
2044
2045
							if ( isset( $new_args['element_require'] ) ) {
2046
								echo str_replace( array(
2047
										"'+",
2048
										"+'"
2049
									), '', $this->block_props_replace( $new_args['element_require'] ) ) . " &&  ";
2050
								unset( $new_args['element_require'] );
2051
							}
2052
2053
							echo "\n el( '" . $new_args['element'] . "', {";
2054
2055
							// get the attributes
2056
							foreach ( $new_args as $new_key => $new_value ) {
2057
2058
2059
								if ( $new_key == 'element' || $new_key == 'content' || $new_key == 'element_require' || $new_key == 'element_repeat' || is_array( $new_value ) ) {
2060
									// do nothing
2061
								} else {
2062
									echo $this->block_element( array( $new_key => $new_value ) );
2063
								}
2064
							}
2065
2066
							echo "},";// end attributes
2067
2068
							// get the content
2069
							$first_item = 0;
2070
							foreach ( $new_args as $new_key => $new_value ) {
2071
								if ( $new_key === 'content' || is_array( $new_value ) ) {
2072
2073
									if ( $new_key === 'content' ) {
2074
										echo "'" . $this->block_props_replace( wp_slash( $new_value ) ) . "'";
2075
									}
2076
2077
									if ( is_array( $new_value ) ) {
2078
2079
										if ( isset( $new_value['element_require'] ) ) {
2080
											echo str_replace( array(
2081
													"'+",
2082
													"+'"
2083
												), '', $this->block_props_replace( $new_value['element_require'] ) ) . " &&  ";
2084
											unset( $new_value['element_require'] );
2085
										}
2086
2087
										if ( isset( $new_value['element_repeat'] ) ) {
2088
											$x = 1;
2089
											while ( $x <= absint( $new_value['element_repeat'] ) ) {
2090
												$this->block_element( array( '' => $new_value ) );
2091
												$x ++;
2092
											}
2093
										} else {
2094
											$this->block_element( array( '' => $new_value ) );
2095
										}
2096
									}
2097
									$first_item ++;
2098
								}
2099
							}
2100
2101
							echo ")";// end content
2102
2103
							echo ", \n";
2104
2105
						}
2106
					} else {
2107
2108
						if ( substr( $element, 0, 3 ) === "if_" ) {
2109
							echo str_replace( "if_", "", $element ) . ": " . $this->block_props_replace( $new_args, true ) . ",";
2110
						} elseif ( $element == 'style' ) {
2111
							echo $element . ": " . $this->block_props_replace( $new_args ) . ",";
2112
						} else {
2113
							echo $element . ": '" . $this->block_props_replace( $new_args ) . "',";
2114
						}
2115
2116
					}
2117
				}
2118
			}
2119
		}
2120
2121
		/**
2122
		 * Replace block attributes placeholders with the proper naming.
2123
		 *
2124
		 * @param $string
2125
		 *
2126
		 * @return mixed
2127
		 */
2128
		public function block_props_replace( $string, $no_wrap = false ) {
2129
2130
			if ( $no_wrap ) {
2131
				$string = str_replace( array( "[%", "%]" ), array( "props.attributes.", "" ), $string );
2132
			} else {
2133
				$string = str_replace( array( "[%", "%]" ), array( "'+props.attributes.", "+'" ), $string );
2134
			}
2135
2136
			return $string;
2137
		}
2138
2139
		/**
2140
		 * Outputs the content of the widget
2141
		 *
2142
		 * @param array $args
2143
		 * @param array $instance
2144
		 */
2145
		public function widget( $args, $instance ) {
2146
2147
			// get the filtered values
2148
			$argument_values = $this->argument_values( $instance );
2149
			$argument_values = $this->string_to_bool( $argument_values );
2150
			$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...
2151
2152
			ob_start();
2153
			if ( $output ) {
0 ignored issues
show
introduced by
$output is defined implicitly as null, thus it is always evaluated to false.
Loading history...
2154
				// Before widget
2155
				$before_widget = $args['before_widget'];
2156
				$before_widget = apply_filters( 'wp_super_duper_before_widget', $before_widget, $args, $instance, $this );
2157
				$before_widget = apply_filters( 'wp_super_duper_before_widget_' . $this->base_id, $before_widget, $args, $instance, $this );
2158
2159
				// After widget
2160
				$after_widget = $args['after_widget'];
2161
				$after_widget = apply_filters( 'wp_super_duper_after_widget', $after_widget, $args, $instance, $this );
2162
				$after_widget = apply_filters( 'wp_super_duper_after_widget_' . $this->base_id, $after_widget, $args, $instance, $this );
2163
2164
				echo $before_widget;
2165
				// elementor strips the widget wrapping div so we check for and add it back if needed
2166
				if ( $this->is_elementor_widget_output() ) {
2167
					echo ! empty( $this->options['widget_ops']['classname'] ) ? "<span class='" . esc_attr( $this->options['widget_ops']['classname'] ) . "'>" : '';
2168
				}
2169
				echo $this->output_title( $args, $instance );
2170
				echo $output;
2171
				if ( $this->is_elementor_widget_output() ) {
2172
					echo ! empty( $this->options['widget_ops']['classname'] ) ? "</span>" : '';
2173
				}
2174
				echo $after_widget;
2175
			} elseif ( $this->is_preview() && $output == '' ) {// if preview show a placeholder if empty
2176
				$output = $this->preview_placeholder_text( "{{" . $this->base_id . "}}" );
2177
				echo $output;
2178
			}
2179
			$output = ob_get_clean();
2180
2181
			$output = apply_filters( 'wp_super_duper_widget_output', $output, $instance, $args, $this );
2182
2183
			echo $output;
2184
		}
2185
2186
		/**
2187
		 * Tests if the current output is inside a elementor container.
2188
		 *
2189
		 * @since 1.0.4
2190
		 * @return bool
2191
		 */
2192
		public function is_elementor_widget_output() {
2193
			$result = false;
2194
			if ( defined( 'ELEMENTOR_VERSION' ) && isset( $this->number ) && $this->number == 'REPLACE_TO_ID' ) {
2195
				$result = true;
2196
			}
2197
2198
			return $result;
2199
		}
2200
2201
		/**
2202
		 * Tests if the current output is inside a elementor preview.
2203
		 *
2204
		 * @since 1.0.4
2205
		 * @return bool
2206
		 */
2207
		public function is_elementor_preview() {
2208
			$result = false;
2209
			if ( isset( $_REQUEST['elementor-preview'] ) || ( is_admin() && isset( $_REQUEST['action'] ) && $_REQUEST['action'] == 'elementor' ) || ( isset( $_REQUEST['action'] ) && $_REQUEST['action'] == 'elementor_ajax' ) ) {
2210
				$result = true;
2211
			}
2212
2213
			return $result;
2214
		}
2215
2216
		/**
2217
		 * Tests if the current output is inside a Divi preview.
2218
		 *
2219
		 * @since 1.0.6
2220
		 * @return bool
2221
		 */
2222
		public function is_divi_preview() {
2223
			$result = false;
2224
			if ( isset( $_REQUEST['et_fb'] ) || isset( $_REQUEST['et_pb_preview'] ) || ( is_admin() && isset( $_REQUEST['action'] ) && $_REQUEST['action'] == 'elementor' ) ) {
2225
				$result = true;
2226
			}
2227
2228
			return $result;
2229
		}
2230
2231
		/**
2232
		 * Tests if the current output is inside a Beaver builder preview.
2233
		 *
2234
		 * @since 1.0.6
2235
		 * @return bool
2236
		 */
2237
		public function is_beaver_preview() {
2238
			$result = false;
2239
			if ( isset( $_REQUEST['fl_builder'] ) ) {
2240
				$result = true;
2241
			}
2242
2243
			return $result;
2244
		}
2245
2246
		/**
2247
		 * Tests if the current output is inside a siteorigin builder preview.
2248
		 *
2249
		 * @since 1.0.6
2250
		 * @return bool
2251
		 */
2252
		public function is_siteorigin_preview() {
2253
			$result = false;
2254
			if ( ! empty( $_REQUEST['siteorigin_panels_live_editor'] ) ) {
2255
				$result = true;
2256
			}
2257
2258
			return $result;
2259
		}
2260
2261
		/**
2262
		 * Tests if the current output is inside a cornerstone builder preview.
2263
		 *
2264
		 * @since 1.0.8
2265
		 * @return bool
2266
		 */
2267
		public function is_cornerstone_preview() {
2268
			$result = false;
2269
			if ( ! empty( $_REQUEST['cornerstone_preview'] ) || basename( $_SERVER['REQUEST_URI'] ) == 'cornerstone-endpoint' ) {
2270
				$result = true;
2271
			}
2272
2273
			return $result;
2274
		}
2275
2276
		/**
2277
		 * Tests if the current output is inside a fusion builder preview.
2278
		 *
2279
		 * @since 1.1.0
2280
		 * @return bool
2281
		 */
2282
		public function is_fusion_preview() {
2283
			$result = false;
2284
			if ( ! empty( $_REQUEST['fb-edit'] ) || ! empty( $_REQUEST['fusion_load_nonce'] ) ) {
2285
				$result = true;
2286
			}
2287
2288
			return $result;
2289
		}
2290
2291
		/**
2292
		 * General function to check if we are in a preview situation.
2293
		 *
2294
		 * @since 1.0.6
2295
		 * @return bool
2296
		 */
2297
		public function is_preview() {
2298
			$preview = false;
2299
			if ( $this->is_divi_preview() ) {
2300
				$preview = true;
2301
			} elseif ( $this->is_elementor_preview() ) {
2302
				$preview = true;
2303
			} elseif ( $this->is_beaver_preview() ) {
2304
				$preview = true;
2305
			} elseif ( $this->is_siteorigin_preview() ) {
2306
				$preview = true;
2307
			} elseif ( $this->is_cornerstone_preview() ) {
2308
				$preview = true;
2309
			} elseif ( $this->is_fusion_preview() ) {
2310
				$preview = true;
2311
			}
2312
2313
			return $preview;
2314
		}
2315
2316
		/**
2317
		 * Output the super title.
2318
		 *
2319
		 * @param $args
2320
		 * @param array $instance
2321
		 *
2322
		 * @return string
2323
		 */
2324
		public function output_title( $args, $instance = array() ) {
2325
			$output = '';
2326
			if ( ! empty( $instance['title'] ) ) {
2327
				/** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */
2328
				$title  = apply_filters( 'widget_title', $instance['title'], $instance, $this->id_base );
2329
				$output = $args['before_title'] . $title . $args['after_title'];
2330
			}
2331
2332
			return $output;
2333
		}
2334
2335
		/**
2336
		 * Outputs the options form inputs for the widget.
2337
		 *
2338
		 * @param array $instance The widget options.
2339
		 */
2340
		public function form( $instance ) {
2341
2342
			// set widget instance
2343
			$this->instance = $instance;
2344
2345
			// set it as a SD widget
2346
			echo $this->widget_advanced_toggle();
2347
2348
			echo "<p>" . esc_attr( $this->options['widget_ops']['description'] ) . "</p>";
2349
			$arguments_raw = $this->get_arguments();
2350
2351
			if ( is_array( $arguments_raw ) ) {
0 ignored issues
show
introduced by
The condition is_array($arguments_raw) is always true.
Loading history...
2352
2353
				$arguments = $this->group_arguments($arguments_raw);
2354
2355
				// Do we have sections?
2356
				$has_sections = $arguments == $arguments_raw ? false : true;
2357
2358
2359
				if($has_sections){
2360
					$panel_count = 0;
2361
					foreach($arguments as $key => $args){
2362
2363
						?>
2364
						<script>
2365
//							jQuery(this).find("i").toggleClass("fas fa-chevron-up fas fa-chevron-down");jQuery(this).next().toggle();
2366
						</script>
2367
						<?php
2368
2369
						$hide = $panel_count ? ' style="display:none;" ' : '';
2370
						$icon_class = $panel_count ? 'fas fa-chevron-up' : 'fas fa-chevron-down';
2371
						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>";
2372
						echo "<div class='sd-toggle-group sd-input-group-".sanitize_title_with_dashes($key)."' $hide>";
2373
2374
						foreach($args as $k => $a){
2375
							$this->widget_inputs($a, $instance);
2376
						}
2377
2378
						echo "</div>";
2379
2380
						$panel_count++;
2381
2382
					}
2383
				}else{
2384
					foreach ( $arguments as $key => $args ) {
2385
						$this->widget_inputs( $args, $instance );
2386
					}
2387
				}
2388
2389
			}
2390
		}
2391
2392
		/**
2393
		 * Get the hidden input that when added makes the advanced button show on widget settings.
2394
		 *
2395
		 * @return string
2396
		 */
2397
		public function widget_advanced_toggle() {
2398
2399
			$output = '';
2400
			if ( $this->block_show_advanced() ) {
2401
				$val = 1;
2402
			} else {
2403
				$val = 0;
2404
			}
2405
2406
			$output .= "<input type='hidden'  class='sd-show-advanced' value='$val' />";
2407
2408
			return $output;
2409
		}
2410
2411
		/**
2412
		 * Convert require element.
2413
		 *
2414
		 * @since 1.0.0
2415
		 *
2416
		 * @param string $input Input element.
2417
		 *
2418
		 * @return string $output
2419
		 */
2420
		public function convert_element_require( $input ) {
2421
2422
			$input = str_replace( "'", '"', $input );// we only want double quotes
2423
2424
			$output = esc_attr( str_replace( array( "[%", "%]" ), array(
2425
				"jQuery(form).find('[data-argument=\"",
2426
				"\"]').find('input,select').val()"
2427
			), $input ) );
2428
2429
			return $output;
2430
		}
2431
2432
		/**
2433
		 * Builds the inputs for the widget options.
2434
		 *
2435
		 * @param $args
2436
		 * @param $instance
2437
		 */
2438
		public function widget_inputs( $args, $instance ) {
2439
2440
			$class             = "";
2441
			$element_require   = "";
2442
			$custom_attributes = "";
2443
2444
			// get value
2445
			if ( isset( $instance[ $args['name'] ] ) ) {
2446
				$value = $instance[ $args['name'] ];
2447
			} elseif ( ! isset( $instance[ $args['name'] ] ) && ! empty( $args['default'] ) ) {
2448
				$value = is_array( $args['default'] ) ? array_map( "esc_html", $args['default'] ) : esc_html( $args['default'] );
2449
			} else {
2450
				$value = '';
2451
			}
2452
2453
			// get placeholder
2454
			if ( ! empty( $args['placeholder'] ) ) {
2455
				$placeholder = "placeholder='" . esc_html( $args['placeholder'] ) . "'";
2456
			} else {
2457
				$placeholder = '';
2458
			}
2459
2460
			// get if advanced
2461
			if ( isset( $args['advanced'] ) && $args['advanced'] ) {
2462
				$class .= " sd-advanced-setting ";
2463
			}
2464
2465
			// element_require
2466
			if ( isset( $args['element_require'] ) && $args['element_require'] ) {
2467
				$element_require = $args['element_require'];
2468
			}
2469
2470
			// custom_attributes
2471
			if ( isset( $args['custom_attributes'] ) && $args['custom_attributes'] ) {
2472
				$custom_attributes = $this->array_to_attributes( $args['custom_attributes'], true );
2473
			}
2474
2475
			// before wrapper
2476
			?>
2477
			<p class="sd-argument <?php echo esc_attr( $class ); ?>"
2478
			   data-argument='<?php echo esc_attr( $args['name'] ); ?>'
2479
			   data-element_require='<?php if ( $element_require ) {
2480
				   echo $this->convert_element_require( $element_require );
2481
			   } ?>'
2482
			>
2483
				<?php
2484
2485
				switch ( $args['type'] ) {
2486
					//array('text','password','number','email','tel','url','color')
2487
					case "text":
2488
					case "password":
2489
					case "number":
2490
					case "email":
2491
					case "tel":
2492
					case "url":
2493
					case "color":
2494
						?>
2495
						<label
2496
							for="<?php echo esc_attr( $this->get_field_id( $args['name'] ) ); ?>"><?php echo esc_attr( $args['title'] ); ?><?php echo $this->widget_field_desc( $args ); ?></label>
2497
						<input <?php echo $placeholder; ?> class="widefat"
2498
							<?php echo $custom_attributes; ?>
2499
							                               id="<?php echo esc_attr( $this->get_field_id( $args['name'] ) ); ?>"
2500
							                               name="<?php echo esc_attr( $this->get_field_name( $args['name'] ) ); ?>"
2501
							                               type="<?php echo esc_attr( $args['type'] ); ?>"
2502
							                               value="<?php echo esc_attr( $value ); ?>">
2503
						<?php
2504
2505
						break;
2506
					case "select":
2507
						$multiple = isset( $args['multiple'] ) && $args['multiple'] ? true : false;
2508
						if ( $multiple ) {
2509
							if ( empty( $value ) ) {
2510
								$value = array();
2511
							}
2512
						}
2513
						?>
2514
						<label
2515
							for="<?php echo esc_attr( $this->get_field_id( $args['name'] ) ); ?>"><?php echo esc_attr( $args['title'] ); ?><?php echo $this->widget_field_desc( $args ); ?></label>
2516
						<select <?php echo $placeholder; ?> class="widefat"
2517
							<?php echo $custom_attributes; ?>
2518
							                                id="<?php echo esc_attr( $this->get_field_id( $args['name'] ) ); ?>"
2519
							                                name="<?php echo esc_attr( $this->get_field_name( $args['name'] ) );
2520
							                                if ( $multiple ) {
2521
								                                echo "[]";
2522
							                                } ?>"
2523
							<?php if ( $multiple ) {
2524
								echo "multiple";
2525
							} //@todo not implemented yet due to gutenberg not supporting it
2526
							?>
2527
						>
2528
							<?php
2529
2530
							if ( ! empty( $args['options'] ) ) {
2531
								foreach ( $args['options'] as $val => $label ) {
2532
									if ( $multiple ) {
2533
										$selected = in_array( $val, $value ) ? 'selected="selected"' : '';
2534
									} else {
2535
										$selected = selected( $value, $val, false );
2536
									}
2537
									echo "<option value='$val' " . $selected . ">$label</option>";
2538
								}
2539
							}
2540
							?>
2541
						</select>
2542
						<?php
2543
						break;
2544
					case "checkbox":
2545
						?>
2546
						<input <?php echo $placeholder; ?>
2547
							<?php checked( 1, $value, true ) ?>
2548
							<?php echo $custom_attributes; ?>
2549
							class="widefat" id="<?php echo esc_attr( $this->get_field_id( $args['name'] ) ); ?>"
2550
							name="<?php echo esc_attr( $this->get_field_name( $args['name'] ) ); ?>" type="checkbox"
2551
							value="1">
2552
						<label
2553
							for="<?php echo esc_attr( $this->get_field_id( $args['name'] ) ); ?>"><?php echo esc_attr( $args['title'] ); ?><?php echo $this->widget_field_desc( $args ); ?></label>
2554
						<?php
2555
						break;
2556
					case "hidden":
2557
						?>
2558
						<input id="<?php echo esc_attr( $this->get_field_id( $args['name'] ) ); ?>"
2559
						       name="<?php echo esc_attr( $this->get_field_name( $args['name'] ) ); ?>" type="hidden"
2560
						       value="<?php echo esc_attr( $value ); ?>">
2561
						<?php
2562
						break;
2563
					default:
2564
						echo "No input type found!"; // @todo we need to add more input types.
2565
				}
2566
2567
				// after wrapper
2568
				?>
2569
			</p>
2570
			<?php
2571
2572
		}
2573
2574
		/**
2575
		 * Get the widget input description html.
2576
		 *
2577
		 * @param $args
2578
		 *
2579
		 * @return string
2580
		 * @todo, need to make its own tooltip script
2581
		 */
2582
		public function widget_field_desc( $args ) {
2583
2584
			$description = '';
2585
			if ( isset( $args['desc'] ) && $args['desc'] ) {
2586
				if ( isset( $args['desc_tip'] ) && $args['desc_tip'] ) {
2587
					$description = $this->desc_tip( $args['desc'] );
2588
				} else {
2589
					$description = '<span class="description">' . wp_kses_post( $args['desc'] ) . '</span>';
2590
				}
2591
			}
2592
2593
			return $description;
2594
		}
2595
2596
		/**
2597
		 * Get the tool tip html.
2598
		 *
2599
		 * @param $tip
2600
		 * @param bool $allow_html
2601
		 *
2602
		 * @return string
2603
		 */
2604
		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...
2605
			if ( $allow_html ) {
2606
				$tip = $this->sanitize_tooltip( $tip );
2607
			} else {
2608
				$tip = esc_attr( $tip );
2609
			}
2610
2611
			return '<span class="gd-help-tip dashicons dashicons-editor-help" title="' . $tip . '"></span>';
2612
		}
2613
2614
		/**
2615
		 * Sanitize a string destined to be a tooltip.
2616
		 *
2617
		 * @param string $var
2618
		 *
2619
		 * @return string
2620
		 */
2621
		public function sanitize_tooltip( $var ) {
2622
			return htmlspecialchars( wp_kses( html_entity_decode( $var ), array(
2623
				'br'     => array(),
2624
				'em'     => array(),
2625
				'strong' => array(),
2626
				'small'  => array(),
2627
				'span'   => array(),
2628
				'ul'     => array(),
2629
				'li'     => array(),
2630
				'ol'     => array(),
2631
				'p'      => array(),
2632
			) ) );
2633
		}
2634
2635
		/**
2636
		 * Processing widget options on save
2637
		 *
2638
		 * @param array $new_instance The new options
2639
		 * @param array $old_instance The previous options
2640
		 *
2641
		 * @return array
2642
		 * @todo we should add some sanitation here.
2643
		 */
2644
		public function update( $new_instance, $old_instance ) {
2645
2646
			//save the widget
2647
			$instance = array_merge( (array) $old_instance, (array) $new_instance );
2648
2649
			// set widget instance
2650
			$this->instance = $instance;
2651
2652
			if ( empty( $this->arguments ) ) {
2653
				$this->get_arguments();
2654
			}
2655
2656
			// check for checkboxes
2657
			if ( ! empty( $this->arguments ) ) {
2658
				foreach ( $this->arguments as $argument ) {
2659
					if ( isset( $argument['type'] ) && $argument['type'] == 'checkbox' && ! isset( $new_instance[ $argument['name'] ] ) ) {
2660
						$instance[ $argument['name'] ] = '0';
2661
					}
2662
				}
2663
			}
2664
2665
			return $instance;
2666
		}
2667
2668
		/**
2669
		 * Checks if the current call is a ajax call to get the block content.
2670
		 *
2671
		 * This can be used in your widget to return different content as the block content.
2672
		 *
2673
		 * @since 1.0.3
2674
		 * @return bool
2675
		 */
2676
		public function is_block_content_call() {
2677
			$result = false;
2678
			if ( wp_doing_ajax() && isset( $_REQUEST['action'] ) && $_REQUEST['action'] == 'super_duper_output_shortcode' ) {
2679
				$result = true;
2680
			}
2681
2682
			return $result;
2683
		}
2684
2685
	}
2686
2687
}