Passed
Push — master ( 919089...f59267 )
by Stiofan
41s queued 11s
created

WP_Super_Duper::is_elementor_preview()   B

Complexity

Conditions 7
Paths 2

Size

Total Lines 8

Duplication

Lines 8
Ratio 100 %

Importance

Changes 0
Metric Value
cc 7
nc 2
nop 0
dl 8
loc 8
rs 8.8333
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
	 * @since 1.0.6 Some refactoring for page builders - CHANGED
21
	 * @since 1.0.7 Some refactoring for page builders - CHANGED
22
	 * @since 1.0.8 Some refactoring for page builders ( cornerstone builder now supported ) - CHANGED
23
	 * @since 1.0.9 Numbers saving as strings and not numbers which can cause block render issues on refresh - FIXED
24
	 * @since 1.0.10 Some refactoring for page builders ( Avia builder for Enfold theme now supported ) - CHANGED
25
	 * @ver 1.0.10
26
	 */
27
	class WP_Super_Duper extends WP_Widget {
28
29
		public $version = "1.0.10";
30
		public $block_code;
31
		public $options;
32
		public $base_id;
33
		public $arguments = array();
34
		public $instance = array();
35
		private $class_name;
36
37
		/**
38
		 * Take the array options and use them to build.
39
		 */
40
		public function __construct( $options ) {
41
			global $sd_widgets;
42
43
			$sd_widgets[ $options['base_id'] ] = array(
44
				'name'       => $options['name'],
45
				'class_name' => $options['class_name']
46
			);
47
			$this->base_id                     = $options['base_id'];
48
			// lets filter the options before we do anything
49
			$options       = apply_filters( "wp_super_duper_options", $options );
50
			$options       = apply_filters( "wp_super_duper_options_{$this->base_id}", $options );
51
			$options       = $this->add_name_from_key( $options );
52
			$this->options = $options;
53
54
			$this->base_id   = $options['base_id'];
55
			$this->arguments = isset( $options['arguments'] ) ? $options['arguments'] : array();
56
57
			// init parent
58
			parent::__construct( $options['base_id'], $options['name'], $options['widget_ops'] );
59
60
			if ( isset( $options['class_name'] ) ) {
61
				// register widget
62
				$this->class_name = $options['class_name'];
63
64
				// register shortcode
65
				$this->register_shortcode();
66
67
				// register block
68
				add_action( 'admin_enqueue_scripts', array( $this, 'register_block' ) );
69
			}
70
71
			// add the CSS and JS we need ONCE
72
			global $sd_widget_scripts;
73
74
			if ( ! $sd_widget_scripts ) {
75
				wp_add_inline_script( 'admin-widgets', $this->widget_js() );
76
				wp_add_inline_script( 'customize-controls', $this->widget_js() );
77
				wp_add_inline_style( 'widgets', $this->widget_css() );
78
79
				$sd_widget_scripts = true;
80
81
				// add shortcode insert button once
82
				add_action( 'media_buttons', array( $this, 'shortcode_insert_button' ) );
83
				if ( $this->is_preview() ) {
84
					add_action( 'wp_footer', array( $this, 'shortcode_insert_button_script' ) );
85
					// this makes the insert button work for elementor
86
					add_action( 'elementor/editor/after_enqueue_scripts', array(
87
						$this,
88
						'shortcode_insert_button_script'
89
					) ); // for elementor
90
				}
91
				// this makes the insert button work for cornerstone
92
				add_action( 'cornerstone_load_builder', array(
93
					$this,
94
					'shortcode_insert_button_script'
95
				) ); // for cornerstone builder (this is the preview)
96
97
				add_action( 'wp_ajax_super_duper_get_widget_settings', array( __CLASS__, 'get_widget_settings' ) );
98
				add_action( 'wp_ajax_super_duper_get_picker', array( __CLASS__, 'get_picker' ) );
99
100
				// add generator text to admin head
101
				add_action( 'admin_head', array( $this, 'generator' ) );
102
			}
103
104
			do_action( 'wp_super_duper_widget_init', $options, $this );
105
		}
106
107
		/**
108
		 * A function to ge the shortcode builder picker html.
109
		 *
110
		 * @param string $editor_id
111
		 *
112
		 * @return string
113
		 */
114
		public static function get_picker( $editor_id = '' ) {
115
116
			ob_start();
117
			if ( isset( $_POST['editor_id'] ) ) {
118
				$editor_id = esc_attr( $_POST['editor_id'] );
119
			} elseif ( isset( $_REQUEST['et_fb'] ) ) {
120
				$editor_id = 'main_content_content_vb_tiny_mce';
121
			}
122
123
			global $sd_widgets;
124
			?>
125
126
			<div class="sd-shortcode-left-wrap">
127
				<?php
128
				asort( $sd_widgets );
129
				if ( ! empty( $sd_widgets ) ) {
130
					echo '<select class="widefat" onchange="sd_get_shortcode_options(this);">';
131
					echo "<option>" . __( 'Select shortcode' ) . "</option>";
132
					foreach ( $sd_widgets as $shortcode => $class ) {
133
						echo "<option value='" . esc_attr( $shortcode ) . "'>" . esc_attr( $shortcode ) . " (" . esc_attr( $class['name'] ) . ")</option>";
134
					}
135
					echo "</select>";
136
137
				}
138
				?>
139
				<div class="sd-shortcode-settings"></div>
140
141
			</div>
142
143
			<div class="sd-shortcode-right-wrap">
144
				<textarea id='sd-shortcode-output' disabled></textarea>
145
				<div id='sd-shortcode-output-actions'>
146
					<?php if ( $editor_id != '' ) { ?>
147
						<button class="button sd-insert-shortcode-button"
148
						        onclick="sd_insert_shortcode(<?php if ( ! empty( $editor_id ) ) {
149
							        echo "'" . $editor_id . "'";
150
						        } ?>)"><?php _e( 'Insert shortcode' ); ?></button>
151
					<?php } ?>
152
					<button class="button"
153
					        onclick="sd_copy_to_clipboard()"><?php _e( 'Copy shortcode' ); ?></button>
154
				</div>
155
			</div>
156
			<?php
157
158
			$html = ob_get_clean();
159
160
			if ( wp_doing_ajax() ) {
161
				echo $html;
162
				$should_die = true;
163
164
				// some builder get the editor via ajax so we should not die on those ocasions
165
				$dont_die = array(
166
					'parent_tag',// WP Bakery
167
					'avia_request' // enfold
168
				);
169
170
				foreach ( $dont_die as $request ) {
171
					if ( isset( $_REQUEST[ $request ] ) ) {
172
						$should_die = false;
173
					}
174
				}
175
176
				if ( $should_die ) {
177
					wp_die();
178
				}
179
180
			} else {
181
				return $html;
182
			}
183
184
			return '';
185
186
		}
187
188
		/**
189
		 * Output the version in the admin header.
190
		 */
191
		public function generator() {
192
			echo '<meta name="generator" content="WP Super Duper v' . $this->version . '" />';
193
		}
194
195
		/**
196
		 * Get widget settings.
197
		 *
198
		 * @since 1.0.0
199
		 */
200
		public static function get_widget_settings() {
201
			global $sd_widgets;
202
203
			$shortcode = isset( $_REQUEST['shortcode'] ) && $_REQUEST['shortcode'] ? sanitize_title_with_dashes( $_REQUEST['shortcode'] ) : '';
204
			if ( ! $shortcode ) {
205
				wp_die();
206
			}
207
			$widget_args = isset( $sd_widgets[ $shortcode ] ) ? $sd_widgets[ $shortcode ] : '';
208
			if ( ! $widget_args ) {
209
				wp_die();
210
			}
211
			$class_name = isset( $widget_args['class_name'] ) && $widget_args['class_name'] ? $widget_args['class_name'] : '';
212
			if ( ! $class_name ) {
213
				wp_die();
214
			}
215
216
			// invoke an instance method
217
			$widget = new $class_name;
218
219
			ob_start();
220
			$widget->form( array() );
221
			$form = ob_get_clean();
222
			echo "<form id='$shortcode'>" . $form . "<div class=\"widget-control-save\"></div></form>";
223
			echo "<style>" . $widget->widget_css() . "</style>";
224
			echo "<script>" . $widget->widget_js() . "</script>";
225
			?>
226
			<?php
227
			wp_die();
228
		}
229
230
		/**
231
		 * Insert shortcode builder button to classic editor (not inside Gutenberg, not needed).
232
		 *
233
		 * @since 1.0.0
234
		 *
235
		 * @param string $editor_id Optional. Shortcode editor id. Default null.
236
		 * @param string $insert_shortcode_function Optional. Insert shotcode function. Default null.
237
		 */
238
		public static function shortcode_insert_button( $editor_id = '', $insert_shortcode_function = '' ) {
239
			global $sd_widgets, $shortcode_insert_button_once;
240
			if ( $shortcode_insert_button_once ) {
241
				return;
242
			}
243
			add_thickbox();
244
245
246
			/**
247
			 * Cornerstone makes us play dirty tricks :/
248
			 * 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.
249
			 */
250
			if ( function_exists( 'cornerstone_plugin_init' ) && ! is_admin() ) {
251
				echo '<span id="insert-media-button">';
252
			}
253
254
			echo self::shortcode_button( 'this', 'true' );
255
256
			// see opening note
257
			if ( function_exists( 'cornerstone_plugin_init' ) && ! is_admin() ) {
258
				echo '</span>'; // end #insert-media-button
259
			}
260
261
			self::shortcode_insert_button_script( $editor_id, $insert_shortcode_function );
262
			$shortcode_insert_button_once = true;
263
		}
264
265
		/**
266
		 * Gets the shortcode insert button html.
267
		 *
268
		 * @param string $id
269
		 * @param string $search_for_id
270
		 *
271
		 * @return mixed
272
		 */
273
		public static function shortcode_button( $id = '', $search_for_id = '' ) {
274
			ob_start();
275
			?>
276
			<span class="sd-lable-shortcode-inserter">
277
				<a onclick="sd_ajax_get_picker(<?php echo $id;
278
				if ( $search_for_id ) {
279
					echo "," . $search_for_id;
280
				} ?>);" href="#TB_inline?width=100%&height=550&inlineId=super-duper-content-ajaxed"
