Passed
Push — master ( 03dff3...2bff3c )
by Stiofan
01:08 queued 13s
created

WP_Super_Duper::is_elementor_widget_output()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
nc 2
nop 0
dl 0
loc 8
rs 10
c 0
b 0
f 0
1
<?php
2
if ( ! defined( 'ABSPATH' ) ) {
3
	exit;
4
}
5
6
if ( ! class_exists( 'WP_Super_Duper' ) ) {
7
8
9
	/**
10
	 * A Class to be able to create a Widget, Shortcode or Block to be able to output content for WordPress.
11
	 *
12
	 * Should not be called direct but extended instead.
13
	 *
14
	 * Class WP_Super_Duper
15
	 * @since 1.0.3 is_block_content_call() method added.
16
	 * @since 1.0.3 Placeholder text will be shown for widget that return no block content.
17
	 * @since 1.0.4 is_elementor_widget_output() method added.
18
	 * @since 1.0.4 is_elementor_preview() method added.
19
	 * @since 1.0.5 Block checkbox options are set as true by default even when set as false - FIXED
20
	 * @ver 1.0.5
21
	 */
22
	class WP_Super_Duper extends WP_Widget {
23
24
25
		public $version = "1.0.5";
26
		public $block_code;
27
		public $options;
28
		public $base_id;
29
		public $arguments = array();
30
		public $instance = array();
31
		private $class_name;
32
33
		/**
34
		 * Take the array options and use them to build.
35
		 */
36
		public function __construct( $options ) {
37
			global $sd_widgets;
38
39
			$sd_widgets[ $options['base_id'] ] = array( 'name'       => $options['name'],
40
			                                            'class_name' => $options['class_name']
41
			);
42
			$this->base_id                     = $options['base_id'];
43
			// lets filter the options before we do anything
44
			$options       = apply_filters( "wp_super_duper_options", $options );
45
			$options       = apply_filters( "wp_super_duper_options_{$this->base_id}", $options );
46
			$options       = $this->add_name_from_key( $options );
47
			$this->options = $options;
48
49
			$this->base_id   = $options['base_id'];
50
			$this->arguments = isset( $options['arguments'] ) ? $options['arguments'] : array();
51
52
			// init parent
53
			parent::__construct( $options['base_id'], $options['name'], $options['widget_ops'] );
54
55
			if ( isset( $options['class_name'] ) ) {
56
				// register widget
57
				$this->class_name = $options['class_name'];
58
59
				// register shortcode
60
				$this->register_shortcode();
61
62
				// register block
63
				add_action( 'admin_enqueue_scripts', array( $this, 'register_block' ) );
64
			}
65
66
			// add the CSS and JS we need ONCE
67
			global $sd_widget_scripts;
68
69
			if ( ! $sd_widget_scripts ) {
70
				wp_add_inline_script( 'admin-widgets', $this->widget_js() );
71
				wp_add_inline_script( 'customize-controls', $this->widget_js() );
72
				wp_add_inline_style( 'widgets', $this->widget_css() );
73
74
				$sd_widget_scripts = true;
75
76
				// add shortcode insert button once
77
				add_action( 'media_buttons', array( $this, 'shortcode_insert_button' ) );
78
				add_action( 'wp_ajax_super_duper_get_widget_settings', array( __CLASS__, 'get_widget_settings' ) );
79
			}
80
81
			do_action( 'wp_super_duper_widget_init', $options, $this );
82
		}
83
84
		/**
85
		 * Get widget settings.
86
		 *
87
		 * @since 1.0.0
88
		 */
89
		public static function get_widget_settings() {
90
			global $sd_widgets;
91
92
			$shortcode = isset( $_REQUEST['shortcode'] ) && $_REQUEST['shortcode'] ? sanitize_title_with_dashes( $_REQUEST['shortcode'] ) : '';
93
			if ( ! $shortcode ) {
94
				wp_die();
95
			}
96
			$widget_args = isset( $sd_widgets[ $shortcode ] ) ? $sd_widgets[ $shortcode ] : '';
97
			if ( ! $widget_args ) {
98
				wp_die();
99
			}
100
			$class_name = isset( $widget_args['class_name'] ) && $widget_args['class_name'] ? $widget_args['class_name'] : '';
101
			if ( ! $class_name ) {
102
				wp_die();
103
			}
104
105
			// invoke an instance method
106
			$widget = new $class_name;
107
108
			ob_start();
109
			$widget->form( array() );
110
			$form = ob_get_clean();
111
			echo "<form id='$shortcode'>" . $form . "<div class=\"widget-control-save\"></div></form>";
112
			echo "<style>" . $widget->widget_css() . "</style>";
113
			echo "<script>" . $widget->widget_js() . "</script>";
114
			?>
115
			<?php
116
			wp_die();
117
		}
118
119
		/**
120
		 * Insert shortcode builder button to classic editor (not inside Gutenberg, not needed).
121
		 *
122
		 * @since 1.0.0
123
		 *
124
		 * @param string $editor_id Optional. Shortcode editor id. Default null.
125
		 * @param string $insert_shortcode_function Optional. Insert shotcode function. Default null.
126
		 */
127
		public static function shortcode_insert_button( $editor_id = '', $insert_shortcode_function = '' ) {
128
			global $sd_widgets, $shortcode_insert_button_once;
129
			if ( $shortcode_insert_button_once ) {
130
				return;
131
			}
132
			add_thickbox();
133
			?>
134
			<div id="super-duper-content" style="display:none;">
135
136
				<div class="sd-shortcode-left-wrap">
137
					<?php
138
					asort( $sd_widgets );
139
					if ( ! empty( $sd_widgets ) ) {
140
						echo '<select onchange="sd_get_shortcode_options(this);">';
141
						echo "<option>" . __( 'Select shortcode' ) . "</option>";
142
						foreach ( $sd_widgets as $shortcode => $class ) {
143
							echo "<option value='" . esc_attr( $shortcode ) . "'>" . esc_attr( $shortcode ) . " (" . esc_attr( $class['name'] ) . ")</option>";
144
						}
145
						echo "</select>";
146
147
					}
148
					?>
149
					<div class="sd-shortcode-settings"></div>
150
151
				</div>
152
153
				<div class="sd-shortcode-right-wrap">
154
					<textarea id='sd-shortcode-output' disabled></textarea>
155
					<div id='sd-shortcode-output-actions'>
156
						<button class="button"
157
						        onclick="sd_insert_shortcode()"><?php _e( 'Insert shortcode' ); ?></button>
158
						<button class="button"
159
						        onclick="sd_copy_to_clipboard()"><?php _e( 'Copy shortcode' ); ?></button>
160
					</div>
161
				</div>
162
163
			</div>
164
165
			<?php
166
			// if Font Awesome is available then show a icon if not show a WP icon.
167
			$button_string = wp_style_is( 'font-awesome', 'enqueued' ) && 1 == 2 ? '<i class="fas fa-cubes" aria-hidden="true"></i>' : '<span style="padding-top: 3px;" class="dashicons dashicons-screenoptions"></span>';
168
			?>
169
170
			<a href="#TB_inline?width=100%&height=550&inlineId=super-duper-content"
171
			   class="thickbox button super-duper-content-open"
172
			   title="<?php _e( 'Add Shortcode' ); ?>"><?php echo $button_string; ?></a>
173
174
			<style>
175
				.sd-shortcode-left-wrap {
176
					float: left;
177
					width: 60%;
178
				}
179
180
				.sd-shortcode-left-wrap .gd-help-tip {
181
					float: none;
182
				}
183
184
				.sd-shortcode-right-wrap {
185
					float: right;
186
					width: 35%;
187
				}
188
189
				#sd-shortcode-output {
190
					height: 250px;
191
					width: 100%;
192
				}
193
			</style>
194
			<script>
195
196
				<?php
197
				if(! empty( $insert_shortcode_function )){
198
					echo $insert_shortcode_function;
199
				}else{
200
201
				/**
202
				 * Function for super duper insert shortcode.
203
				 *
204
				 * @since 1.0.0
205
				 */
206
				?>
207
				function sd_insert_shortcode() {
208
					$shortcode = jQuery('#sd-shortcode-output').val();
209
					if ($shortcode) {
210
						console.log(jQuery("#wp-content-editor-container textarea").attr("aria-hidden"));
211
						if (tinyMCE && tinyMCE.activeEditor && jQuery("#wp-content-editor-container textarea").attr("aria-hidden") == "true") {
212
							tinyMCE.execCommand('mceInsertContent', false, $shortcode);
213
						} else {
214
							var $txt = jQuery("#wp-content-editor-container textarea");
215
							var caretPos = $txt[0].selectionStart;
216
							var textAreaTxt = $txt.val();
217
							var txtToAdd = $shortcode;
218
							$txt.val(textAreaTxt.substring(0, caretPos) + txtToAdd + textAreaTxt.substring(caretPos));
219
						}
220
						tb_remove();
221
					}
222
				}
223
				<?php }?>
224
225
				function sd_copy_to_clipboard() {
226
					/* Get the text field */
227
					var copyText = document.getElementById("sd-shortcode-output");
228
					//un-disable the field
229
					copyText.disabled = false;
230
					/* Select the text field */
231
					copyText.select();
232
					/* Copy the text inside the text field */
233
					document.execCommand("Copy");
234
					//re-disable the field
235
					copyText.disabled = true;
236
					/* Alert the copied text */
237
					alert("Copied the text: " + copyText.value);
238
				}
239
				function sd_get_shortcode_options($this) {
240
241
					$short_code = jQuery($this).val();
242
					if ($short_code) {
243
244
						var data = {
245
							'action': 'super_duper_get_widget_settings',
246
							'shortcode': $short_code,
247
							'attributes': 123,
248
							'post_id': 321,
249
							'_ajax_nonce': '<?php echo wp_create_nonce( 'super_duper_output_shortcode' );?>'
250
						};
251
252
						jQuery.post(ajaxurl, data, function (response) {
253
							console.log(response);
254
							jQuery('.sd-shortcode-settings').html(response);
255
256
							jQuery('#' + $short_code).on('change', 'select', function () {
257
								sd_build_shortcode($short_code);
258
							}); // take care of select tags
259
260
							jQuery('#' + $short_code).on('change keypress keyup', 'input', function () {
261
								sd_build_shortcode($short_code);
262
							});
263
264
							sd_build_shortcode($short_code);
265
266
							// resize the window to fit
267
							jQuery('#TB_ajaxContent').css('width', 'auto').css('height', 'calc(100% - 46px)');
268
269
							return response;
270
						});
271
					}
272
273
				}
274
275
				function sd_build_shortcode($id) {
276
277
					var multiSelects = {};
278
					var multiSelectsRemove = [];
279
280
					$output = "[" + $id;
281
282
					$form_data = jQuery("#" + $id).serializeArray();
283
284
					// run checks for multiselects
285
					jQuery.each($form_data, function (index, element) {
286
						if (element && element.value) {
287
							$field_name = element.name.substr(element.name.indexOf("][") + 2);
288
							$field_name = $field_name.replace("]", "");
289
							// check if its a multiple
290
							if ($field_name.includes("[]")) {
291
								multiSelectsRemove[multiSelectsRemove.length] = index;
292
								$field_name = $field_name.replace("[]", "");
293
								if ($field_name in multiSelects) {
294
									multiSelects[$field_name] = multiSelects[$field_name] + "," + element.value;
295
								} else {
296
									multiSelects[$field_name] = element.value;
297
								}
298
							}
299
						}
300
					});
301
302
					// fix multiselects if any are found
303
					if (multiSelectsRemove.length) {
304
305
						// remove all multiselects
306
						multiSelectsRemove.reverse();
307
						multiSelectsRemove.forEach(function (index) {
308
							$form_data.splice(index, 1);
309
						});
310
311
						$ms_arr = [];
312
						// add multiselets back
313
						jQuery.each(multiSelects, function (index, value) {
314
							$ms_arr[$ms_arr.length] = {"name": "[][" + index + "]", "value": value};
315
						});
316
						$form_data = $form_data.concat($ms_arr);
317
					}
318
319
320
					if ($form_data) {
321
						$form_data.forEach(function (element) {
322
323
							if (element.value) {
324
								$field_name = element.name.substr(element.name.indexOf("][") + 2);
325
								$field_name = $field_name.replace("]", "");
326
								$output = $output + " " + $field_name + '="' + element.value + '"';
327
							}
328
329
						});
330
					}
331
					$output = $output + "]";
332
					jQuery('#sd-shortcode-output').html($output);
333
				}
334
			</script>
335
			<?php
336
			$shortcode_insert_button_once = true;
337
		}
338
339
		public function widget_css() {
340
			ob_start();
341
			?>
342
			<style>
343
				.sd-advanced-setting {
344
					display: none;
345
				}
346
347
				.sd-advanced-setting.sd-adv-show {
348
					display: block;
349
				}
350
351
				.sd-argument.sd-require-hide,
352
				.sd-advanced-setting.sd-require-hide {
353
					display: none;
354
				}
355
356
				button.sd-advanced-button {
357
					margin-right: 3px !important;
358
					font-size: 20px !important;
359
				}
360
			</style>
361
			<?php
362
			$output = ob_get_clean();
363
364
			/*
365
			 * We only add the <script> tags for code highlighting, so we strip them from the output.
366
			 */
367
			return str_replace( array(
368
				'<style>',
369
				'</style>'
370
			), '', $output );
371
		}
372
373
		public function widget_js() {
374
			ob_start();
375
			?>
376
			<script>
377
378
				/**
379
				 * Toggle advanced settings visibility.
380
				 */
381
				function sd_toggle_advanced($this) {
382
					var form = jQuery($this).parents('form,.form');
383
					form.find('.sd-advanced-setting').toggleClass('sd-adv-show');
384
					return false;// prevent form submit
385
				}
386
387
				/**
388
				 * Check a form to see what items shoudl be shown or hidden.
389
				 */
390
				function sd_show_hide(form) {
391
					console.log('show/hide');
392
					jQuery(form).find(".sd-argument").each(function () {
393
394
						var $element_require = jQuery(this).data('element_require');
395
396
						if ($element_require) {
397
398
							$element_require = $element_require.replace("&#039;", "'"); // replace single quotes
399
							$element_require = $element_require.replace("&quot;", '"'); // replace double quotes
400
401
							if (eval($element_require)) {
402
								jQuery(this).removeClass('sd-require-hide');
403
							} else {
404
								jQuery(this).addClass('sd-require-hide');
405
							}
406
						}
407
					});
408
				}
409
410
				/**
411
				 * Initialise widgets from the widgets screen.
412
				 */
413
				function sd_init_widgets($selector) {
414
					jQuery(".sd-show-advanced").each(function (index) {
415
						sd_init_widget(this, $selector);
416
					});
417
				}
418
419
				/**
420
				 * Initialise a individual widget.
421
				 */
422
				function sd_init_widget($this, $selector) {
423
					console.log($selector);
424
425
					if (!$selector) {
426
						$selector = 'form';
427
					}
428
					// only run once.
429
					if (jQuery($this).data('sd-widget-enabled')) {
430
						return;
431
					} else {
432
						jQuery($this).data('sd-widget-enabled', true);
433
					}
434
435
					var $button = '<button class="button button-primary right sd-advanced-button" onclick="sd_toggle_advanced(this);return false;"><i class="fas fa-sliders-h" aria-hidden="true"></i></button>';
436
					var form = jQuery($this).parents('' + $selector + '');
437
438
					if (jQuery($this).val() == '1' && jQuery(form).find('.sd-advanced-button').length == 0) {
439
						console.log('add advanced button');
440
441
						jQuery(form).find('.widget-control-save').after($button);
442
					} else {
443
						console.log('no advanced button');
444
						console.log(jQuery($this).val());
445
						console.log(jQuery(form).find('.sd-advanced-button').length);
446
447
					}
448
449
					// show hide on form change
450
					jQuery(form).change(function () {
451
						sd_show_hide(form);
452
					});
453
454
					// show hide on load
455
					sd_show_hide(form);
456
				}
457
458
				/**
459
				 * Init a customizer widget.
460
				 */
461
				function sd_init_customizer_widget(section) {
462
					if (section.expanded) {
463
						section.expanded.bind(function (isExpanding) {
464
							if (isExpanding) {
465
								// is it a SD widget?
466
								if (jQuery(section.container).find('.sd-show-advanced').length) {
467
									// init the widget
468
									sd_init_widget(jQuery(section.container).find('.sd-show-advanced'), ".form");
469
								}
470
							}
471
						});
472
					}
473
				}
474
475
				/**
476
				 * If on widgets screen.
477
				 */
478
				jQuery(function () {
479
					// if not in customizer.
480
					if (!wp.customize) {
481
						sd_init_widgets("form");
482
					}
483
484
					// init on widget added
485
					jQuery(document).on('widget-added', function (e, widget) {
486
						console.log('widget added');
487
						// is it a SD widget?
488
						if (jQuery(widget).find('.sd-show-advanced').length) {
489
							// init the widget
490
							sd_init_widget(jQuery(widget).find('.sd-show-advanced'), "form");
491
						}
492
					});
493
494
					// inint on widget updated
495
					jQuery(document).on('widget-updated', function (e, widget) {
496
						console.log('widget updated');
497
498
						// is it a SD widget?
499
						if (jQuery(widget).find('.sd-show-advanced').length) {
500
							// init the widget
501
							sd_init_widget(jQuery(widget).find('.sd-show-advanced'), "form");
502
						}
503
					});
504
505
				});
506
507
508
				/**
509
				 * We need to run this before jQuery is ready
510
				 */
511
				if (wp.customize) {
512
					wp.customize.bind('ready', function () {
513
514
						// init widgets on load
515
						wp.customize.control.each(function (section) {
516
							sd_init_customizer_widget(section);
517
						});
518
519
						// init widgets on add
520
						wp.customize.control.bind('add', function (section) {
521
							sd_init_customizer_widget(section);
522
						});
523
524
					});
525
526
				}
527
				<?php do_action( 'wp_super_duper_widget_js', $this ); ?>
528
			</script>
529
			<?php
530
			$output = ob_get_clean();
531
532
			/*
533
			 * We only add the <script> tags for code highlighting, so we strip them from the output.
534
			 */
535
			return str_replace( array(
536
				'<script>',
537
				'</script>'
538
			), '', $output );
539
		}
540
541
542
		/**
543
		 * Set the name from the argument key.
544
		 *
545
		 * @param $options
546
		 *
547
		 * @return mixed
548
		 */
549
		private function add_name_from_key( $options, $arguments = false ) {
550
			if ( ! empty( $options['arguments'] ) ) {
551
				foreach ( $options['arguments'] as $key => $val ) {
552
					$options['arguments'][ $key ]['name'] = $key;
553
				}
554
			} elseif ( $arguments && is_array( $options ) && ! empty( $options ) ) {
555
				foreach ( $options as $key => $val ) {
556
					$options[ $key ]['name'] = $key;
557
				}
558
			}
559
560
			return $options;
561
		}
562
563
		/**
564
		 * Register the parent shortcode.
565
		 *
566
		 * @since 1.0.0
567
		 */
568
		public function register_shortcode() {
569
			add_shortcode( $this->base_id, array( $this, 'shortcode_output' ) );
570
			add_action( 'wp_ajax_super_duper_output_shortcode', array( __CLASS__, 'render_shortcode' ) );
571
		}
572
573
		/**
574
		 * Render the shortcode via ajax so we can return it to Gutenberg.
575
		 *
576
		 * @since 1.0.0
577
		 */
578
		public static function render_shortcode() {
579
580
			check_ajax_referer( 'super_duper_output_shortcode', '_ajax_nonce', true );
581
			if ( ! current_user_can( 'manage_options' ) ) {
582
				wp_die();
583
			}
584
585
			// we might need the $post value here so lets set it.
586
			if ( isset( $_POST['post_id'] ) && $_POST['post_id'] ) {
587
				$post_obj = get_post( absint( $_POST['post_id'] ) );
588
				if ( ! empty( $post_obj ) && empty( $post ) ) {
0 ignored issues
show
Bug introduced by
The variable $post seems only to be defined at a later point. As such the call to empty() seems to always evaluate to true.

This check marks calls to isset(...) or empty(...) that are found before the variable itself is defined. These will always have the same result.

This is likely the result of code being shifted around. Consider removing these calls.

Loading history...
589
					global $post;
590
					$post = $post_obj;
591
				}
592
			}
593
594
			if ( isset( $_POST['shortcode'] ) && $_POST['shortcode'] ) {
595
				$shortcode_name   = sanitize_title_with_dashes( $_POST['shortcode'] );
596
				$attributes_array = isset( $_POST['attributes'] ) && $_POST['attributes'] ? $_POST['attributes'] : array();
597
				$attributes       = '';
598
				if ( ! empty( $attributes_array ) ) {
599
					foreach ( $attributes_array as $key => $value ) {
600
						$attributes .= " " . sanitize_title_with_dashes( $key ) . "='" . wp_slash( $value ) . "' ";
601
					}
602
				}
603
604
				$shortcode = "[" . $shortcode_name . " " . $attributes . "]";
605
606
				echo do_shortcode( $shortcode );
607
608
			}
609
			wp_die();
610
		}
611
612
		/**
613
		 * Output the shortcode.
614
		 *
615
		 * @param array $args
616
		 * @param string $content
617
		 *
618
		 * @return string
619
		 */
620
		public function shortcode_output( $args = array(), $content = '' ) {
621
			$args = self::argument_values( $args );
622
623
			// add extra argument so we know its a output to gutenberg
624
			//$args
625
			$args = $this->string_to_bool( $args );
626
627
628
			$calss = isset( $this->options['widget_ops']['classname'] ) ? esc_attr( $this->options['widget_ops']['classname'] ) : '';
629
630
			$calss = apply_filters( 'wp_super_duper_div_classname', $calss, $args, $this );
631
			$calss = apply_filters( 'wp_super_duper_div_classname_' . $this->base_id, $calss, $args, $this );
632
633
			$attrs = apply_filters( 'wp_super_duper_div_attrs', '', $args, $this );
0 ignored issues
show
Unused Code introduced by
$attrs is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
634
			$attrs = apply_filters( 'wp_super_duper_div_attrs_' . $this->base_id, '', $args, $this );
635
636
			$shortcode_args = array();
637
			$output         = '';
638
			$no_wrap        = isset( $this->options['no_wrap'] ) && $this->options['no_wrap'] ? true : false;
639
			$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) (which targets 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...
640
			if ( $main_content && ! $no_wrap ) {
641
				// wrap the shortcode in a dive with the same class as the widget
642
				$output .= '<div class="' . $calss . '" ' . $attrs . '>';
643
				if ( ! empty( $args['title'] ) ) {
644
					// if its a shortcode and there is a title try to grab the title wrappers
645
					$shortcode_args = array( 'before_title' => '', 'after_title' => '' );
646
					if ( empty( $instance ) ) {
0 ignored issues
show
Bug introduced by
The variable $instance seems to never exist, and therefore empty should always return true. Did you maybe rename this variable?

This check looks for calls to isset(...) or empty() on variables that are yet undefined. These calls will always produce the same result and can be removed.

This is most likely caused by the renaming of a variable or the removal of a function/method parameter.

Loading history...
647
						global $wp_registered_sidebars;
648
						if ( ! empty( $wp_registered_sidebars ) ) {
649
							foreach ( $wp_registered_sidebars as $sidebar ) {
650
								if ( ! empty( $sidebar['before_title'] ) ) {
651
									$shortcode_args['before_title'] = $sidebar['before_title'];
652
									$shortcode_args['after_title']  = $sidebar['after_title'];
653
									break;
654
								}
655
							}
656
						}
657
					}
658
					$output .= $this->output_title( $shortcode_args, $args );
659
				}
660
				$output .= $main_content;
661
				$output .= '</div>';
662
			} elseif ( $main_content && $no_wrap ) {
663
				$output .= $main_content;
664
			}
665
666
			return $output;
667
		}
668
669
		/**
670
		 * Sometimes booleans values can be turned to strings, so we fix that.
671
		 *
672
		 * @param $options
673
		 *
674
		 * @return mixed
675
		 */
676
		public function string_to_bool( $options ) {
677
			// convert bool strings to booleans
678
			foreach ( $options as $key => $val ) {
679
				if ( $val == 'false' ) {
680
					$options[ $key ] = false;
681
				} elseif ( $val == 'true' ) {
682
					$options[ $key ] = true;
683
				}
684
			}
685
686
			return $options;
687
		}
688
689
		/**
690
		 * Get the argument values that are also filterable.
691
		 *
692
		 * @param $instance
693
		 *
694
		 * @return array
695
		 */
696
		public function argument_values( $instance ) {
697
			$argument_values = array();
698
699
			// set widget instance
700
			$this->instance = $instance;
701
702
			if ( empty( $this->arguments ) ) {
703
				$this->arguments = $this->get_arguments();
704
			}
705
706
			if ( ! empty( $this->arguments ) ) {
707
				foreach ( $this->arguments as $key => $args ) {
708
					// set the input name from the key
709
					$args['name'] = $key;
710
					//
711
					$argument_values[ $key ] = isset( $instance[ $key ] ) ? $instance[ $key ] : '';
712
					if ( $argument_values[ $key ] == '' && isset( $args['default'] ) ) {
713
						$argument_values[ $key ] = $args['default'];
714
					}
715
				}
716
			}
717
718
			return $argument_values;
719
		}
720
721
		/**
722
		 * Set arguments in super duper.
723
		 *
724
		 * @since 1.0.0
725
		 *
726
		 * @return array Set arguments.
727
		 */
728
		public function set_arguments() {
729
			return $this->arguments;
730
		}
731
732
		/**
733
		 * Get arguments in super duper.
734
		 *
735
		 * @since 1.0.0
736
		 *
737
		 * @return array Get arguments.
738
		 */
739
		public function get_arguments() {
740
			if ( empty( $this->arguments ) ) {
741
				$this->arguments = $this->set_arguments();
742
			}
743
744
			$this->arguments = apply_filters( 'wp_super_duper_arguments', $this->arguments, $this->options, $this->instance );
745
			$this->arguments = $this->add_name_from_key( $this->arguments, true );
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->add_name_from_key($this->arguments, true) of type * is incompatible with the declared type array of property $arguments.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
746
747
			return $this->arguments;
748
		}
749
750
		/**
751
		 * This is the main output class for all 3 items, widget, shortcode and block, it is extended in the calling class.
752
		 *
753
		 * @param array $args
754
		 * @param array $widget_args
755
		 * @param string $content
756
		 */
757
		public function output( $args = array(), $widget_args = array(), $content = '' ) {
758
759
		}
760
761
		/**
762
		 * Add the dynamic block code inline when the wp-block in enqueued.
763
		 */
764
		public function register_block() {
765
			wp_add_inline_script( 'wp-blocks', $this->block() );
766
		}
767
768
		/**
769
		 * Check if we need to show advanced options.
770
		 *
771
		 * @return bool
772
		 */
773
		public function block_show_advanced() {
774
775
			$show      = false;
776
			$arguments = $this->arguments;
777
778
			if ( empty( $arguments ) ) {
779
				$arguments = $this->get_arguments();
780
			}
781
782
			if ( ! empty( $arguments ) ) {
783
				foreach ( $arguments as $argument ) {
784
					if ( isset( $argument['advanced'] ) && $argument['advanced'] ) {
785
						$show = true;
786
					}
787
				}
788
			}
789
790
			return $show;
791
		}
792
793
794
		/**
795
		 * Output the JS for building the dynamic Guntenberg block.
796
		 *
797
		 * @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.
798
		 * @return mixed
799
		 */
800
		public function block() {
801
			ob_start();
802
			?>
803
			<script>
804
				/**
805
				 * BLOCK: Basic
806
				 *
807
				 * Registering a basic block with Gutenberg.
808
				 * Simple block, renders and saves the same content without any interactivity.
809
				 *
810
				 * Styles:
811
				 *        editor.css — Editor styles for the block.
812
				 *        style.css  — Editor & Front end styles for the block.
813
				 */
814
				(function () {
815
					var __ = wp.i18n.__; // The __() for internationalization.
816
					var el = wp.element.createElement; // The wp.element.createElement() function to create elements.
817
					var editable = wp.blocks.Editable;
818
					var blocks = wp.blocks;
819
					var registerBlockType = wp.blocks.registerBlockType; // The registerBlockType() to register blocks.
820
					var is_fetching = false;
821
					var prev_attributes = [];
822
823
					/**
824
					 * Register Basic Block.
825
					 *
826
					 * Registers a new block provided a unique name and an object defining its
827
					 * behavior. Once registered, the block is made available as an option to any
828
					 * editor interface where blocks are implemented.
829
					 *
830
					 * @param  {string}   name     Block name.
831
					 * @param  {Object}   settings Block settings.
832
					 * @return {?WPBlock}          The block, if it has been successfully
833
					 *                             registered; otherwise `undefined`.
834
					 */
835
					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.
836
						title: '<?php echo $this->options['name'];?>', // Block title.
837
						description: '<?php echo esc_attr( $this->options['widget_ops']['description'] )?>', // Block title.
838
						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/.
839
						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.
840
						<?php if ( isset( $this->options['block-keywords'] ) ) {
841
						echo "keywords : " . $this->options['block-keywords'] . ",";
842
					}?>
843
844
						<?php
845
846
						$show_advanced = $this->block_show_advanced();
847
848
						$show_alignment = false;
849
850
						if ( ! empty( $this->arguments ) ) {
851
							echo "attributes : {";
852
853
							if ( $show_advanced ) {
854
								echo "show_advanced: {";
855
								echo "	type: 'boolean',";
856
								echo "  default: false,";
857
								echo "},";
858
							}
859
860
							// block wrap element
861
							if ( isset( $this->options['block-wrap'] ) ) { //@todo we should validate this?
862
								echo "block_wrap: {";
863
								echo "	type: 'string',";
864
								echo "  default: '" . esc_attr( $this->options['block-wrap'] ) . "',";
865
								echo "},";
866
							}
867
868
869
							foreach ( $this->arguments as $key => $args ) {
870
871
								// set if we should show alignment
872
								if ( $key == 'alignment' ) {
873
									$show_alignment = true;
874
								}
875
876
								$extra = '';
0 ignored issues
show
Unused Code introduced by
$extra is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
877
878
								if ( $args['type'] == 'checkbox' ) {
879
									$type    = 'boolean';
880
									$default = isset( $args['default'] ) && $args['default'] ? 'true' : 'false';
881
								} elseif ( $args['type'] == 'number' ) {
882
									$type    = 'number';
883
									$default = isset( $args['default'] ) ? "'" . $args['default'] . "'" : "''";
884
								} elseif ( $args['type'] == 'select' && ! empty( $args['multiple'] ) ) {
885
									$type = 'array';
886
									if ( is_array( $args['default'] ) ) {
887
										$default = isset( $args['default'] ) ? "['" . implode( "','", $args['default'] ) . "']" : "[]";
888 View Code Duplication
									} else {
889
										$default = isset( $args['default'] ) ? "'" . $args['default'] . "'" : "''";
890
									}
891
								} elseif ( $args['type'] == 'multiselect' ) {
892
									$type    = 'array';
893
									$default = isset( $args['default'] ) ? "'" . $args['default'] . "'" : "''";
894 View Code Duplication
								} else {
895
									$type    = 'string';
896
									$default = isset( $args['default'] ) ? "'" . $args['default'] . "'" : "''";
897
								}
898
								echo $key . " : {";
899
								echo "type : '$type',";
900
								echo "default : $default,";
901
								echo "},";
902
							}
903
904
							echo "content : {type : 'string',default: 'Please select the attributes in the block settings'},";
905
906
							echo "},";
907
908
						}
909
910
						?>
911
912
						// The "edit" property must be a valid function.
913
						edit: function (props) {
914
915
							var content = props.attributes.content;
916
917
							function onChangeContent() {
918
919
								if (!is_fetching && prev_attributes[props.id] != props.attributes) {
920
921
									//console.log(props);
922
923
									is_fetching = true;
924
									var data = {
925
										'action': 'super_duper_output_shortcode',
926
										'shortcode': '<?php echo $this->options['base_id'];?>',
927
										'attributes': props.attributes,
928
										'post_id': <?php global $post; if ( isset( $post->ID ) ) {
929
										echo $post->ID;
930
									}?>,
931
										'_ajax_nonce': '<?php echo wp_create_nonce( 'super_duper_output_shortcode' );?>'
932
									};
933
934
									jQuery.post(ajaxurl, data, function (response) {
935
										return response;
936
									}).then(function (env) {
937
938
										// if the content is empty then we place some placeholder text
939
										if (env == '') {
940
											env = "<div style='background:#0185ba33;padding: 10px;'>" + "<?php _e( 'Placeholder for: ' );?>" + props.name + "</div>";
941
										}
942
943
										props.setAttributes({content: env});
944
										is_fetching = false;
945
										prev_attributes[props.id] = props.attributes;
946
									});
947
948
949
								}
950
951
								return props.attributes.content;
952
953
							}
954
955
							return [
956
957
								el(wp.editor.BlockControls, {key: 'controls'},
958
959
									<?php if($show_alignment){?>
960
									el(
961
										wp.editor.AlignmentToolbar,
962
										{
963
											value: props.attributes.alignment,
964
											onChange: function (alignment) {
965
												props.setAttributes({alignment: alignment})
966
											}
967
										}
968
									)
969
									<?php }?>
970
971
								),
972
973
								el(wp.editor.InspectorControls, {key: 'inspector'},
974
975
									<?php
976
977
									if(! empty( $this->arguments )){
978
979
									if ( $show_advanced ) {
980
									?>
981
									el(
982
										wp.components.ToggleControl,
983
										{
984
											label: 'Show Advanced Settings?',
985
											checked: props.attributes.show_advanced,
986
											onChange: function (show_advanced) {
987
												props.setAttributes({show_advanced: !props.attributes.show_advanced})
988
											}
989
										}
990
									),
991
									<?php
992
993
									}
994
995
									foreach($this->arguments as $key => $args){
996
									$custom_attributes = ! empty( $args['custom_attributes'] ) ? $this->array_to_attributes( $args['custom_attributes'] ) : '';
997
									$options = '';
998
									$extra = '';
999
									$require = '';
0 ignored issues
show
Unused Code introduced by
$require is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1000
									$onchange = "props.setAttributes({ $key: $key } )";
1001
									$value = "props.attributes.$key";
1002
									$text_type = array( 'text', 'password', 'number', 'email', 'tel', 'url', 'color' );
1003
									if ( in_array( $args['type'], $text_type ) ) {
1004
										$type = 'TextControl';
1005
									} elseif ( $args['type'] == 'checkbox' ) {
1006
										$type = 'CheckboxControl';
1007
										$extra .= "checked: props.attributes.$key,";
1008
										$onchange = "props.setAttributes({ $key: ! props.attributes.$key } )";
1009
									} elseif ( $args['type'] == 'select' || $args['type'] == 'multiselect' ) {
1010
										$type = 'SelectControl';
1011
										if ( ! empty( $args['options'] ) ) {
1012
											$options .= "options  : [";
1013
											foreach ( $args['options'] as $option_val => $option_label ) {
1014
												$options .= "{ value : '" . esc_attr( $option_val ) . "',     label : '" . esc_attr( $option_label ) . "'     },";
1015
											}
1016
											$options .= "],";
1017
										}
1018
										if ( isset( $args['multiple'] ) && $args['multiple'] ) { //@todo multiselect does not work at the moment: https://github.com/WordPress/gutenberg/issues/5550
1019
											$extra .= ' multiple: true, ';
1020
											//$onchange = "props.setAttributes({ $key: ['edit'] } )";
1021
											//$value = "['edit', 'delete']";
1022
										}
1023
									} elseif ( $args['type'] == 'alignment' ) {
1024
										$type = 'AlignmentToolbar'; // @todo this does not seem to work but cant find a example
1025
									} else {
1026
										continue;// if we have not implemented the control then don't break the JS.
1027
									}
1028
1029
									// add show only if advanced
1030
									if ( ! empty( $args['advanced'] ) ) {
1031
										echo "props.attributes.show_advanced && ";
1032
									}
1033
									// add setting require if defined
1034
									if ( ! empty( $args['element_require'] ) ) {
1035
										echo $this->block_props_replace( $args['element_require'], true ) . " && ";
1036
									}
1037
									?>
1038
									el(
1039
										wp.components.<?php echo esc_attr( $type );?>,
1040
										{
1041
											label: '<?php echo esc_attr( $args['title'] );?>',
1042
											help: '<?php if ( isset( $args['desc'] ) ) {
1043
												echo esc_attr( $args['desc'] );
1044
											}?>',
1045
											value: <?php echo $value;?>,
1046
											<?php if ( $type == 'TextControl' && $args['type'] != 'text' ) {
1047
											echo "type: '" . esc_attr( $args['type'] ) . "',";
1048
										}?>
1049
											<?php if ( ! empty( $args['placeholder'] ) ) {
1050
											echo "placeholder: '" . esc_attr( $args['placeholder'] ) . "',";
1051
										}?>
1052
											<?php echo $options;?>
1053
											<?php echo $extra;?>
1054
											<?php echo $custom_attributes;?>
1055
											onChange: function ( <?php echo $key;?> ) {
1056
												<?php echo $onchange;?>
1057
											}
1058
										}
1059
									),
1060
									<?php
1061
									}
1062
									}
1063
									?>
1064
1065
								),
1066
1067
								<?php
1068
								// If the user sets block-output array then build it
1069
								if ( ! empty( $this->options['block-output'] ) ) {
1070
								$this->block_element( $this->options['block-output'] );
1071
							}else{
1072
								// if no block-output is set then we try and get the shortcode html output via ajax.
1073
								?>
1074
								el('div', {
1075
									dangerouslySetInnerHTML: {__html: onChangeContent()},
1076
									className: props.className,
1077
									style: {'min-height': '30px'}
1078
								})
1079
								<?php
1080
								}
1081
								?>
1082
							]; // end return
1083
						},
1084
1085
						// The "save" property must be specified and must be a valid function.
1086
						save: function (props) {
1087
1088
							//console.log(props);
1089
1090
1091
							var attr = props.attributes;
1092
							var align = '';
1093
1094
							// build the shortcode.
1095
							var content = "[<?php echo $this->options['base_id'];?>";
1096
							<?php
1097
1098
							if(! empty( $this->arguments )){
1099
							foreach($this->arguments as $key => $args){
1100
							?>
1101
							if (attr.hasOwnProperty("<?php echo esc_attr( $key );?>")) {
1102
								content += " <?php echo esc_attr( $key );?>='" + attr.<?php echo esc_attr( $key );?>+ "' ";
1103
							}
1104
							<?php
1105
							}
1106
							}
1107
1108
							?>
1109
							content += "]";
1110
1111
1112
							// @todo should we add inline style here or just css classes?
1113
							if (attr.alignment) {
1114
								if (attr.alignment == 'left') {
1115
									align = 'alignleft';
1116
								}
1117
								if (attr.alignment == 'center') {
1118
									align = 'aligncenter';
1119
								}
1120
								if (attr.alignment == 'right') {
1121
									align = 'alignright';
1122
								}
1123
							}
1124
1125
							//console.log(content);
1126
							var block_wrap = 'div';
1127
							if (attr.hasOwnProperty("block_wrap")) {
1128
								block_wrap = attr.block_wrap;
1129
							}
1130
							return el(block_wrap, {dangerouslySetInnerHTML: {__html: content}, className: align});
1131
1132
						}
1133
					});
1134
				})();
