Passed
Push — master ( a83567...99d634 )
by Stiofan
05:05
created

WP_Super_Duper::shortcode_output()   F

Complexity

Conditions 18
Paths 512

Size

Total Lines 57
Code Lines 34

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 18
eloc 34
c 3
b 0
f 0
nc 512
nop 2
dl 0
loc 57
rs 1.3777

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

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

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

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...
1285
1286
			}
1287
			wp_die();
1288
		}
1289
1290
		/**
1291
		 * Output the shortcode.
1292
		 *
1293
		 * @param array $args
1294
		 * @param string $content
1295
		 *
1296
		 * @return string
1297
		 */
1298
		public function shortcode_output( $args = array(), $content = '' ) {
1299
			$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

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

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