281
				   class="thickbox button super-duper-content-open" title="Add Shortcode">
282
					<span style="vertical-align: middle;line-height: 18px;font-size: 20px;"
283
					      class="dashicons dashicons-screenoptions"></span>
284
				</a>
285
				<div id="super-duper-content-ajaxed" style="display:none;">
286
					<span>Loading</span>
287
				</div>
288
			</span>
289
290
			<?php
291
			$html = ob_get_clean();
292
293
			// remove line breaks so we can use it in js
294
			return preg_replace( "/\r|\n/", "", trim( $html ) );
295
		}
296
297
		/**
298
		 * Makes SD work with the siteOrigin page builder.
299
		 *
300
		 * @since 1.0.6
301
		 * @return mixed
302
		 */
303 View Code Duplication
		public static function siteorigin_js() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
304
			ob_start();
305
			?>
306
			<script>
307
				/**
308
				 * Check a form to see what items shoudl be shown or hidden.
309
				 */
310
				function sd_so_show_hide(form) {
311
					jQuery(form).find(".sd-argument").each(function () {
312
313
						var $element_require = jQuery(this).data('element_require');
314
315
						if ($element_require) {
316
317
							$element_require = $element_require.replace("&#039;", "'"); // replace single quotes
318
							$element_require = $element_require.replace("&quot;", '"'); // replace double quotes
319
320
							if (eval($element_require)) {
321
								jQuery(this).removeClass('sd-require-hide');
322
							} else {
323
								jQuery(this).addClass('sd-require-hide');
324
							}
325
						}
326
					});
327
				}
328
329
				/**
330
				 * Toggle advanced settings visibility.
331
				 */
332
				function sd_so_toggle_advanced($this) {
333
					var form = jQuery($this).parents('form,.form,.so-content');
334
					form.find('.sd-advanced-setting').toggleClass('sd-adv-show');
335
					return false;// prevent form submit
336
				}
337
338
				/**
339
				 * Initialise a individual widget.
340
				 */
341
				function sd_so_init_widget($this, $selector) {
342
					if (!$selector) {
343
						$selector = 'form';
344
					}
345
					// only run once.
346
					if (jQuery($this).data('sd-widget-enabled')) {
347
						return;
348
					} else {
349
						jQuery($this).data('sd-widget-enabled', true);
350
					}
351
352
					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>';
353
					var form = jQuery($this).parents('' + $selector + '');
354
355
					if (jQuery($this).val() == '1' && jQuery(form).find('.sd-advanced-button').length == 0) {
356
						jQuery(form).append($button);
357
					}
358
359
					// show hide on form change
360
					jQuery(form).change(function () {
361
						sd_so_show_hide(form);
362
					});
363
364
					// show hide on load
365
					sd_so_show_hide(form);
366
				}
367
368
				jQuery(function () {
369
					jQuery(document).on('open_dialog', function (w, e) {
370
						setTimeout(function () {
371
							if (jQuery('.so-panels-dialog-wrapper:visible .so-content.panel-dialog .sd-show-advanced').length) {
372
								console.log('exists');
373
								if (jQuery('.so-panels-dialog-wrapper:visible .so-content.panel-dialog .sd-show-advanced').val() == '1') {
374
									console.log('true');
375
									sd_so_init_widget('.so-panels-dialog-wrapper:visible .so-content.panel-dialog .sd-show-advanced', 'div');
376
								}
377
							}
378
						}, 200);
379
					});
380
				});
381
			</script>
382
			<?php
383
			$output = ob_get_clean();
384
385
			/*
386
			 * We only add the <script> tags for code highlighting, so we strip them from the output.
387
			 */
388
389
			return str_replace( array(
390
				'<script>',
391
				'</script>'
392
			), '', $output );
393
		}
394
395
		/**
396
		 * Output the JS and CSS for the shortcode insert button.
397
		 *
398
		 * @since 1.0.6
399
		 *
400
		 * @param string $editor_id
401
		 * @param string $insert_shortcode_function
402
		 */
403
		public static function shortcode_insert_button_script( $editor_id = '', $insert_shortcode_function = '' ) {
404
			?>
405
			<style>
406
				.sd-shortcode-left-wrap {
407
					float: left;
408
					width: 60%;
409
				}
410
411
				.sd-shortcode-left-wrap .gd-help-tip {
412
					float: none;
413
				}
414
415
				.sd-shortcode-left-wrap .widefat {
416
					border-spacing: 0;
417
					width: 100%;
418
					clear: both;
419
					margin: 0;
420
					border: 1px solid #ddd;
421
					box-shadow: inset 0 1px 2px rgba(0, 0, 0, .07);
422
					background-color: #fff;
423
					color: #32373c;
424
					outline: 0;
425
					transition: 50ms border-color ease-in-out;
426
					padding: 3px 5px;
427
				}
428
429
				.sd-shortcode-left-wrap input[type=checkbox].widefat {
430
					border: 1px solid #b4b9be;
431
					background: #fff;
432
					color: #555;
433
					clear: none;
434
					cursor: pointer;
435
					display: inline-block;
436
					line-height: 0;
437
					height: 16px;
438
					margin: -4px 4px 0 0;
439
					margin-top: 0;
440
					outline: 0;
441
					padding: 0 !important;
442
					text-align: center;
443
					vertical-align: middle;
444
					width: 16px;
445
					min-width: 16px;
446
					-webkit-appearance: none;
447
					box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);
448
					transition: .05s border-color ease-in-out;
449
				}
450
451
				.sd-shortcode-left-wrap input[type=checkbox]:checked:before {
452
					content: "\f147";
453
					margin: -3px 0 0 -4px;
454
					color: #1e8cbe;
455
					float: left;
456
					display: inline-block;
457
					vertical-align: middle;
458
					width: 16px;
459
					font: normal 21px/1 dashicons;
460
					speak: none;
461
					-webkit-font-smoothing: antialiased;
462
					-moz-osx-font-smoothing: grayscale;
463
				}
464
465
				#sd-shortcode-output-actions button,
466
				.sd-advanced-button {
467
					color: #555;
468
					border-color: #ccc;
469
					background: #f7f7f7;
470
					box-shadow: 0 1px 0 #ccc;
471
					vertical-align: top;
472
					display: inline-block;
473
					text-decoration: none;
474
					font-size: 13px;
475
					line-height: 26px;
476
					height: 28px;
477
					margin: 0;
478
					padding: 0 10px 1px;
479
					cursor: pointer;
480
					border-width: 1px;
481
					border-style: solid;
482
					-webkit-appearance: none;
483
					border-radius: 3px;
484
					white-space: nowrap;
485
					box-sizing: border-box;
486
				}
487
488
				button.sd-advanced-button {
489
					background: #0073aa;
490
					border-color: #006799;
491
					box-shadow: inset 0 2px 0 #006799;
492
					vertical-align: top;
493
					color: #fff;
494
					text-decoration: none;
495
					text-shadow: 0 -1px 1px #006799, 1px 0 1px #006799, 0 1px 1px #006799, -1px 0 1px #006799;
496
					float: right;
497
					margin-right: 3px !important;
498
					font-size: 20px !important;
499
				}
500
501
				.sd-shortcode-right-wrap {
502
					float: right;
503
					width: 35%;
504
				}
505
506
				#sd-shortcode-output {
507
					background: rgba(255, 255, 255, .5);
508
					border-color: rgba(222, 222, 222, .75);
509
					box-shadow: inset 0 1px 2px rgba(0, 0, 0, .04);
510
					color: rgba(51, 51, 51, .5);
511
					overflow: auto;
512
					padding: 2px 6px;
513
					line-height: 1.4;
514
					resize: vertical;
515
				}
516
517
				#sd-shortcode-output {
518
					height: 250px;
519
					width: 100%;
520
				}
521
			</style>
522
			<?php
523
			if ( class_exists( 'SiteOrigin_Panels' ) ) {
524
				echo "<script>" . self::siteorigin_js() . "</script>";
525
			}
526
			?>
527
			<script>
528
				<?php
529
				if(! empty( $insert_shortcode_function )){
530
					echo $insert_shortcode_function;
531
				}else{
532
533
				/**
534
				 * Function for super duper insert shortcode.
535
				 *
536
				 * @since 1.0.0
537
				 */
538
				?>
539
				function sd_insert_shortcode($editor_id) {
540
					$shortcode = jQuery('#TB_ajaxContent #sd-shortcode-output').val();
541
					if ($shortcode) {
542
543
						if (!$editor_id) {
544
545
							<?php
546
							if ( isset( $_REQUEST['et_fb'] ) ) {
547
								echo '$editor_id = "#main_content_content_vb_tiny_mce";';
548
							} elseif ( isset( $_REQUEST['action'] ) && $_REQUEST['action'] == 'elementor' ) {
549
								echo '$editor_id = "#elementor-controls .wp-editor-container textarea";';
550
							} else {
551
								echo '$editor_id = "#wp-content-editor-container textarea";';
552
							}
553
							?>
554
						} else {
555
							$editor_id = '#' + $editor_id;
556
						}
557
558
						if (tinyMCE && tinyMCE.activeEditor && jQuery($editor_id).attr("aria-hidden") == "true") {
559
							tinyMCE.execCommand('mceInsertContent', false, $shortcode);
560
						} else {
561
							var $txt = jQuery($editor_id);
562
							var caretPos = $txt[0].selectionStart;
563
							var textAreaTxt = $txt.val();
564
							var txtToAdd = $shortcode;
565
							var textareaValue = textAreaTxt.substring(0, caretPos) + txtToAdd + textAreaTxt.substring(caretPos);
566
							$txt.focus().val(textareaValue).change().keydown().blur().keyup().keypress().trigger('input').trigger('change');
567
568
							// set Divi react input value
569
							var input = document.getElementById("main_content_content_vb_tiny_mce");
570
							if (input) {
571
								sd_setNativeValue(input, textareaValue);
572
							}
573
574
						}
575
						tb_remove();
576
					}
577
				}
578
579
				/*
580
				Set the value of elements controled via react.
581
				 */
582
				function sd_setNativeValue(element, value) {
583
					let lastValue = element.value;
584
					element.value = value;
585
					let event = new Event("input", {target: element, bubbles: true});
586
					// React 15
587
					event.simulated = true;
588
					// React 16
589
					let tracker = element._valueTracker;
590
					if (tracker) {
591
						tracker.setValue(lastValue);
592
					}
593
					element.dispatchEvent(event);
594
				}
595
				<?php }?>