1135
			</script>
1136
			<?php
1137
			$output = ob_get_clean();
1138
1139
			/*
1140
			 * We only add the <script> tags for code highlighting, so we strip them from the output.
1141
			 */
1142
1143
			return str_replace( array(
1144
				'<script>',
1145
				'</script>'
1146
			), '', $output );
1147
		}
1148
1149
		/**
1150
		 * Convert an array of attributes to block string.
1151
		 *
1152
		 * @todo there is prob a faster way to do this, also we could add some validation here.
1153
		 *
1154
		 * @param $custom_attributes
1155
		 *
1156
		 * @return string
1157
		 */
1158
		public function array_to_attributes( $custom_attributes, $html = false ) {
1159
			$attributes = '';
1160
			if ( ! empty( $custom_attributes ) ) {
1161
1162
				if ( $html ) {
1163
					foreach ( $custom_attributes as $key => $val ) {
1164
						$attributes .= " $key='$val' ";
1165
					}
1166
				} else {
1167
					foreach ( $custom_attributes as $key => $val ) {
1168
						$attributes .= "'$key': '$val',";
1169
					}
1170
				}
1171
			}
1172
1173
			return $attributes;
1174
		}
1175
1176
		/**
1177
		 * A self looping function to create the output for JS block elements.
1178
		 *
1179
		 * This is what is output in the WP Editor visual view.
1180
		 *
1181
		 * @param $args
1182
		 */