596
597
				/*
598
				Copies the shortcode to the clipboard.
599
				 */
600
				function sd_copy_to_clipboard() {
601
					/* Get the text field */
602
					var copyText = document.querySelector("#TB_ajaxContent #sd-shortcode-output");
603
					//un-disable the field
604
					copyText.disabled = false;
605
					/* Select the text field */
606
					copyText.select();
607
					/* Copy the text inside the text field */
608
					document.execCommand("Copy");
609
					//re-disable the field
610
					copyText.disabled = true;
611
					/* Alert the copied text */
612
					alert("Copied the text: " + copyText.value);
613
				}
614
615
				/*
616
				Gets the shortcode options.
617
				 */
618
				function sd_get_shortcode_options($this) {
619
620
					$short_code = jQuery($this).val();
621
					if ($short_code) {
622
623
						var data = {
624
							'action': 'super_duper_get_widget_settings',
625
							'shortcode': $short_code,
626
							'attributes': 123,
627
							'post_id': 321,
628
							'_ajax_nonce': '<?php echo wp_create_nonce( 'super_duper_output_shortcode' );?>'
629
						};
630
631
						if (typeof ajaxurl === 'undefined') {
632
							var ajaxurl = "<?php echo admin_url( 'admin-ajax.php' );?>";
633
						}
634
635
						jQuery.post(ajaxurl, data, function (response) {
636
							jQuery('#TB_ajaxContent .sd-shortcode-settings').html(response);
637
638
							jQuery('#' + $short_code).on('change', 'select', function () {
639
								sd_build_shortcode($short_code);
640
							}); // take care of select tags
641
642
							jQuery('#' + $short_code).on('change keypress keyup', 'input', function () {
643
								sd_build_shortcode($short_code);
644
							});
645
646
							sd_build_shortcode($short_code);
647
648
							// resize the window to fit
649
							setTimeout(function () {
650
								jQuery('#TB_ajaxContent').css('width', 'auto').css('height', '75vh');
651
							}, 200);
652
653
654
							return response;
655
						});
656
					}
657
658
				}
659
660
				/*
661
				Builds and inserts the shortcode into the viewer.
662
				 */
663
				function sd_build_shortcode($id) {
664
665
					var multiSelects = {};
666
					var multiSelectsRemove = [];
667
668
					$output = "[" + $id;
669
670
					$form_data = jQuery("#" + $id).serializeArray();
671
672
					// run checks for multiselects
673
					jQuery.each($form_data, function (index, element) {
674
						if (element && element.value) {
675
							$field_name = element.name.substr(element.name.indexOf("][") + 2);
676
							$field_name = $field_name.replace("]", "");
677
							// check if its a multiple
678
							if ($field_name.includes("[]")) {
679
								multiSelectsRemove[multiSelectsRemove.length] = index;
680
								$field_name = $field_name.replace("[]", "");
681
								if ($field_name in multiSelects) {
682
									multiSelects[$field_name] = multiSelects[$field_name] + "," + element.value;
683
								} else {
684
									multiSelects[$field_name] = element.value;
685
								}
686
							}
687
						}
688
					});
689
690
					// fix multiselects if any are found
691
					if (multiSelectsRemove.length) {
692
693
						// remove all multiselects
694
						multiSelectsRemove.reverse();
695
						multiSelectsRemove.forEach(function (index) {
696
							$form_data.splice(index, 1);
697
						});
698
699
						$ms_arr = [];
700
						// add multiselets back
701
						jQuery.each(multiSelects, function (index, value) {
702
							$ms_arr[$ms_arr.length] = {"name": "[][" + index + "]", "value": value};
703
						});
704
						$form_data = $form_data.concat($ms_arr);
705
					}
706
707
708
					if ($form_data) {
709
						$form_data.forEach(function (element) {
710
711
							if (element.value) {
712
								$field_name = element.name.substr(element.name.indexOf("][") + 2);
713
								$field_name = $field_name.replace("]", "");
714
								$output = $output + " " + $field_name + '="' + element.value + '"';
715
							}
716
717
						});
718
					}
719
					$output = $output + "]";
720
					jQuery('#TB_ajaxContent #sd-shortcode-output').html($output);
721
				}
722
723
724
				/*
725
				Delay the init of the textareas for 1 second.
726
				 */
727
				(function () {
728
					setTimeout(function () {
729
						sd_init_textareas();
730
					}, 1000);
731
				})();
732
733
				/*
734
				Init the textareas to be able to show the shortcode builder button.
735
				 */
736
				function sd_init_textareas() {
737
738
					// General textareas
739
					jQuery(document).on('focus', 'textarea', function () {
740
741
						if (jQuery(this).hasClass('wp-editor-area')) {
742
							// insert the shortcode button to the textarea lable if not there already
743
							if (!jQuery(this).parent().find('.sd-lable-shortcode-inserter').length) {
744
								jQuery(this).parent().find('.quicktags-toolbar').append(sd_shortcode_button(jQuery(this).attr('id')));
745
							}
746
						} else {
747
							// insert the shortcode button to the textarea lable if not there already
748
							if (!jQuery("label[for='" + jQuery(this).attr('id') + "']").find('.sd-lable-shortcode-inserter').length) {
749
								jQuery("label[for='" + jQuery(this).attr('id') + "']").append(sd_shortcode_button(jQuery(this).attr('id')));
750
							}
751
						}
752
					});
753
754
					// The below tries to add the shorcode builder button to the builders own raw/shortcode sections.
755
756
					// DIVI
757
					jQuery(document).on('focusin', '.et-fb-codemirror', function () {
758
						// insert the shortcode button to the textarea lable if not there already
759
						if (!jQuery(this).closest('.et-fb-form__group').find('.sd-lable-shortcode-inserter').length) {
760
							jQuery(this).closest('.et-fb-form__group').find('.et-fb-form__label-text').append(sd_shortcode_button());
761
						}
762
					});
763
764
					// Beaver
765
					jQuery(document).on('focusin', '.fl-code-field', function () {
766
						// insert the shortcode button to the textarea lable if not there already
767
						if (!jQuery(this).closest('.fl-field-control-wrapper').find('.sd-lable-shortcode-inserter').length) {
768
							jQuery(this).closest('.fl-field-control-wrapper').prepend(sd_shortcode_button());
769
						}
770
					});
771
772
					// Fushion builder (avada)
773
					jQuery(document).on('focusin', '.CodeMirror.cm-s-default', function () {
774
						// insert the shortcode button to the textarea lable if not there already
775
						if (!jQuery(this).parent().find('.sd-lable-shortcode-inserter').length) {
776
							jQuery(sd_shortcode_button()).insertBefore(this);
777
						}
778
					});
779
780
					// Avia builder (enfold)
781
					jQuery(document).on('focusin', '#aviaTBcontent', function () {
782
						// insert the shortcode button to the textarea lable if not there already
783
						if (!jQuery(this).parent().parent().find('.avia-name-description ').find('.sd-lable-shortcode-inserter').length) {
784
							jQuery(this).parent().parent().find('.avia-name-description strong').append(sd_shortcode_button(jQuery(this).attr('id')));
785
						}
786
					});
787
788
					// Cornerstone
789
					jQuery(document).on('focusin', '.cs-control.cs-control-textarea', function () {
790
						// insert the shortcode button to the textarea lable if not there already
791
						if (!jQuery(this).find('.cs-control-header label').find('.sd-lable-shortcode-inserter').length) {
792
							jQuery(this).find('.cs-control-header label').append(sd_shortcode_button());
793
						}
794
					});
795
796
					// WP Bakery, code editor does not render shortcodes.
797
//					jQuery(document).on('focusin', '.wpb-textarea_raw_html', function () {
798
//						// insert the shortcode button to the textarea lable if not there already
799
//						if(!jQuery(this).parent().parent().find('.wpb_element_label').find('.sd-lable-shortcode-inserter').length){
800
//							jQuery(this).parent().parent().find('.wpb_element_label').append(sd_shortcode_button());
801
//						}
802
//					});
803
804
				}
805
806
				/**
807
				 * Gets the html for the picker via ajax and updates it on the fly.
808
				 *
809
				 * @param $id
810
				 * @param $search
811
				 */
812
				function sd_ajax_get_picker($id, $search) {
813
					if ($search) {
814
						$this = $id;
815
						$id = jQuery($this).closest('.wp-editor-wrap').find('.wp-editor-container textarea').attr('id');
816
					}
817
818
					var data = {
819
						'action': 'super_duper_get_picker',
820
						'editor_id': $id,
821
						'_ajax_nonce': '<?php echo wp_create_nonce( 'super_duper_picker' );?>'
822
					};
823
824
					if (!ajaxurl) {
825
						var ajaxurl = "<?php echo admin_url( 'admin-ajax.php' ); ?>";
826
					}
827
828
					jQuery.post(ajaxurl, data, function (response) {
829
						jQuery('#TB_ajaxContent').html(response);
830
						//return response;
831
					}).then(function (env) {
832
						jQuery('body').on('thickbox:removed', function () {
833
							jQuery('#super-duper-content-ajaxed').html('');
834
						});
835
					});
836
				}
837
838
				/**
839
				 * Get the html for the shortcode inserter button depending on if a textarea id is available.
840
				 *
841
				 * @param $id string The textarea id.
842
				 * @returns {string}
843
				 */
844
				function sd_shortcode_button($id) {
845
					if ($id) {
846
						return '<?php echo self::shortcode_button( "\\''+\$id+'\\'" );?>';
847
					} else {
848
						return '<?php echo self::shortcode_button();?>';
849
					}
850
				}
851
852
			</script>
853
854
			<?php
855
		}
856
857
		/**
858
		 * Gets some CSS for the widgets screen.
859
		 *
860
		 * @return mixed
861
		 */
862 View Code Duplication
		public function widget_css() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
863
			ob_start();
864
			?>
865
			<style>
866
				.sd-advanced-setting {
867
					display: none;
868
				}
869
870
				.sd-advanced-setting.sd-adv-show {
871
					display: block;
872
				}
873
874
				.sd-argument.sd-require-hide,
875
				.sd-advanced-setting.sd-require-hide {
876
					display: none;
877
				}
878
879
				button.sd-advanced-button {
880
					margin-right: 3px !important;
881
					font-size: 20px !important;
882
				}
883
			</style>
884
			<?php
885
			$output = ob_get_clean();
886
887
			/*
888
			 * We only add the <script> tags for code highlighting, so we strip them from the output.
889
			 */
890
891
			return str_replace( array(
892
				'<style>',
893
				'</style>'
894
			), '', $output );
895
		}
896
897
		/**
898
		 * Gets some JS for the widgets screen.
899
		 *
900
		 * @return mixed
901
		 */
902 View Code Duplication
		public function widget_js() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
903
			ob_start();
904
			?>
905
			<script>
906
907
				/**
908
				 * Toggle advanced settings visibility.
909
				 */
910
				function sd_toggle_advanced($this) {
911
					var form = jQuery($this).parents('form,.form');
912
					form.find('.sd-advanced-setting').toggleClass('sd-adv-show');
913
					return false;// prevent form submit
914
				}
915
916
				/**
917
				 * Check a form to see what items shoudl be shown or hidden.
918
				 */
919
				function sd_show_hide(form) {
920
					console.log('show/hide');
921
					jQuery(form).find(".sd-argument").each(function () {
922
923
						var $element_require = jQuery(this).data('element_require');
924
925
						if ($element_require) {
926
927
							$element_require = $element_require.replace("&#039;", "'"); // replace single quotes
928
							$element_require = $element_require.replace("&quot;", '"'); // replace double quotes
929
930
							if (eval($element_require)) {
931
								jQuery(this).removeClass('sd-require-hide');
932
							} else {
933
								jQuery(this).addClass('sd-require-hide');
934
							}
935
						}
936
					});
937
				}
938
939
				/**
940
				 * Initialise widgets from the widgets screen.
941
				 */
942
				function sd_init_widgets($selector) {
943
					jQuery(".sd-show-advanced").each(function (index) {
944
						sd_init_widget(this, $selector);
945
					});
946
				}
947
948
				/**
949
				 * Initialise a individual widget.
950
				 */
951
				function sd_init_widget($this, $selector) {
952
					console.log($selector);
953
954
					if (!$selector) {
955
						$selector = 'form';
956
					}
957
					// only run once.
958
					if (jQuery($this).data('sd-widget-enabled')) {
959
						return;
960
					} else {
961
						jQuery($this).data('sd-widget-enabled', true);
962
					}
963
964
					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>';
965
					var form = jQuery($this).parents('' + $selector + '');
966
967
					if (jQuery($this).val() == '1' && jQuery(form).find('.sd-advanced-button').length == 0) {
968
						console.log('add advanced button');
969
970
						jQuery(form).find('.widget-control-save').after($button);
971
					} else {
972
						console.log('no advanced button');
973
						console.log(jQuery($this).val());
974
						console.log(jQuery(form).find('.sd-advanced-button').length);
975
976
					}
977
978
					// show hide on form change
979
					jQuery(form).change(function () {
980
						sd_show_hide(form);
981
					});
982
983
					// show hide on load
984
					sd_show_hide(form);
985
				}
986
987
				/**
988
				 * Init a customizer widget.
989
				 */
990
				function sd_init_customizer_widget(section) {
991
					if (section.expanded) {
992
						section.expanded.bind(function (isExpanding) {
993
							if (isExpanding) {
994
								// is it a SD widget?
995
								if (jQuery(section.container).find('.sd-show-advanced').length) {
996
									// init the widget
997
									sd_init_widget(jQuery(section.container).find('.sd-show-advanced'), ".form");
998
								}
999
							}
1000
						});
1001
					}
1002
				}
1003
1004
				/**
1005
				 * If on widgets screen.
1006
				 */
1007
				jQuery(function () {
1008
					// if not in customizer.
1009
					if (!wp.customize) {
1010
						sd_init_widgets("form");
1011
					}
1012
1013
					// init on widget added
1014
					jQuery(document).on('widget-added', function (e, widget) {
1015
						console.log('widget added');
1016
						// is it a SD widget?
1017
						if (jQuery(widget).find('.sd-show-advanced').length) {
1018
							// init the widget
1019
							sd_init_widget(jQuery(widget).find('.sd-show-advanced'), "form");
1020
						}
1021
					});
1022
1023
					// inint on widget updated
1024
					jQuery(document).on('widget-updated', function (e, widget) {
1025
						console.log('widget updated');
1026
1027
						// is it a SD widget?
1028
						if (jQuery(widget).find('.sd-show-advanced').length) {
1029
							// init the widget
1030
							sd_init_widget(jQuery(widget).find('.sd-show-advanced'), "form");
1031
						}
1032
					});
1033
1034
				});
1035
1036
1037
				/**
1038
				 * We need to run this before jQuery is ready
1039
				 */
1040
				if (wp.customize) {
1041
					wp.customize.bind('ready', function () {
1042
1043
						// init widgets on load
1044
						wp.customize.control.each(function (section) {
1045
							sd_init_customizer_widget(section);
1046
						});
1047
1048
						// init widgets on add
1049
						wp.customize.control.bind('add', function (section) {
1050
							sd_init_customizer_widget(section);
1051
						});
1052
1053
					});
1054
1055
				}
1056
				<?php do_action( 'wp_super_duper_widget_js', $this ); ?>
1057
			</script>
1058
			<?php
1059
			$output = ob_get_clean();
1060
1061
			/*
1062
			 * We only add the <script> tags for code highlighting, so we strip them from the output.
1063
			 */
1064
1065
			return str_replace( array(
1066
				'<script>',
1067
				'</script>'
1068
			), '', $output );
1069
		}
1070
1071
1072
		/**
1073
		 * Set the name from the argument key.
1074
		 *
1075
		 * @param $options
1076
		 *
1077
		 * @return mixed
1078
		 */
1079
		private function add_name_from_key( $options, $arguments = false ) {
1080
			if ( ! empty( $options['arguments'] ) ) {
1081
				foreach ( $options['arguments'] as $key => $val ) {
1082
					$options['arguments'][ $key ]['name'] = $key;
1083
				}
1084
			} elseif ( $arguments && is_array( $options ) && ! empty( $options ) ) {
1085
				foreach ( $options as $key => $val ) {
1086
					$options[ $key ]['name'] = $key;
1087
				}
1088
			}
1089
1090
			return $options;
1091
		}
1092
1093
		/**
1094
		 * Register the parent shortcode.
1095
		 *
1096
		 * @since 1.0.0
1097
		 */
1098
		public function register_shortcode() {
1099
			add_shortcode( $this->base_id, array( $this, 'shortcode_output' ) );
1100
			add_action( 'wp_ajax_super_duper_output_shortcode', array( __CLASS__, 'render_shortcode' ) );
1101
		}
1102
1103
		/**
1104
		 * Render the shortcode via ajax so we can return it to Gutenberg.
1105
		 *
1106
		 * @since 1.0.0
1107
		 */
1108
		public static function render_shortcode() {
1109
1110
			check_ajax_referer( 'super_duper_output_shortcode', '_ajax_nonce', true );
1111
			if ( ! current_user_can( 'manage_options' ) ) {
1112
				wp_die();
1113
			}
1114
1115
			// we might need the $post value here so lets set it.
1116
			if ( isset( $_POST['post_id'] ) && $_POST['post_id'] ) {
1117
				$post_obj = get_post( absint( $_POST['post_id'] ) );
1118
				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...
1119
					global $post;
1120
					$post = $post_obj;
1121
				}
1122
			}
1123
1124
			if ( isset( $_POST['shortcode'] ) && $_POST['shortcode'] ) {
1125
				$shortcode_name   = sanitize_title_with_dashes( $_POST['shortcode'] );
1126
				$attributes_array = isset( $_POST['attributes'] ) && $_POST['attributes'] ? $_POST['attributes'] : array();
1127
				$attributes       = '';
1128
				if ( ! empty( $attributes_array ) ) {
1129
					foreach ( $attributes_array as $key => $value ) {
1130
						$attributes .= " " . sanitize_title_with_dashes( $key ) . "='" . wp_slash( $value ) . "' ";
1131
					}
1132
				}
1133
1134
				$shortcode = "[" . $shortcode_name . " " . $attributes . "]";
1135
1136
				echo do_shortcode( $shortcode );
1137
1138
			}
1139
			wp_die();
1140
		}
1141
1142
		/**
1143
		 * Output the shortcode.
1144
		 *
1145
		 * @param array $args
1146
		 * @param string $content
1147
		 *
1148
		 * @return string
1149
		 */
1150
		public function shortcode_output( $args = array(), $content = '' ) {
1151
			$args = self::argument_values( $args );
1152
1153
			// add extra argument so we know its a output to gutenberg
1154
			//$args
1155
			$args = $this->string_to_bool( $args );
1156
1157
1158
			$calss = isset( $this->options['widget_ops']['classname'] ) ? esc_attr( $this->options['widget_ops']['classname'] ) : '';
1159
1160
			$calss = apply_filters( 'wp_super_duper_div_classname', $calss, $args, $this );
1161
			$calss = apply_filters( 'wp_super_duper_div_classname_' . $this->base_id, $calss, $args, $this );
1162
1163
			$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...
1164
			$attrs = apply_filters( 'wp_super_duper_div_attrs_' . $this->base_id, '', $args, $this );
1165
1166
			$shortcode_args = array();
1167
			$output         = '';
1168
			$no_wrap        = isset( $this->options['no_wrap'] ) && $this->options['no_wrap'] ? true : false;
1169
			$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...
1170
			if ( $main_content && ! $no_wrap ) {
1171
				// wrap the shortcode in a dive with the same class as the widget
1172
				$output .= '<div class="' . $calss . '" ' . $attrs . '>';
1173
				if ( ! empty( $args['title'] ) ) {
1174
					// if its a shortcode and there is a title try to grab the title wrappers
1175
					$shortcode_args = array( 'before_title' => '', 'after_title' => '' );
1176
					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...
1177
						global $wp_registered_sidebars;
1178
						if ( ! empty( $wp_registered_sidebars ) ) {
1179
							foreach ( $wp_registered_sidebars as $sidebar ) {
1180
								if ( ! empty( $sidebar['before_title'] ) ) {
1181
									$shortcode_args['before_title'] = $sidebar['before_title'];
1182
									$shortcode_args['after_title']  = $sidebar['after_title'];
1183
									break;
1184
								}
1185
							}
1186
						}
1187
					}
1188
					$output .= $this->output_title( $shortcode_args, $args );
1189
				}
1190
				$output .= $main_content;
1191
				$output .= '</div>';
1192
			} elseif ( $main_content && $no_wrap ) {
1193
				$output .= $main_content;
1194
			}