1183
		public function block_element( $args ) {
1184
1185
1186
			if ( ! empty( $args ) ) {
1187
				foreach ( $args as $element => $new_args ) {
1188
1189
					if ( is_array( $new_args ) ) { // its an element
1190
1191
1192
						if ( isset( $new_args['element'] ) ) {
1193
1194 View Code Duplication
							if ( isset( $new_args['element_require'] ) ) {
1195
								echo str_replace( array(
1196
										"'+",
1197
										"+'"
1198
									), '', $this->block_props_replace( $new_args['element_require'] ) ) . " &&  ";
1199
								unset( $new_args['element_require'] );
1200
							}
1201
1202
							echo "\n el( '" . $new_args['element'] . "', {";
1203
1204
							// get the attributes
1205
							foreach ( $new_args as $new_key => $new_value ) {
1206
1207
1208
								if ( $new_key == 'element' || $new_key == 'content' || $new_key == 'element_require' || $new_key == 'element_repeat' || is_array( $new_value ) ) {
1209
									// do nothing
1210
								} else {
1211
									echo $this->block_element( array( $new_key => $new_value ) );
1212
								}
1213
							}
1214
1215
							echo "},";// end attributes
1216
1217
							// get the content
1218
							$first_item = 0;
1219
							foreach ( $new_args as $new_key => $new_value ) {
1220
								if ( $new_key === 'content' || is_array( $new_value ) ) {
1221
1222
									if ( $new_key === 'content' ) {
1223
										echo "'" . $this->block_props_replace( $new_value ) . "'";
1224
									}
1225
1226
									if ( is_array( $new_value ) ) {
1227
1228 View Code Duplication
										if ( isset( $new_value['element_require'] ) ) {
1229
											echo str_replace( array(
1230
													"'+",
1231
													"+'"
1232
												), '', $this->block_props_replace( $new_value['element_require'] ) ) . " &&  ";
1233
											unset( $new_value['element_require'] );
1234
										}
1235
1236
										if ( isset( $new_value['element_repeat'] ) ) {
1237
											$x = 1;
1238
											while ( $x <= absint( $new_value['element_repeat'] ) ) {
1239
												$this->block_element( array( '' => $new_value ) );
1240
												$x ++;
1241
											}
1242
										} else {
1243
											$this->block_element( array( '' => $new_value ) );
1244
										}
1245
									}
1246
									$first_item ++;
1247
								}
1248
							}
1249
1250
							echo ")";// end content
1251
1252
							echo ", \n";
1253
1254
						}
1255
					} else {
1256
1257
						if ( substr( $element, 0, 3 ) === "if_" ) {
1258
							echo str_replace( "if_", "", $element ) . ": " . $this->block_props_replace( $new_args, true ) . ",";
1259
						} elseif ( $element == 'style' ) {
1260
							echo $element . ": " . $this->block_props_replace( $new_args ) . ",";
1261
						} else {
1262
							echo $element . ": '" . $this->block_props_replace( $new_args ) . "',";
1263
						}
1264
1265
					}
1266
				}
1267
			}
1268
		}