1195
1196
			// if preview show a placeholder if empty
1197 View Code Duplication
			if ( $this->is_preview() && $output == '' ) {
1198
				$output = $this->preview_placeholder_text( "[{" . $this->base_id . "}]" );
1199
			}
1200
1201
			return $output;
1202
		}
1203
1204
		/**
1205
		 * Placeholder text to show if output is empty and we are on a preview/builder page.
1206
		 *
1207
		 * @param string $name
1208
		 *
1209
		 * @return string
1210
		 */
1211
		public function preview_placeholder_text( $name = '' ) {
1212
			return "<div style='background:#0185ba33;padding: 10px;border: 4px #ccc dashed;'>" . sprintf( __( 'Placeholder for: %s' ), $name ) . "</div>";
1213
		}
1214
1215
		/**
1216
		 * Sometimes booleans values can be turned to strings, so we fix that.
1217
		 *
1218
		 * @param $options
1219
		 *
1220
		 * @return mixed
1221
		 */
1222
		public function string_to_bool( $options ) {
1223
			// convert bool strings to booleans
1224
			foreach ( $options as $key => $val ) {
1225
				if ( $val == 'false' ) {
1226
					$options[ $key ] = false;
1227
				} elseif ( $val == 'true' ) {
1228
					$options[ $key ] = true;
1229
				}
1230
			}
1231
1232
			return $options;
1233
		}
1234
1235
		/**
1236
		 * Get the argument values that are also filterable.
1237
		 *
1238
		 * @param $instance
1239
		 *
1240
		 * @return array
1241
		 */
1242
		public function argument_values( $instance ) {
1243
			$argument_values = array();
1244
1245
			// set widget instance
1246
			$this->instance = $instance;
1247
1248
			if ( empty( $this->arguments ) ) {
1249
				$this->arguments = $this->get_arguments();
1250
			}
1251
1252
			if ( ! empty( $this->arguments ) ) {
1253
				foreach ( $this->arguments as $key => $args ) {
1254
					// set the input name from the key
1255
					$args['name'] = $key;
1256
					//
1257
					$argument_values[ $key ] = isset( $instance[ $key ] ) ? $instance[ $key ] : '';
1258
					if ( $argument_values[ $key ] == '' && isset( $args['default'] ) ) {
1259
						$argument_values[ $key ] = $args['default'];
1260
					}
1261
				}
1262
			}
1263
1264
			return $argument_values;
1265
		}
1266
1267
		/**
1268
		 * Set arguments in super duper.
1269
		 *
1270
		 * @since 1.0.0
1271
		 *
1272
		 * @return array Set arguments.
1273
		 */
1274
		public function set_arguments() {
1275
			return $this->arguments;
1276
		}
1277
1278
		/**
1279
		 * Get arguments in super duper.
1280
		 *
1281
		 * @since 1.0.0
1282
		 *
1283
		 * @return array Get arguments.
1284
		 */
1285
		public function get_arguments() {
1286
			if ( empty( $this->arguments ) ) {
1287
				$this->arguments = $this->set_arguments();
1288
			}
1289
1290
			$this->arguments = apply_filters( 'wp_super_duper_arguments', $this->arguments, $this->options, $this->instance );
1291
			$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...
1292
1293
			return $this->arguments;
1294
		}
1295
1296
		/**
1297
		 * This is the main output class for all 3 items, widget, shortcode and block, it is extended in the calling class.
1298
		 *
1299
		 * @param array $args
1300
		 * @param array $widget_args
1301
		 * @param string $content
1302
		 */
1303
		public function output( $args = array(), $widget_args = array(), $content = '' ) {
1304
1305
		}
1306
1307
		/**
1308
		 * Add the dynamic block code inline when the wp-block in enqueued.
1309
		 */
1310
		public function register_block() {
1311
			wp_add_inline_script( 'wp-blocks', $this->block() );
1312
			if ( class_exists( 'SiteOrigin_Panels' ) ) {
1313
1314
				wp_add_inline_script( 'wp-blocks', $this->siteorigin_js() );
1315
1316
			}
1317
		}
1318
1319
		/**
1320
		 * Check if we need to show advanced options.
1321
		 *
1322
		 * @return bool
1323
		 */
1324
		public function block_show_advanced() {
1325
1326
			$show      = false;
1327
			$arguments = $this->arguments;
1328
1329
			if ( empty( $arguments ) ) {
1330
				$arguments = $this->get_arguments();
1331
			}
1332
1333
			if ( ! empty( $arguments ) ) {
1334
				foreach ( $arguments as $argument ) {
1335
					if ( isset( $argument['advanced'] ) && $argument['advanced'] ) {
1336
						$show = true;
1337
					}
1338
				}
1339
			}
1340
1341
			return $show;
1342
		}
1343
1344
1345
		/**
1346
		 * Output the JS for building the dynamic Guntenberg block.
1347
		 *
1348
		 * @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.
1349
		 * @since 1.0.9 Save numbers as numbers and not strings.
1350
		 * @return mixed
1351
		 */
1352
		public function block() {
1353
			ob_start();
1354
			?>
1355
			<script>
1356
				/**
1357
				 * BLOCK: Basic
1358
				 *
1359
				 * Registering a basic block with Gutenberg.
1360
				 * Simple block, renders and saves the same content without any interactivity.
1361
				 *
1362
				 * Styles:
1363
				 *        editor.css — Editor styles for the block.
1364
				 *        style.css  — Editor & Front end styles for the block.
1365
				 */
1366
				(function () {
1367
					var __ = wp.i18n.__; // The __() for internationalization.
1368
					var el = wp.element.createElement; // The wp.element.createElement() function to create elements.
1369
					var editable = wp.blocks.Editable;
1370
					var blocks = wp.blocks;
1371
					var registerBlockType = wp.blocks.registerBlockType; // The registerBlockType() to register blocks.
1372
					var is_fetching = false;
1373
					var prev_attributes = [];
1374
1375
					/**
1376
					 * Register Basic Block.
1377
					 *
1378
					 * Registers a new block provided a unique name and an object defining its
1379
					 * behavior. Once registered, the block is made available as an option to any
1380
					 * editor interface where blocks are implemented.
1381
					 *
1382
					 * @param  {string}   name     Block name.
1383
					 * @param  {Object}   settings Block settings.
1384
					 * @return {?WPBlock}          The block, if it has been successfully
1385
					 *                             registered; otherwise `undefined`.
1386
					 */
1387
					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.
1388
						title: '<?php echo $this->options['name'];?>', // Block title.
1389
						description: '<?php echo esc_attr( $this->options['widget_ops']['description'] )?>', // Block title.
1390
						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/.
1391
						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.
1392
						<?php if ( isset( $this->options['block-keywords'] ) ) {
1393
						echo "keywords : " . $this->options['block-keywords'] . ",";
1394
					}?>
1395
1396
						<?php
1397
1398
						$show_advanced = $this->block_show_advanced();
1399
1400
						$show_alignment = false;
1401
1402
						if ( ! empty( $this->arguments ) ) {
1403
							echo "attributes : {";
1404
1405
							if ( $show_advanced ) {
1406
								echo "show_advanced: {";
1407
								echo "	type: 'boolean',";
1408
								echo "  default: false,";
1409
								echo "},";
1410
							}
1411
1412
							// block wrap element
1413
							if ( isset( $this->options['block-wrap'] ) ) { //@todo we should validate this?
1414
								echo "block_wrap: {";
1415
								echo "	type: 'string',";
1416
								echo "  default: '" . esc_attr( $this->options['block-wrap'] ) . "',";
1417
								echo "},";
1418
							}
1419
1420
1421
							foreach ( $this->arguments as $key => $args ) {
1422
1423
								// set if we should show alignment
1424
								if ( $key == 'alignment' ) {
1425
									$show_alignment = true;
1426
								}
1427
1428
								$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...
1429
1430
								if ( $args['type'] == 'checkbox' ) {
1431
									$type    = 'boolean';
1432
									$default = isset( $args['default'] ) && $args['default'] ? 'true' : 'false';
1433
								} elseif ( $args['type'] == 'number' ) {
1434
									$type    = 'number';
1435
									$default = isset( $args['default'] ) ? "'" . $args['default'] . "'" : "''";
1436
								} elseif ( $args['type'] == 'select' && ! empty( $args['multiple'] ) ) {
1437
									$type = 'array';
1438
									if ( is_array( $args['default'] ) ) {
1439
										$default = isset( $args['default'] ) ? "['" . implode( "','", $args['default'] ) . "']" : "[]";
1440 View Code Duplication
									} else {
1441
										$default = isset( $args['default'] ) ? "'" . $args['default'] . "'" : "''";
1442
									}
1443
								} elseif ( $args['type'] == 'multiselect' ) {
1444
									$type    = 'array';
1445
									$default = isset( $args['default'] ) ? "'" . $args['default'] . "'" : "''";
1446 View Code Duplication
								} else {
1447
									$type    = 'string';
1448
									$default = isset( $args['default'] ) ? "'" . $args['default'] . "'" : "''";
1449
								}
1450
								echo $key . " : {";
1451
								echo "type : '$type',";
1452
								echo "default : $default,";
1453
								echo "},";
1454
							}
1455
1456
							echo "content : {type : 'string',default: 'Please select the attributes in the block settings'},";
1457
1458
							echo "},";
1459
1460
						}
1461
1462
						?>
1463
1464
						// The "edit" property must be a valid function.
1465
						edit: function (props) {
1466
1467
							var content = props.attributes.content;
1468
1469
							function onChangeContent() {
1470
1471
								if (!is_fetching && prev_attributes[props.id] != props.attributes) {
1472
1473
									//console.log(props);
1474
1475
									is_fetching = true;
1476
									var data = {
1477
										'action': 'super_duper_output_shortcode',
1478
										'shortcode': '<?php echo $this->options['base_id'];?>',
1479
										'attributes': props.attributes,
1480
										'post_id': <?php global $post; if ( isset( $post->ID ) ) {
1481
										echo $post->ID;
1482
									}?>,
1483
										'_ajax_nonce': '<?php echo wp_create_nonce( 'super_duper_output_shortcode' );?>'
1484
									};
1485
1486
									jQuery.post(ajaxurl, data, function (response) {
1487
										return response;
1488
									}).then(function (env) {
1489
1490
										// if the content is empty then we place some placeholder text
1491
										if (env == '') {
1492
											env = "<div style='background:#0185ba33;padding: 10px;border: 4px #ccc dashed;'>" + "<?php _e( 'Placeholder for: ' );?>" + props.name + "</div>";
1493
										}
1494
1495
										props.setAttributes({content: env});
1496
										is_fetching = false;
1497
										prev_attributes[props.id] = props.attributes;
1498
									});
1499
1500
1501
								}
1502
1503
								return props.attributes.content;
1504
1505
							}
1506
1507
							return [
1508
1509
								el(wp.editor.BlockControls, {key: 'controls'},
1510
1511
									<?php if($show_alignment){?>
1512
									el(
1513
										wp.editor.AlignmentToolbar,
1514
										{
1515
											value: props.attributes.alignment,
1516
											onChange: function (alignment) {
1517
												props.setAttributes({alignment: alignment})
1518
											}
1519
										}
1520
									)
1521
									<?php }?>
1522
1523
								),
1524
1525
								el(wp.editor.InspectorControls, {key: 'inspector'},
1526
1527
									<?php
1528
1529
									if(! empty( $this->arguments )){
1530
1531
									if ( $show_advanced ) {
1532
									?>
1533
									el(
1534
										wp.components.ToggleControl,
1535
										{
1536
											label: 'Show Advanced Settings?',
1537
											checked: props.attributes.show_advanced,
1538
											onChange: function (show_advanced) {
1539
												props.setAttributes({show_advanced: !props.attributes.show_advanced})
1540
											}
1541
										}
1542
									),
1543
									<?php
1544
1545
									}
1546
1547
									foreach($this->arguments as $key => $args){
1548
									$custom_attributes = ! empty( $args['custom_attributes'] ) ? $this->array_to_attributes( $args['custom_attributes'] ) : '';
1549
									$options = '';
1550
									$extra = '';
1551
									$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...
1552
									$onchange = "props.setAttributes({ $key: $key } )";
1553
									$value = "props.attributes.$key";
1554
									$text_type = array( 'text', 'password', 'number', 'email', 'tel', 'url', 'color' );
1555
									if ( in_array( $args['type'], $text_type ) ) {
1556
										$type = 'TextControl';
1557
										// Save numbers as numbers and not strings
1558
										if ( $args['type'] == 'number' ) {
1559
											$onchange = "props.setAttributes({ $key: Number($key) } )";
1560
										}
1561
									}
1562
//									elseif ( $args['type'] == 'color' ) { //@todo ColorPicker labels are not shown yet, we may have to add our own https://github.com/WordPress/gutenberg/issues/14378
1563
//										$type = 'ColorPicker';
1564
//									}
1565
									elseif ( $args['type'] == 'checkbox' ) {
1566
										$type = 'CheckboxControl';
1567
										$extra .= "checked: props.attributes.$key,";
1568
										$onchange = "props.setAttributes({ $key: ! props.attributes.$key } )";
1569
									} elseif ( $args['type'] == 'select' || $args['type'] == 'multiselect' ) {
1570
										$type = 'SelectControl';
1571
										if ( ! empty( $args['options'] ) ) {
1572
											$options .= "options  : [";
1573
											foreach ( $args['options'] as $option_val => $option_label ) {
1574
												$options .= "{ value : '" . esc_attr( $option_val ) . "',     label : '" . esc_attr( $option_label ) . "'     },";
1575
											}
1576
											$options .= "],";
1577
										}
1578
										if ( isset( $args['multiple'] ) && $args['multiple'] ) { //@todo multiselect does not work at the moment: https://github.com/WordPress/gutenberg/issues/5550
1579
											$extra .= ' multiple: true, ';
1580
											//$onchange = "props.setAttributes({ $key: ['edit'] } )";
1581
											//$value = "['edit', 'delete']";
1582
										}
1583
									} elseif ( $args['type'] == 'alignment' ) {
1584
										$type = 'AlignmentToolbar'; // @todo this does not seem to work but cant find a example
1585
									} else {
1586
										continue;// if we have not implemented the control then don't break the JS.
1587
									}
1588
1589
									// add show only if advanced
1590
									if ( ! empty( $args['advanced'] ) ) {
1591
										echo "props.attributes.show_advanced && ";
1592
									}
1593
									// add setting require if defined
1594
									if ( ! empty( $args['element_require'] ) ) {
1595
										echo $this->block_props_replace( $args['element_require'], true ) . " && ";
1596
									}
1597
									?>
1598
									el(
1599
										wp.components.<?php echo esc_attr( $type );?>,
1600
										{
1601
											label: '<?php echo esc_attr( $args['title'] );?>',
1602
											help: '<?php if ( isset( $args['desc'] ) ) {
1603
												echo esc_attr( $args['desc'] );
1604
											}?>',
1605
											value: <?php echo $value;?>,
1606
											<?php if ( $type == 'TextControl' && $args['type'] != 'text' ) {
1607
											echo "type: '" . esc_attr( $args['type'] ) . "',";
1608
										}?>
1609
											<?php if ( ! empty( $args['placeholder'] ) ) {
1610
											echo "placeholder: '" . esc_attr( $args['placeholder'] ) . "',";
1611
										}?>
1612
											<?php echo $options;?>
1613
											<?php echo $extra;?>
1614
											<?php echo $custom_attributes;?>
1615
											onChange: function ( <?php echo $key;?> ) {
1616
												<?php echo $onchange;?>
1617
											}
1618
										}
1619
									),
1620
									<?php
1621
									}
1622
									}
1623
									?>
1624
1625
								),
1626
1627
								<?php
1628
								// If the user sets block-output array then build it
1629
								if ( ! empty( $this->options['block-output'] ) ) {
1630
								$this->block_element( $this->options['block-output'] );
1631
							}else{
1632
								// if no block-output is set then we try and get the shortcode html output via ajax.
1633
								?>
1634
								el('div', {
1635
									dangerouslySetInnerHTML: {__html: onChangeContent()},
1636
									className: props.className,
1637
									style: {'min-height': '30px'}
1638
								})
1639
								<?php
1640
								}
1641
								?>
1642
							]; // end return
1643
						},
1644
1645
						// The "save" property must be specified and must be a valid function.
1646
						save: function (props) {
1647
1648
							//console.log(props);
1649
1650
1651
							var attr = props.attributes;
1652
							var align = '';
1653
1654
							// build the shortcode.
1655
							var content = "[<?php echo $this->options['base_id'];?>";
1656
							<?php
1657
1658
							if(! empty( $this->arguments )){
1659
							foreach($this->arguments as $key => $args){
1660
							?>
1661
							if (attr.hasOwnProperty("<?php echo esc_attr( $key );?>")) {
1662
								content += " <?php echo esc_attr( $key );?>='" + attr.<?php echo esc_attr( $key );?>+ "' ";
1663
							}
1664
							<?php
1665
							}
1666
							}
1667
1668
							?>
1669
							content += "]";
1670
1671
1672
							// @todo should we add inline style here or just css classes?
1673
							if (attr.alignment) {
1674
								if (attr.alignment == 'left') {
1675
									align = 'alignleft';
1676
								}
1677
								if (attr.alignment == 'center') {
1678
									align = 'aligncenter';
1679
								}
1680
								if (attr.alignment == 'right') {
1681
									align = 'alignright';
1682
								}
1683
							}
1684
1685
							//console.log(content);
1686
							var block_wrap = 'div';
1687
							if (attr.hasOwnProperty("block_wrap")) {
1688
								block_wrap = attr.block_wrap;
1689
							}
1690
							return el(block_wrap, {dangerouslySetInnerHTML: {__html: content}, className: align});
1691
1692
						}
1693
					});
1694
				})();
1695
			</script>
1696
			<?php
1697
			$output = ob_get_clean();
1698
1699
			/*
1700
			 * We only add the <script> tags for code highlighting, so we strip them from the output.
1701
			 */
1702
1703
			return str_replace( array(
1704
				'<script>',
1705
				'</script>'
1706
			), '', $output );
1707
		}
1708
1709
		/**
1710
		 * Convert an array of attributes to block string.
1711
		 *
1712
		 * @todo there is prob a faster way to do this, also we could add some validation here.
1713
		 *
1714
		 * @param $custom_attributes
1715
		 *
1716
		 * @return string
1717
		 */
1718
		public function array_to_attributes( $custom_attributes, $html = false ) {
1719
			$attributes = '';
1720
			if ( ! empty( $custom_attributes ) ) {
1721
1722
				if ( $html ) {
1723
					foreach ( $custom_attributes as $key => $val ) {
1724
						$attributes .= " $key='$val' ";
1725
					}
1726
				} else {
1727
					foreach ( $custom_attributes as $key => $val ) {
1728
						$attributes .= "'$key': '$val',";
1729
					}
1730
				}
1731
			}
1732
1733
			return $attributes;
1734
		}
1735
1736
		/**
1737
		 * A self looping function to create the output for JS block elements.
1738
		 *
1739
		 * This is what is output in the WP Editor visual view.
1740
		 *
1741
		 * @param $args
1742
		 */