1269
1270
		/**
1271
		 * Replace block attributes placeholders with the proper naming.
1272
		 *
1273
		 * @param $string
1274
		 *
1275
		 * @return mixed
1276
		 */
1277
		public function block_props_replace( $string, $no_wrap = false ) {
1278
1279
			if ( $no_wrap ) {
1280
				$string = str_replace( array( "[%", "%]" ), array( "props.attributes.", "" ), $string );
1281
			} else {
1282
				$string = str_replace( array( "[%", "%]" ), array( "'+props.attributes.", "+'" ), $string );
1283
			}
1284
1285
			return $string;
1286
		}
1287
1288
		/**
1289
		 * Outputs the content of the widget
1290
		 *
1291
		 * @param array $args
1292
		 * @param array $instance
1293
		 */
1294
		public function widget( $args, $instance ) {
1295
1296
			// get the filtered values
1297
			$argument_values = $this->argument_values( $instance );
1298
			$argument_values = $this->string_to_bool( $argument_values );
1299
			$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) (which targets 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...
1300
1301
			if ( $output ) {
1302
				// Before widget
1303
				$before_widget = $args['before_widget'];
1304
				$before_widget = apply_filters( 'wp_super_duper_before_widget', $before_widget, $args, $instance, $this );
1305
				$before_widget = apply_filters( 'wp_super_duper_before_widget_' . $this->base_id, $before_widget, $args, $instance, $this );
1306
1307
				// After widget
1308
				$after_widget = $args['after_widget'];
1309
				$after_widget = apply_filters( 'wp_super_duper_after_widget', $after_widget, $args, $instance, $this );
1310
				$after_widget = apply_filters( 'wp_super_duper_after_widget_' . $this->base_id, $after_widget, $args, $instance, $this );
1311
1312
				echo $before_widget;
1313
				// elementor strips the widget wrapping div so we check for and add it back if needed
1314
				if ( $this->is_elementor_widget_output() ) {
1315
					echo ! empty( $this->options['widget_ops']['classname'] ) ? "<span class='" . esc_attr( $this->options['widget_ops']['classname'] ) . "'>" : '';
1316
				}
1317
				echo $this->output_title( $args, $instance );
1318
				echo $output;
1319
				if ( $this->is_elementor_widget_output() ) {
1320
					echo ! empty( $this->options['widget_ops']['classname'] ) ? "</span>" : '';
1321
				}
1322
				echo $after_widget;
1323
			}
1324
		}
1325
1326
		/**
1327
		 * Tests if the current output is inside a elementor container.
1328
		 *
1329
		 * @since 1.0.4
1330
		 * @return bool
1331
		 */
1332
		public function is_elementor_widget_output() {
1333
			$result = false;
1334
			if ( defined( 'ELEMENTOR_VERSION' ) && isset( $this->number ) && $this->number == 'REPLACE_TO_ID' ) {
1335
				$result = true;
1336
			}
1337
1338
			return $result;
1339
		}
1340
1341
		/**
1342
		 * Tests if the current output is inside a elementor preview.
1343
		 *
1344
		 * @since 1.0.4
1345
		 * @return bool
1346
		 */
1347
		public function is_elementor_preview() {
1348
			$result = false;
1349
			if ( isset( $_REQUEST['elementor-preview'] ) || ( is_admin() && isset( $_REQUEST['action'] ) && $_REQUEST['action'] == 'elementor' ) ) {
1350
				$result = true;
1351
			}
1352
1353
			return $result;
1354
		}
1355
1356
		/**
1357
		 * Output the super title.
1358
		 *
1359
		 * @param $args
1360
		 * @param array $instance
1361
		 *
1362
		 * @return string
1363
		 */
1364
		public function output_title( $args, $instance = array() ) {
1365
			$output = '';
1366
			if ( ! empty( $instance['title'] ) ) {
1367
				/** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */
1368
				$title  = apply_filters( 'widget_title', $instance['title'], $instance, $this->id_base );
1369
				$output = $args['before_title'] . $title . $args['after_title'];
1370
			}
1371
1372
			return $output;
1373
		}