1743
		public function block_element( $args ) {
1744
1745
1746
			if ( ! empty( $args ) ) {
1747
				foreach ( $args as $element => $new_args ) {
1748
1749
					if ( is_array( $new_args ) ) { // its an element
1750
1751
1752
						if ( isset( $new_args['element'] ) ) {
1753
1754 View Code Duplication
							if ( isset( $new_args['element_require'] ) ) {
1755
								echo str_replace( array(
1756
										"'+",
1757
										"+'"
1758
									), '', $this->block_props_replace( $new_args['element_require'] ) ) . " &&  ";
1759
								unset( $new_args['element_require'] );
1760
							}
1761
1762
							echo "\n el( '" . $new_args['element'] . "', {";
1763
1764
							// get the attributes
1765
							foreach ( $new_args as $new_key => $new_value ) {
1766
1767
1768
								if ( $new_key == 'element' || $new_key == 'content' || $new_key == 'element_require' || $new_key == 'element_repeat' || is_array( $new_value ) ) {
1769
									// do nothing
1770
								} else {
1771
									echo $this->block_element( array( $new_key => $new_value ) );
1772
								}
1773
							}
1774
1775
							echo "},";// end attributes
1776
1777
							// get the content
1778
							$first_item = 0;
1779
							foreach ( $new_args as $new_key => $new_value ) {
1780
								if ( $new_key === 'content' || is_array( $new_value ) ) {
1781
1782
									if ( $new_key === 'content' ) {
1783
										echo "'" . $this->block_props_replace( $new_value ) . "'";
1784
									}
1785
1786
									if ( is_array( $new_value ) ) {
1787
1788 View Code Duplication
										if ( isset( $new_value['element_require'] ) ) {
1789
											echo str_replace( array(
1790
													"'+",
1791
													"+'"
1792
												), '', $this->block_props_replace( $new_value['element_require'] ) ) . " &&  ";
1793
											unset( $new_value['element_require'] );
1794
										}
1795
1796
										if ( isset( $new_value['element_repeat'] ) ) {
1797
											$x = 1;
1798
											while ( $x <= absint( $new_value['element_repeat'] ) ) {
1799
												$this->block_element( array( '' => $new_value ) );
1800
												$x ++;
1801
											}
1802
										} else {
1803
											$this->block_element( array( '' => $new_value ) );
1804
										}
1805
									}
1806
									$first_item ++;
1807
								}
1808
							}
1809
1810
							echo ")";// end content
1811
1812
							echo ", \n";
1813
1814
						}
1815
					} else {
1816
1817
						if ( substr( $element, 0, 3 ) === "if_" ) {
1818
							echo str_replace( "if_", "", $element ) . ": " . $this->block_props_replace( $new_args, true ) . ",";
1819
						} elseif ( $element == 'style' ) {
1820
							echo $element . ": " . $this->block_props_replace( $new_args ) . ",";
1821
						} else {
1822
							echo $element . ": '" . $this->block_props_replace( $new_args ) . "',";
1823
						}
1824
1825
					}
1826
				}
1827
			}
1828
		}
1829
1830
		/**
1831
		 * Replace block attributes placeholders with the proper naming.
1832
		 *
1833
		 * @param $string
1834
		 *
1835
		 * @return mixed
1836
		 */
1837
		public function block_props_replace( $string, $no_wrap = false ) {
1838
1839
			if ( $no_wrap ) {
1840
				$string = str_replace( array( "[%", "%]" ), array( "props.attributes.", "" ), $string );
1841
			} else {
1842
				$string = str_replace( array( "[%", "%]" ), array( "'+props.attributes.", "+'" ), $string );
1843
			}
1844
1845
			return $string;
1846
		}
1847
1848
		/**
1849
		 * Outputs the content of the widget
1850
		 *
1851
		 * @param array $args
1852
		 * @param array $instance
1853
		 */
1854
		public function widget( $args, $instance ) {
1855
1856
			// get the filtered values
1857
			$argument_values = $this->argument_values( $instance );
1858
			$argument_values = $this->string_to_bool( $argument_values );
1859
			$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...
1860
1861
			if ( $output ) {
1862
				// Before widget
1863
				$before_widget = $args['before_widget'];
1864
				$before_widget = apply_filters( 'wp_super_duper_before_widget', $before_widget, $args, $instance, $this );
1865
				$before_widget = apply_filters( 'wp_super_duper_before_widget_' . $this->base_id, $before_widget, $args, $instance, $this );
1866
1867
				// After widget
1868
				$after_widget = $args['after_widget'];
1869
				$after_widget = apply_filters( 'wp_super_duper_after_widget', $after_widget, $args, $instance, $this );
1870
				$after_widget = apply_filters( 'wp_super_duper_after_widget_' . $this->base_id, $after_widget, $args, $instance, $this );
1871
1872
				echo $before_widget;
1873
				// elementor strips the widget wrapping div so we check for and add it back if needed
1874
				if ( $this->is_elementor_widget_output() ) {
1875
					echo ! empty( $this->options['widget_ops']['classname'] ) ? "<span class='" . esc_attr( $this->options['widget_ops']['classname'] ) . "'>" : '';
1876
				}
1877
				echo $this->output_title( $args, $instance );
1878
				echo $output;
1879
				if ( $this->is_elementor_widget_output() ) {
1880
					echo ! empty( $this->options['widget_ops']['classname'] ) ? "</span>" : '';
1881
				}
1882
				echo $after_widget;
1883 View Code Duplication
			} elseif ( $this->is_preview() && $output == '' ) {// if preview show a placeholder if empty
1884
				$output = $this->preview_placeholder_text( "{{" . $this->base_id . "}}" );
1885
				echo $output;
1886
			}
1887
		}
1888
1889
		/**
1890
		 * Tests if the current output is inside a elementor container.
1891
		 *
1892
		 * @since 1.0.4
1893
		 * @return bool
1894
		 */
1895
		public function is_elementor_widget_output() {
1896
			$result = false;
1897
			if ( defined( 'ELEMENTOR_VERSION' ) && isset( $this->number ) && $this->number == 'REPLACE_TO_ID' ) {
1898
				$result = true;
1899
			}
1900
1901
			return $result;
1902
		}
1903
1904
		/**
1905
		 * Tests if the current output is inside a elementor preview.
1906
		 *
1907
		 * @since 1.0.4
1908
		 * @return bool
1909
		 */
1910 View Code Duplication
		public function is_elementor_preview() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1911
			$result = false;
1912
			if ( isset( $_REQUEST['elementor-preview'] ) || ( is_admin() && isset( $_REQUEST['action'] ) && $_REQUEST['action'] == 'elementor' ) || ( isset( $_REQUEST['action'] ) && $_REQUEST['action'] == 'elementor_ajax' ) ) {
1913
				$result = true;
1914
			}
1915
1916
			return $result;
1917
		}
1918
1919
		/**
1920
		 * Tests if the current output is inside a Divi preview.
1921
		 *
1922
		 * @since 1.0.6
1923
		 * @return bool
1924
		 */
1925 View Code Duplication
		public function is_divi_preview() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1926
			$result = false;
1927
			if ( isset( $_REQUEST['et_fb'] ) || isset( $_REQUEST['et_pb_preview'] ) || ( is_admin() && isset( $_REQUEST['action'] ) && $_REQUEST['action'] == 'elementor' ) ) {
1928
				$result = true;
1929
			}
1930
1931
			return $result;
1932
		}
1933
1934
		/**
1935
		 * Tests if the current output is inside a Beaver builder preview.
1936
		 *
1937
		 * @since 1.0.6
1938
		 * @return bool
1939
		 */
1940
		public function is_beaver_preview() {
1941
			$result = false;
1942
			if ( isset( $_REQUEST['fl_builder'] ) ) {
1943
				$result = true;
1944
			}
1945
1946
			return $result;
1947
		}
1948
1949
		/**
1950
		 * Tests if the current output is inside a siteorigin builder preview.
1951
		 *
1952
		 * @since 1.0.6
1953
		 * @return bool
1954
		 */
1955
		public function is_siteorigin_preview() {
1956
			$result = false;
1957
			if ( ! empty( $_REQUEST['siteorigin_panels_live_editor'] ) ) {
1958
				$result = true;
1959
			}
1960
1961
			return $result;
1962
		}
1963
1964
		/**
1965
		 * Tests if the current output is inside a cornerstone builder preview.
1966
		 *
1967
		 * @since 1.0.8
1968
		 * @return bool
1969
		 */
1970
		public function is_cornerstone_preview() {
1971
			$result = false;
1972
			if ( ! empty( $_REQUEST['cornerstone_preview'] ) || basename( $_SERVER['REQUEST_URI'] ) == 'cornerstone-endpoint' ) {
1973
				$result = true;
1974
			}
1975
1976
			return $result;
1977
		}
1978
1979
		/**
1980
		 * General function to check if we are in a preview situation.
1981
		 *
1982
		 * @since 1.0.6
1983
		 * @return bool
1984
		 */
1985
		public function is_preview() {
1986
			$preview = false;
1987
			if ( $this->is_divi_preview() ) {
1988
				$preview = true;
1989
			} elseif ( $this->is_elementor_preview() ) {
1990
				$preview = true;
1991
			} elseif ( $this->is_beaver_preview() ) {
1992
				$preview = true;
1993
			} elseif ( $this->is_siteorigin_preview() ) {
1994
				$preview = true;
1995
			} elseif ( $this->is_cornerstone_preview() ) {
1996
				$preview = true;
1997
			}
1998
1999
			return $preview;
2000
		}
2001
2002
		/**
2003
		 * Output the super title.
2004
		 *
2005
		 * @param $args
2006
		 * @param array $instance
2007
		 *
2008
		 * @return string
2009
		 */
2010
		public function output_title( $args, $instance = array() ) {
2011
			$output = '';
2012
			if ( ! empty( $instance['title'] ) ) {
2013
				/** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */
2014
				$title  = apply_filters( 'widget_title', $instance['title'], $instance, $this->id_base );
2015
				$output = $args['before_title'] . $title . $args['after_title'];
2016
			}
2017
2018
			return $output;
2019
		}
2020
2021
		/**
2022
		 * Outputs the options form inputs for the widget.
2023
		 *
2024
		 * @param array $instance The widget options.
2025
		 */
2026
		public function form( $instance ) {
2027
2028
			// set widget instance
2029
			$this->instance = $instance;
2030
2031
			// set it as a SD widget
2032
			echo $this->widget_advanced_toggle();
2033
2034
			echo "<p>" . esc_attr( $this->options['widget_ops']['description'] ) . "</p>";
2035
			$arguments = $this->get_arguments();
2036
2037
			if ( is_array( $arguments ) ) {
2038
				foreach ( $arguments as $key => $args ) {
2039
					$this->widget_inputs( $args, $instance );
2040
				}
2041
			}
2042
		}