1374
1375
		/**
1376
		 * Outputs the options form inputs for the widget.
1377
		 *
1378
		 * @param array $instance The widget options.
1379
		 */
1380
		public function form( $instance ) {
1381
1382
			// set widget instance
1383
			$this->instance = $instance;
1384
1385
			// set it as a SD widget
1386
			echo $this->widget_advanced_toggle();
1387
1388
			echo "<p>" . esc_attr( $this->options['widget_ops']['description'] ) . "</p>";
1389
			$arguments = $this->get_arguments();
1390
1391
			if ( is_array( $arguments ) ) {
1392
				foreach ( $arguments as $key => $args ) {
1393
					$this->widget_inputs( $args, $instance );
1394
				}
1395
			}
1396
		}
1397
1398
		/**
1399
		 * Get the hidden input that when added makes the advanced button show on widget settings.
1400
		 *
1401
		 * @return string
1402
		 */
1403
		public function widget_advanced_toggle() {
1404
1405
			$output = '';
1406
			if ( $this->block_show_advanced() ) {
1407
				$val = 1;
1408
			} else {
1409
				$val = 0;
1410
			}
1411
1412
			$output .= "<input type='hidden'  class='sd-show-advanced' value='$val' />";
1413
1414
			return $output;
1415
		}
1416
1417
		/**
1418
		 * Convert require element.
1419
		 *
1420
		 * @since 1.0.0
1421
		 *
1422
		 * @param string $input Input element.
1423
		 *
1424
		 * @return string $output
1425
		 */
1426
		public function convert_element_require( $input ) {
1427
1428
			$input = str_replace( "'", '"', $input );// we only want double quotes
1429
1430
			$output = esc_attr( str_replace( array( "[%", "%]" ), array(
1431
				"jQuery(form).find('[data-argument=\"",
1432
				"\"]').find('input,select').val()"
1433
			), $input ) );
1434
1435
			return $output;
1436
		}
1437
1438
		/**
1439
		 * Builds the inputs for the widget options.
1440
		 *
1441
		 * @param $args
1442
		 * @param $instance
1443
		 */
1444
		public function widget_inputs( $args, $instance ) {
1445
1446
			$class             = "";
1447
			$element_require   = "";
1448
			$custom_attributes = "";
1449
1450
			// get value
1451
			if ( isset( $instance[ $args['name'] ] ) ) {
1452
				$value = $instance[ $args['name'] ];
1453
			} elseif ( ! isset( $instance[ $args['name'] ] ) && ! empty( $args['default'] ) ) {
1454
				$value = is_array( $args['default'] ) ? array_map( "esc_html", $args['default'] ) : esc_html( $args['default'] );
1455
			} else {
1456
				$value = '';
1457
			}
1458
1459
			// get placeholder
1460 View Code Duplication
			if ( ! empty( $args['placeholder'] ) ) {
1461
				$placeholder = "placeholder='" . esc_html( $args['placeholder'] ) . "'";
1462
			} else {
1463
				$placeholder = '';
1464
			}
1465
1466
			// get if advanced
1467
			if ( isset( $args['advanced'] ) && $args['advanced'] ) {
1468
				$class .= " sd-advanced-setting ";
1469
			}
1470
1471
			// element_require
1472
			if ( isset( $args['element_require'] ) && $args['element_require'] ) {
1473
				$element_require = $args['element_require'];
1474
			}
1475
1476
			// custom_attributes
1477
			if ( isset( $args['custom_attributes'] ) && $args['custom_attributes'] ) {
1478
				$custom_attributes = $this->array_to_attributes( $args['custom_attributes'], true );
1479
			}
1480
1481
			// before wrapper
1482
			?>
1483
			<p class="sd-argument <?php echo esc_attr( $class ); ?>"
1484
			   data-argument='<?php echo esc_attr( $args['name'] ); ?>'
1485
			   data-element_require='<?php if ( $element_require ) {
1486
				   echo $this->convert_element_require( $element_require );
1487
			   } ?>'