2043
2044
		/**
2045
		 * Get the hidden input that when added makes the advanced button show on widget settings.
2046
		 *
2047
		 * @return string
2048
		 */
2049
		public function widget_advanced_toggle() {
2050
2051
			$output = '';
2052
			if ( $this->block_show_advanced() ) {
2053
				$val = 1;
2054
			} else {
2055
				$val = 0;
2056
			}
2057
2058
			$output .= "<input type='hidden'  class='sd-show-advanced' value='$val' />";
2059
2060
			return $output;
2061
		}
2062
2063
		/**
2064
		 * Convert require element.
2065
		 *
2066
		 * @since 1.0.0
2067
		 *
2068
		 * @param string $input Input element.
2069
		 *
2070
		 * @return string $output
2071
		 */
2072
		public function convert_element_require( $input ) {
2073
2074
			$input = str_replace( "'", '"', $input );// we only want double quotes
2075
2076
			$output = esc_attr( str_replace( array( "[%", "%]" ), array(
2077
				"jQuery(form).find('[data-argument=\"",
2078
				"\"]').find('input,select').val()"
2079
			), $input ) );
2080
2081
			return $output;
2082
		}
2083
2084
		/**
2085
		 * Builds the inputs for the widget options.
2086
		 *
2087
		 * @param $args
2088
		 * @param $instance
2089
		 */
2090
		public function widget_inputs( $args, $instance ) {
2091
2092
			$class             = "";
2093
			$element_require   = "";
2094
			$custom_attributes = "";
2095
2096
			// get value
2097
			if ( isset( $instance[ $args['name'] ] ) ) {
2098
				$value = $instance[ $args['name'] ];
2099
			} elseif ( ! isset( $instance[ $args['name'] ] ) && ! empty( $args['default'] ) ) {
2100
				$value = is_array( $args['default'] ) ? array_map( "esc_html", $args['default'] ) : esc_html( $args['default'] );
2101
			} else {
2102
				$value = '';
2103
			}
2104
2105
			// get placeholder
2106 View Code Duplication
			if ( ! empty( $args['placeholder'] ) ) {
2107
				$placeholder = "placeholder='" . esc_html( $args['placeholder'] ) . "'";
2108
			} else {
2109
				$placeholder = '';
2110
			}
2111
2112
			// get if advanced
2113
			if ( isset( $args['advanced'] ) && $args['advanced'] ) {
2114
				$class .= " sd-advanced-setting ";
2115
			}
2116
2117
			// element_require
2118
			if ( isset( $args['element_require'] ) && $args['element_require'] ) {
2119
				$element_require = $args['element_require'];
2120
			}
2121
2122
			// custom_attributes
2123
			if ( isset( $args['custom_attributes'] ) && $args['custom_attributes'] ) {
2124
				$custom_attributes = $this->array_to_attributes( $args['custom_attributes'], true );
2125
			}
2126
2127
			// before wrapper
2128
			?>
2129
			<p class="sd-argument <?php echo esc_attr( $class ); ?>"
2130
			   data-argument='<?php echo esc_attr( $args['name'] ); ?>'
2131
			   data-element_require='<?php if ( $element_require ) {
2132
				   echo $this->convert_element_require( $element_require );
2133
			   } ?>'
2134
			>
2135
				<?php
2136
2137
				switch ( $args['type'] ) {
2138
					//array('text','password','number','email','tel','url','color')
2139
					case "text":
2140
					case "password":
2141
					case "number":
2142
					case "email":
2143
					case "tel":
2144
					case "url":
2145 View Code Duplication
					case "color":
2146
						?>
2147
						<label
2148
							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>
2149
						<input <?php echo $placeholder; ?> class="widefat"
2150
							<?php echo $custom_attributes; ?>
2151
							                               id="<?php echo esc_attr( $this->get_field_id( $args['name'] ) ); ?>"
2152
							                               name="<?php echo esc_attr( $this->get_field_name( $args['name'] ) ); ?>"
2153
							                               type="<?php echo esc_attr( $args['type'] ); ?>"
2154
							                               value="<?php echo esc_attr( $value ); ?>">
2155
						<?php
2156
2157
						break;
2158
					case "select":
2159
						$multiple = isset( $args['multiple'] ) && $args['multiple'] ? true : false;
2160
						if ( $multiple ) {
2161
							if ( empty( $value ) ) {
2162
								$value = array();
2163
							}
2164
						}
2165
						?>
2166
						<label
2167
							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>
2168
						<select <?php echo $placeholder; ?> class="widefat"
2169
							<?php echo $custom_attributes; ?>
2170
							                                id="<?php echo esc_attr( $this->get_field_id( $args['name'] ) ); ?>"
2171
							                                name="<?php echo esc_attr( $this->get_field_name( $args['name'] ) );
2172
							                                if ( $multiple ) {
2173
								                                echo "[]";
2174
							                                } ?>"
2175
							<?php if ( $multiple ) {
2176
								echo "multiple";
2177
							} //@todo not implemented yet due to gutenberg not supporting it
2178
							?>
2179
						>
2180
							<?php
2181
2182
							if ( ! empty( $args['options'] ) ) {
2183
								foreach ( $args['options'] as $val => $label ) {
2184
									if ( $multiple ) {
2185
										$selected = in_array( $val, $value ) ? 'selected="selected"' : '';
2186
									} else {
2187
										$selected = selected( $value, $val, false );
2188
									}
2189
									echo "<option value='$val' " . $selected . ">$label</option>";
2190
								}
2191
							}
2192
							?>
2193
						</select>
2194
						<?php
2195
						break;
2196 View Code Duplication
					case "checkbox":
2197
						?>
2198
						<input <?php echo $placeholder; ?>
2199
							<?php checked( 1, $value, true ) ?>
2200
							<?php echo $custom_attributes; ?>
2201
							class="widefat" id="<?php echo esc_attr( $this->get_field_id( $args['name'] ) ); ?>"
2202
							name="<?php echo esc_attr( $this->get_field_name( $args['name'] ) ); ?>" type="checkbox"
2203
							value="1">
2204
						<label
2205
							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>
2206
						<?php
2207
						break;
2208
					case "hidden":
2209
						?>
2210
						<input id="<?php echo esc_attr( $this->get_field_id( $args['name'] ) ); ?>"
2211
						       name="<?php echo esc_attr( $this->get_field_name( $args['name'] ) ); ?>" type="hidden"
2212
						       value="<?php echo esc_attr( $value ); ?>">
2213
						<?php
2214
						break;
2215
					default:
2216
						echo "No input type found!"; // @todo we need to add more input types.
2217
				}
2218
2219
				// after wrapper
2220
				?>
2221
			</p>
2222
			<?php
2223
2224
		}
2225
2226
		/**
2227
		 * Get the widget input description html.
2228
		 *
2229
		 * @param $args
2230
		 *
2231
		 * @return string
2232
		 * @todo, need to make its own tooltip script
2233
		 */
2234
		public function widget_field_desc( $args ) {
2235
2236
			$description = '';
2237
			if ( isset( $args['desc'] ) && $args['desc'] ) {
2238
				if ( isset( $args['desc_tip'] ) && $args['desc_tip'] ) {
2239
					$description = $this->desc_tip( $args['desc'] );
2240
				} else {
2241
					$description = '<span class="description">' . wp_kses_post( $args['desc'] ) . '</span>';
2242
				}
2243
			}
2244
2245
			return $description;
2246
		}
2247
2248
		/**
2249
		 * Get the tool tip html.
2250
		 *
2251
		 * @param $tip
2252
		 * @param bool $allow_html
2253
		 *
2254
		 * @return string
2255
		 */
2256
		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...
2257
			if ( $allow_html ) {
2258
				$tip = $this->sanitize_tooltip( $tip );
2259
			} else {
2260
				$tip = esc_attr( $tip );
2261
			}
2262
2263
			return '<span class="gd-help-tip dashicons dashicons-editor-help" title="' . $tip . '"></span>';
2264
		}
2265
2266
		/**
2267
		 * Sanitize a string destined to be a tooltip.
2268
		 *
2269
		 * @param string $var
2270
		 *
2271
		 * @return string
2272
		 */
2273
		public function sanitize_tooltip( $var ) {
2274
			return htmlspecialchars( wp_kses( html_entity_decode( $var ), array(
2275
				'br'     => array(),
2276
				'em'     => array(),
2277
				'strong' => array(),
2278
				'small'  => array(),
2279
				'span'   => array(),
2280
				'ul'     => array(),
2281
				'li'     => array(),
2282
				'ol'     => array(),
2283
				'p'      => array(),
2284
			) ) );
2285
		}
2286
2287
		/**
2288
		 * Processing widget options on save
2289
		 *
2290
		 * @param array $new_instance The new options
2291
		 * @param array $old_instance The previous options
2292
		 *
2293
		 * @return array
2294
		 * @todo we should add some sanitation here.
2295
		 */
2296
		public function update( $new_instance, $old_instance ) {
2297
2298
			//save the widget
2299
			$instance = array_merge( (array) $old_instance, (array) $new_instance );
2300
2301
			// set widget instance
2302
			$this->instance = $instance;
2303
2304
			if ( empty( $this->arguments ) ) {
2305
				$this->get_arguments();
2306
			}
2307
2308
			// check for checkboxes
2309
			if ( ! empty( $this->arguments ) ) {
2310
				foreach ( $this->arguments as $argument ) {
2311
					if ( isset( $argument['type'] ) && $argument['type'] == 'checkbox' && ! isset( $new_instance[ $argument['name'] ] ) ) {
2312
						$instance[ $argument['name'] ] = '0';
2313
					}
2314
				}
2315
			}
2316
2317
			return $instance;
2318
		}
2319
2320
		/**
2321
		 * Checks if the current call is a ajax call to get the block content.
2322
		 *
2323
		 * This can be used in your widget to return different content as the block content.
2324
		 *
2325
		 * @since 1.0.3
2326
		 * @return bool
2327
		 */
2328
		public function is_block_content_call() {
2329
			$result = false;
2330
			if ( wp_doing_ajax() && isset( $_REQUEST['action'] ) && $_REQUEST['action'] == 'super_duper_output_shortcode' ) {
2331
				$result = true;
2332
			}
2333
2334
			return $result;
2335
		}
2336
2337
	}
2338
2339
}