1488
			>
1489
				<?php
1490
1491
				switch ( $args['type'] ) {
1492
					//array('text','password','number','email','tel','url','color')
1493
					case "text":
1494
					case "password":
1495
					case "number":
1496
					case "email":
1497
					case "tel":
1498
					case "url":
1499 View Code Duplication
					case "color":
1500
						?>
1501
						<label
1502
							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>
1503
						<input <?php echo $placeholder; ?> class="widefat"
1504
							<?php echo $custom_attributes; ?>
1505
							                               id="<?php echo esc_attr( $this->get_field_id( $args['name'] ) ); ?>"
1506
							                               name="<?php echo esc_attr( $this->get_field_name( $args['name'] ) ); ?>"
1507
							                               type="<?php echo esc_attr( $args['type'] ); ?>"
1508
							                               value="<?php echo esc_attr( $value ); ?>">
1509
						<?php
1510
1511
						break;
1512
					case "select":
1513
						$multiple = isset( $args['multiple'] ) && $args['multiple'] ? true : false;
1514
						if ( $multiple ) {
1515
							if ( empty( $value ) ) {
1516
								$value = array();
1517
							}
1518
						}
1519
						?>
1520
						<label
1521
							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>
1522
						<select <?php echo $placeholder; ?> class="widefat"
1523
							<?php echo $custom_attributes; ?>
1524
							                                id="<?php echo esc_attr( $this->get_field_id( $args['name'] ) ); ?>"
1525
							                                name="<?php echo esc_attr( $this->get_field_name( $args['name'] ) );
1526
							                                if ( $multiple ) {
1527
								                                echo "[]";
1528
							                                } ?>"
1529
							<?php if ( $multiple ) {
1530
								echo "multiple";
1531
							} //@todo not implemented yet due to gutenberg not supporting it
1532
							?>
1533
						>
1534
							<?php
1535
1536
							if ( ! empty( $args['options'] ) ) {
1537
								foreach ( $args['options'] as $val => $label ) {
1538
									if ( $multiple ) {
1539
										$selected = in_array( $val, $value ) ? 'selected="selected"' : '';
1540
									} else {
1541
										$selected = selected( $value, $val, false );
1542
									}
1543
									echo "<option value='$val' " . $selected . ">$label</option>";
1544
								}
1545
							}
1546
							?>
1547
						</select>
1548
						<?php
1549
						break;
1550 View Code Duplication
					case "checkbox":
1551
						?>
1552
						<input <?php echo $placeholder; ?>
1553
							<?php checked( 1, $value, true ) ?>
1554
							<?php echo $custom_attributes; ?>
1555
							class="widefat" id="<?php echo esc_attr( $this->get_field_id( $args['name'] ) ); ?>"
1556
							name="<?php echo esc_attr( $this->get_field_name( $args['name'] ) ); ?>" type="checkbox"
1557
							value="1">
1558
						<label
1559
							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>
1560
						<?php
1561
						break;
1562
					case "hidden":
1563
						?>
1564
						<input id="<?php echo esc_attr( $this->get_field_id( $args['name'] ) ); ?>"
1565
						       name="<?php echo esc_attr( $this->get_field_name( $args['name'] ) ); ?>" type="hidden"
1566
						       value="<?php echo esc_attr( $value ); ?>">
1567
						<?php
1568
						break;
1569
					default:
1570
						echo "No input type found!"; // @todo we need to add more input types.
1571
				}
1572
1573
				// after wrapper
1574
				?>
1575
			</p>
1576
			<?php
1577
1578
		}
1579
1580
		/**
1581
		 * Get the widget input description html.
1582
		 *
1583
		 * @param $args
1584
		 *
1585
		 * @return string
1586
		 * @todo, need to make its own tooltip script
1587
		 */
1588
		public function widget_field_desc( $args ) {
1589
1590
			$description = '';
1591
			if ( isset( $args['desc'] ) && $args['desc'] ) {
1592
				if ( isset( $args['desc_tip'] ) && $args['desc_tip'] ) {
1593
					$description = $this->desc_tip( $args['desc'] );
1594
				} else {
1595
					$description = '<span class="description">' . wp_kses_post( $args['desc'] ) . '</span>';
1596
				}
1597
			}
1598
1599
			return $description;
1600
		}
1601
1602
		/**
1603
		 * Get the tool tip html.
1604
		 *
1605
		 * @param $tip
1606
		 * @param bool $allow_html
1607
		 *
1608
		 * @return string
1609
		 */
1610
		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...
1611
			if ( $allow_html ) {
1612
				$tip = $this->sanitize_tooltip( $tip );
1613
			} else {
1614
				$tip = esc_attr( $tip );
1615
			}
1616
1617
			return '<span class="gd-help-tip dashicons dashicons-editor-help" title="' . $tip . '"></span>';
1618
		}
1619
1620
		/**
1621
		 * Sanitize a string destined to be a tooltip.
1622
		 *
1623
		 * @param string $var
1624
		 *
1625
		 * @return string
1626
		 */
1627
		public function sanitize_tooltip( $var ) {
1628
			return htmlspecialchars( wp_kses( html_entity_decode( $var ), array(
1629
				'br'     => array(),
1630
				'em'     => array(),
1631
				'strong' => array(),
1632
				'small'  => array(),
1633
				'span'   => array(),
1634
				'ul'     => array(),
1635
				'li'     => array(),
1636
				'ol'     => array(),
1637
				'p'      => array(),
1638
			) ) );
1639
		}
1640
1641
		/**
1642
		 * Processing widget options on save
1643
		 *
1644
		 * @param array $new_instance The new options
1645
		 * @param array $old_instance The previous options
1646
		 *
1647
		 * @return array
1648
		 * @todo we should add some sanitation here.
1649
		 */
1650
		public function update( $new_instance, $old_instance ) {
1651
1652
			//save the widget
1653
			$instance = array_merge( (array) $old_instance, (array) $new_instance );
1654
1655
			// set widget instance
1656
			$this->instance = $instance;
1657
1658
			if ( empty( $this->arguments ) ) {
1659
				$this->get_arguments();
1660
			}
1661
1662
			// check for checkboxes
1663
			if ( ! empty( $this->arguments ) ) {
1664
				foreach ( $this->arguments as $argument ) {
1665
					if ( isset( $argument['type'] ) && $argument['type'] == 'checkbox' && ! isset( $new_instance[ $argument['name'] ] ) ) {
1666
						$instance[ $argument['name'] ] = '0';
1667
					}
1668
				}
1669
			}
1670
1671
			return $instance;
1672
		}
1673
1674
		/**
1675
		 * Checks if the current call is a ajax call to get the block content.
1676
		 *
1677
		 * This can be used in your widget to return different content as the block content.
1678
		 *
1679
		 * @since 1.0.3
1680
		 * @return bool
1681
		 */
1682
		public function is_block_content_call() {
1683
			$result = false;
1684
			if ( wp_doing_ajax() && isset( $_REQUEST['action'] ) && $_REQUEST['action'] == 'super_duper_output_shortcode' ) {
1685
				$result = true;
1686
			}
1687
1688
			return $result;
1689
		}
1690
1691
	}
1692
1693
}