Passed
Push — master ( 2dc661...43660e )
by Brian
05:56 queued 14s
created

WP_Super_Duper::is_fusion_preview()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

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

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

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

2 paths for user data to reach this point

  1. Path: Read from $_POST, and Data is passed through sanitize_title_with_dashes(), and sanitize_title_with_dashes($_POST['shortcode']) is assigned to $shortcode_name in vendor/ayecode/wp-super-duper/wp-super-duper.php on line 1299
  1. Read from $_POST, and Data is passed through sanitize_title_with_dashes(), and sanitize_title_with_dashes($_POST['shortcode']) is assigned to $shortcode_name
    in vendor/ayecode/wp-super-duper/wp-super-duper.php on line 1299
  2. '[' . $shortcode_name . ' ' . $attributes . ']' is assigned to $shortcode
    in vendor/ayecode/wp-super-duper/wp-super-duper.php on line 1308
  3. Data is passed through do_shortcode()
    in vendor/ayecode/wp-super-duper/wp-super-duper.php on line 1310
  2. Path: Read from $_POST, and IssetNode && $_POST['attributes'] ? $_POST['attributes'] : array() is assigned to $attributes_array in vendor/ayecode/wp-super-duper/wp-super-duper.php on line 1300
  1. Read from $_POST, and IssetNode && $_POST['attributes'] ? $_POST['attributes'] : array() is assigned to $attributes_array
    in vendor/ayecode/wp-super-duper/wp-super-duper.php on line 1300
  2. $attributes_array is assigned to $key
    in vendor/ayecode/wp-super-duper/wp-super-duper.php on line 1303
  3. Data is passed through sanitize_title_with_dashes(), and ' ' . sanitize_title_with_dashes($key) . '='' . wp_slash($value) . '' ' is assigned to $attributes
    in vendor/ayecode/wp-super-duper/wp-super-duper.php on line 1304
  4. '[' . $shortcode_name . ' ' . $attributes . ']' is assigned to $shortcode
    in vendor/ayecode/wp-super-duper/wp-super-duper.php on line 1308
  5. Data is passed through do_shortcode()
    in vendor/ayecode/wp-super-duper/wp-super-duper.php on line 1310

Preventing Cross-Site-Scripting Attacks

Cross-Site-Scripting allows an attacker to inject malicious code into your website - in particular Javascript code, and have that code executed with the privileges of a visiting user. This can be used to obtain data, or perform actions on behalf of that visiting user.

In order to prevent this, make sure to escape all user-provided data:

// for HTML
$sanitized = htmlentities($tainted, ENT_QUOTES);

// for URLs
$sanitized = urlencode($tainted);

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
1311
1312
			}
1313
			wp_die();
1314
		}
1315
1316
		/**
1317
		 * Output the shortcode.
1318
		 *
1319
		 * @param array $args
1320
		 * @param string $content
1321
		 *
1322
		 * @return string
1323
		 */
1324
		public function shortcode_output( $args = array(), $content = '' ) {
1325
			$args = $this->argument_values( $args );
1326
1327
			// add extra argument so we know its a output to gutenberg
1328
			//$args
1329
			$args = $this->string_to_bool( $args );
1330
1331
			// if we have a enclosed shortcode we add it to the special `html` argument
1332
			if ( ! empty( $content ) ) {
1333
				$args['html'] = $content;
1334
			}
1335
1336
			$class = isset( $this->options['widget_ops']['classname'] ) ? esc_attr( $this->options['widget_ops']['classname'] ) : '';
1337
			$class .= " sdel-".$this->get_instance_hash();
1338
1339
			$class = apply_filters( 'wp_super_duper_div_classname', $class, $args, $this );
1340
			$class = apply_filters( 'wp_super_duper_div_classname_' . $this->base_id, $class, $args, $this );
1341
1342
			$attrs = apply_filters( 'wp_super_duper_div_attrs', '', $args, $this );
0 ignored issues
show
Unused Code introduced by
The assignment to $attrs is dead and can be removed.
Loading history...
1343
			$attrs = apply_filters( 'wp_super_duper_div_attrs_' . $this->base_id, '', $args, $this ); //@todo this does not seem right @kiran?
1344
1345
			$shortcode_args = array();
1346
			$output         = '';
1347
			$no_wrap        = isset( $this->options['no_wrap'] ) && $this->options['no_wrap'] ? true : false;
1348
			if ( isset( $args['no_wrap'] ) && $args['no_wrap'] ) {
1349
				$no_wrap = true;
1350
			}
1351
			$main_content = $this->output( $args, $shortcode_args, $content );
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $main_content is correct as $this->output($args, $shortcode_args, $content) targeting WP_Super_Duper::output() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
1352
			if ( $main_content && ! $no_wrap ) {
0 ignored issues
show
introduced by
$main_content is defined implicitly as null, thus it is always evaluated to false.
Loading history...
1353
				// wrap the shortcode in a div with the same class as the widget
1354
				$output .= '<div class="' . $class . '" ' . $attrs . '>';
1355
				if ( ! empty( $args['title'] ) ) {
1356
					// if its a shortcode and there is a title try to grab the title wrappers
1357
					$shortcode_args = array( 'before_title' => '', 'after_title' => '' );
1358
					if ( empty( $instance ) ) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $instance seems to never exist and therefore empty should always be true.
Loading history...
1359
						global $wp_registered_sidebars;
1360
						if ( ! empty( $wp_registered_sidebars ) ) {
1361
							foreach ( $wp_registered_sidebars as $sidebar ) {
1362
								if ( ! empty( $sidebar['before_title'] ) ) {
1363
									$shortcode_args['before_title'] = $sidebar['before_title'];
1364
									$shortcode_args['after_title']  = $sidebar['after_title'];
1365
									break;
1366
								}
1367
							}
1368
						}
1369
					}
1370
					$output .= $this->output_title( $shortcode_args, $args );
1371
				}
1372
				$output .= $main_content;
1373
				$output .= '</div>';
1374
			} elseif ( $main_content && $no_wrap ) {
0 ignored issues
show
introduced by
$main_content is defined implicitly as null, thus it is always evaluated to false.
Loading history...
1375
				$output .= $main_content;
1376
			}
1377
1378
			// if preview show a placeholder if empty
1379
			if ( $this->is_preview() && $output == '' ) {
1380
				$output = $this->preview_placeholder_text( "{{" . $this->base_id . "}}" );
1381
			}
1382
1383
			return apply_filters( 'wp_super_duper_widget_output', $output, $args, $shortcode_args, $this );
1384
		}
1385
1386
		/**
1387
		 * Placeholder text to show if output is empty and we are on a preview/builder page.
1388
		 *
1389
		 * @param string $name
1390
		 *
1391
		 * @return string
1392
		 */
1393
		public function preview_placeholder_text( $name = '' ) {
1394
			return "<div style='background:#0185ba33;padding: 10px;border: 4px #ccc dashed;'>" . sprintf( __( 'Placeholder for: %s' ), $name ) . "</div>";
1395
		}
1396
1397
		/**
1398
		 * Sometimes booleans values can be turned to strings, so we fix that.
1399
		 *
1400
		 * @param $options
1401
		 *
1402
		 * @return mixed
1403
		 */
1404
		public function string_to_bool( $options ) {
1405
			// convert bool strings to booleans
1406
			foreach ( $options as $key => $val ) {
1407
				if ( $val == 'false' ) {
1408
					$options[ $key ] = false;
1409
				} elseif ( $val == 'true' ) {
1410
					$options[ $key ] = true;
1411
				}
1412
			}
1413
1414
			return $options;
1415
		}
1416
1417
		/**
1418
		 * Get the argument values that are also filterable.
1419
		 *
1420
		 * @param $instance
1421
		 *
1422
		 * @since 1.0.12 Don't set checkbox default value if the value is empty.
1423
		 *
1424
		 * @return array
1425
		 */
1426
		public function argument_values( $instance ) {
1427
			$argument_values = array();
1428
1429
			// set widget instance
1430
			$this->instance = $instance;
1431
1432
			if ( empty( $this->arguments ) ) {
1433
				$this->arguments = $this->get_arguments();
1434
			}
1435
1436
			if ( ! empty( $this->arguments ) ) {
1437
				foreach ( $this->arguments as $key => $args ) {
1438
					// set the input name from the key
1439
					$args['name'] = $key;
1440
					//
1441
					$argument_values[ $key ] = isset( $instance[ $key ] ) ? $instance[ $key ] : '';
1442
					if ( $args['type'] == 'checkbox' && $argument_values[ $key ] == '' ) {
1443
						// don't set default for an empty checkbox
1444
					} elseif ( $argument_values[ $key ] == '' && isset( $args['default'] ) ) {
1445
						$argument_values[ $key ] = $args['default'];
1446
					}
1447
				}
1448
			}
1449
1450
			return $argument_values;
1451
		}
1452
1453
		/**
1454
		 * Set arguments in super duper.
1455
		 *
1456
		 * @since 1.0.0
1457
		 *
1458
		 * @return array Set arguments.
1459
		 */
1460
		public function set_arguments() {
1461
			return $this->arguments;
1462
		}
1463
1464
		/**
1465
		 * Get arguments in super duper.
1466
		 *
1467
		 * @since 1.0.0
1468
		 *
1469
		 * @return array Get arguments.
1470
		 */
1471
		public function get_arguments() {
1472
			if ( empty( $this->arguments ) ) {
1473
				$this->arguments = $this->set_arguments();
1474
			}
1475
1476
			$this->arguments = apply_filters( 'wp_super_duper_arguments', $this->arguments, $this->options, $this->instance );
1477
			$this->arguments = $this->add_name_from_key( $this->arguments, true );
1478
1479
			return $this->arguments;
1480
		}
1481
1482
		/**
1483
		 * This is the main output class for all 3 items, widget, shortcode and block, it is extended in the calling class.
1484
		 *
1485
		 * @param array $args
1486
		 * @param array $widget_args
1487
		 * @param string $content
1488
		 */
1489
		public function output( $args = array(), $widget_args = array(), $content = '' ) {
0 ignored issues
show
Unused Code introduced by
The parameter $widget_args is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

1489
		public function output( $args = array(), /** @scrutinizer ignore-unused */ $widget_args = array(), $content = '' ) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

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

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

2091
		public function block_row_start(/** @scrutinizer ignore-unused */ $key, $args){

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
2092
2093
			// check for row
2094
			if(!empty($args['row'])){
2095
2096
				if(!empty($args['row']['open'])){
2097
2098
				// element require
2099
				$element_require = ! empty( $args['element_require'] ) ? $this->block_props_replace( $args['element_require'], true ) . " && " : "";
2100
				echo $element_require;
2101
2102
					if(false){?><script><?php }?>
2103
						el('div', {
2104
								className: 'bsui components-base-control',
2105
							},
2106
							<?php if(!empty($args['row']['title'])){ ?>
2107
							el('label', {
2108
									className: 'components-base-control__label',
2109
								},
2110
								'<?php echo addslashes( $args['row']['title'] ); ?>'
2111
							),
2112
							<?php }?>
2113
							<?php if(!empty($args['row']['desc'])){ ?>
2114
							el('p', {
2115
									className: 'components-base-control__help mb-0',
2116
								},
2117
								'<?php echo addslashes( $args['row']['desc'] ); ?>'
2118
							),
2119
							<?php }?>
2120
							el(
2121
								'div',
2122
								{
2123
									className: 'row mb-n2 <?php if(!empty($args['row']['class'])){ echo esc_attr($args['row']['class']);} ?>',
2124
								},
2125
								el(
2126
									'div',
2127
									{
2128
										className: 'col pr-2',
2129
									},
2130
2131
					<?php
2132
					if(false){?></script><?php }
2133
				}elseif(!empty($args['row']['close'])){
2134
					if(false){?><script><?php }?>
2135
						el(
2136
							'div',
2137
							{
2138
								className: 'col pl-0',
2139
							},
2140
					<?php
2141
					if(false){?></script><?php }
2142
				}else{
2143
					if(false){?><script><?php }?>
2144
						el(
2145
							'div',
2146
							{
2147
								className: 'col pl-0 pr-2',
2148
							},
2149
					<?php
2150
					if(false){?></script><?php }
2151
				}
2152
2153
			}
2154
2155
		}
2156
2157
		public function block_row_end($key, $args){
0 ignored issues
show
Unused Code introduced by
The parameter $key is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

2157
		public function block_row_end(/** @scrutinizer ignore-unused */ $key, $args){

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
2158
2159
			if(!empty($args['row'])){
2160
				// maybe close
2161
				if(!empty($args['row']['close'])){
2162
					echo "))";
2163
				}
2164
2165
				echo "),";
2166
			}
2167
		}
2168
2169
		public function build_block_arguments( $key, $args ) {
2170
			$custom_attributes = ! empty( $args['custom_attributes'] ) ? $this->array_to_attributes( $args['custom_attributes'] ) : '';
2171
			$options           = '';
2172
			$extra             = '';
2173
			$require           = '';
0 ignored issues
show
Unused Code introduced by
The assignment to $require is dead and can be removed.
Loading history...
2174
2175
			// `content` is a protected and special argument
2176
			if ( $key == 'content' ) {
2177
				return;
2178
			}
2179
2180
2181
			// icon
2182
			$icon = '';
2183
			if( !empty( $args['icon'] ) ){
2184
				$icon .= "el('div', {";
2185
									$icon .= "dangerouslySetInnerHTML: {__html: '".self::get_widget_icon( esc_attr($args['icon']))."'},";
0 ignored issues
show
Bug Best Practice introduced by
The method WP_Super_Duper::get_widget_icon() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2185
									$icon .= "dangerouslySetInnerHTML: {__html: '".self::/** @scrutinizer ignore-call */ get_widget_icon( esc_attr($args['icon']))."'},";
Loading history...
2186
									$icon .= "className: 'text-center',";
2187
									$icon .= "title: '".addslashes( $args['title'] )."',";
2188
								$icon .= "}),";
2189
2190
				// blank title as its added to the icon.
2191
				$args['title'] = '';
2192
			}
2193
2194
			// require advanced
2195
			$require_advanced = ! empty( $args['advanced'] ) ? "props.attributes.show_advanced && " : "";
2196
2197
			// element require
2198
			$element_require = ! empty( $args['element_require'] ) ? $this->block_props_replace( $args['element_require'], true ) . " && " : "";
2199
2200
2201
			$onchange  = "props.setAttributes({ $key: $key } )";
2202
			$onchangecomplete  = "";
2203
			$value     = "props.attributes.$key";
2204
			$text_type = array( 'text', 'password', 'number', 'email', 'tel', 'url', 'colorx' );
2205
			if ( in_array( $args['type'], $text_type ) ) {
2206
				$type = 'TextControl';
2207
				// Save numbers as numbers and not strings
2208
				if ( $args['type'] == 'number' ) {
2209
					$onchange = "props.setAttributes({ $key: Number($key) } )";
2210
				}
2211
			}
2212
			/*
2213
			 * https://www.wptricks.com/question/set-current-tab-on-a-gutenberg-tabpanel-component-from-outside-that-component/ es5 layout
2214
						elseif($args['type']=='tabs'){
2215
							?>
2216
							<script>
2217
								el(
2218
									wp.components.TabPanel,
2219
									{
2220
										tabs: [
2221
											{
2222
												name: 'show',
2223
												title: __( 'Show', 'my-textdomain' ),
2224
											},
2225
											{
2226
												name: 'edit',
2227
												title: __( 'Edit', 'my-textdomain' ),
2228
											},
2229
										],
2230
									},
2231
									( tab ) => {
2232
2233
									if('show' === tab.name){
2234
									return 123;
2235
								}else if ( 'edit' === tab.name ) {
2236
									return 321;
2237
								}
2238
2239
								}
2240
								),
2241
							</script>
2242
							<?php
2243
							return;
2244
						}
2245
			*/
2246
			elseif ( $args['type'] == 'color' ) {
2247
				$type = 'ColorPicker';
2248
				$onchange = "";
2249
				$extra = "color: $value,";
2250
				if(!empty($args['disable_alpha'])){
2251
					$extra .= "disableAlpha: true,";
2252
				}
2253
				$onchangecomplete = "onChangeComplete: function($key) {
2254
				value =  $key.rgb.a && $key.rgb.a < 1 ? \"rgba(\"+$key.rgb.r+\",\"+$key.rgb.g+\",\"+$key.rgb.b+\",\"+$key.rgb.a+\")\" : $key.hex;
2255
                        props.setAttributes({
2256
                            $key: value
2257
                        });
2258
                    },";
2259
			}
2260
			elseif ( $args['type'] == 'checkbox' ) {
2261
				$type = 'CheckboxControl';
2262
				$extra .= "checked: props.attributes.$key,";
2263
				$onchange = "props.setAttributes({ $key: ! props.attributes.$key } )";
2264
			} elseif ( $args['type'] == 'textarea' ) {
2265
				$type = 'TextareaControl';
2266
			} elseif ( $args['type'] == 'select' || $args['type'] == 'multiselect' ) {
2267
				$type = 'SelectControl';
2268
2269
				if($args['name'] == 'category' && !empty($args['post_type_linked'])){
2270
					$options .= "options: taxonomies_".str_replace("-","_", $this->id).",";
2271
				}elseif($args['name'] == 'sort_by' && !empty($args['post_type_linked'])){
2272
					$options .= "options: sort_by_".str_replace("-","_", $this->id).",";
2273
				}else {
2274
2275
					if ( ! empty( $args['options'] ) ) {
2276
						$options .= "options: [";
2277
						foreach ( $args['options'] as $option_val => $option_label ) {
2278
							$options .= "{ value: '" . esc_attr( $option_val ) . "', label: '" . addslashes( $option_label ) . "' },";
2279
						}
2280
						$options .= "],";
2281
					}
2282
				}
2283
				if ( isset( $args['multiple'] ) && $args['multiple'] ) { //@todo multiselect does not work at the moment: https://github.com/WordPress/gutenberg/issues/5550
2284
					$extra .= ' multiple: true, ';
2285
				}
2286
			} elseif ( $args['type'] == 'alignment' ) {
2287
				$type = 'AlignmentToolbar'; // @todo this does not seem to work but cant find a example
2288
			}elseif ( $args['type'] == 'margins' ) {
2289
2290
			} else {
2291
				return;// if we have not implemented the control then don't break the JS.
2292
			}
2293
2294
2295
2296
			// color input does not show the labels so we add them
2297
			if($args['type']=='color'){
2298
				// add show only if advanced
2299
				echo $require_advanced;
2300
				// add setting require if defined
2301
				echo $element_require;
2302
				echo "el('div', {style: {'marginBottom': '8px'}}, '".addslashes( $args['title'] )."'),";
2303
			}
2304
2305
			// add show only if advanced
2306
			echo $require_advanced;
2307
			// add setting require if defined
2308
			echo $element_require;
2309
2310
			// icon
2311
			echo $icon;
2312
			?>
2313
			el( wp.components.<?php echo $type; ?>, {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $type does not seem to be defined for all execution paths leading up to this point.
Loading history...
2314
			label: '<?php echo addslashes( $args['title'] ); ?>',
2315
			help: '<?php if ( isset( $args['desc'] ) ) {
2316
				echo addslashes( $args['desc'] );
2317
			} ?>',
2318
			value: <?php echo $value; ?>,
2319
			<?php if ( $type == 'TextControl' && $args['type'] != 'text' ) {
2320
				echo "type: '" . addslashes( $args['type'] ) . "',";
2321
			} ?>
2322
			<?php if ( ! empty( $args['placeholder'] ) ) {
2323
				echo "placeholder: '" . addslashes( $args['placeholder'] ) . "',";
2324
			} ?>
2325
			<?php echo $options; ?>
2326
			<?php echo $extra; ?>
2327
			<?php echo $custom_attributes; ?>
2328
			<?php echo $onchangecomplete;?>
2329
			onChange: function ( <?php echo $key; ?> ) {
2330
			<?php echo $onchange; ?>
2331
			}
2332
			} ),
2333
			<?php
2334
2335
2336
		}
2337
2338
		/**
2339
		 * Convert an array of attributes to block string.
2340
		 *
2341
		 * @todo there is prob a faster way to do this, also we could add some validation here.
2342
		 *
2343
		 * @param $custom_attributes
2344
		 *
2345
		 * @return string
2346
		 */
2347
		public function array_to_attributes( $custom_attributes, $html = false ) {
2348
			$attributes = '';
2349
			if ( ! empty( $custom_attributes ) ) {
2350
2351
				if ( $html ) {
2352
					foreach ( $custom_attributes as $key => $val ) {
2353
						$attributes .= " $key='$val' ";
2354
					}
2355
				} else {
2356
					foreach ( $custom_attributes as $key => $val ) {
2357
						$attributes .= "'$key': '$val',";
2358
					}
2359
				}
2360
			}
2361
2362
			return $attributes;
2363
		}
2364
2365
		/**
2366
		 * A self looping function to create the output for JS block elements.
2367
		 *
2368
		 * This is what is output in the WP Editor visual view.
2369
		 *
2370
		 * @param $args
2371
		 */
2372
		public function block_element( $args ) {
2373
2374
2375
			if ( ! empty( $args ) ) {
2376
				foreach ( $args as $element => $new_args ) {
2377
2378
					if ( is_array( $new_args ) ) { // its an element
2379
2380
2381
						if ( isset( $new_args['element'] ) ) {
2382
2383
							if ( isset( $new_args['element_require'] ) ) {
2384
								echo str_replace( array(
2385
										"'+",
2386
										"+'"
2387
									), '', $this->block_props_replace( $new_args['element_require'] ) ) . " &&  ";
2388
								unset( $new_args['element_require'] );
2389
							}
2390
2391
							echo "\n el( '" . $new_args['element'] . "', {";
2392
2393
							// get the attributes
2394
							foreach ( $new_args as $new_key => $new_value ) {
2395
2396
2397
								if ( $new_key == 'element' || $new_key == 'content' || $new_key == 'element_require' || $new_key == 'element_repeat' || is_array( $new_value ) ) {
2398
									// do nothing
2399
								} else {
2400
									echo $this->block_element( array( $new_key => $new_value ) );
2401
								}
2402
							}
2403
2404
							echo "},";// end attributes
2405
2406
							// get the content
2407
							$first_item = 0;
2408
							foreach ( $new_args as $new_key => $new_value ) {
2409
								if ( $new_key === 'content' || is_array( $new_value ) ) {
2410
2411
									if ( $new_key === 'content' ) {
2412
										echo "'" . $this->block_props_replace( wp_slash( $new_value ) ) . "'";
2413
									}
2414
2415
									if ( is_array( $new_value ) ) {
2416
2417
										if ( isset( $new_value['element_require'] ) ) {
2418
											echo str_replace( array(
2419
													"'+",
2420
													"+'"
2421
												), '', $this->block_props_replace( $new_value['element_require'] ) ) . " &&  ";
2422
											unset( $new_value['element_require'] );
2423
										}
2424
2425
										if ( isset( $new_value['element_repeat'] ) ) {
2426
											$x = 1;
2427
											while ( $x <= absint( $new_value['element_repeat'] ) ) {
2428
												$this->block_element( array( '' => $new_value ) );
2429
												$x ++;
2430
											}
2431
										} else {
2432
											$this->block_element( array( '' => $new_value ) );
2433
										}
2434
									}
2435
									$first_item ++;
2436
								}
2437
							}
2438
2439
							echo ")";// end content
2440
2441
							echo ", \n";
2442
2443
						}
2444
					} else {
2445
2446
						if ( substr( $element, 0, 3 ) === "if_" ) {
2447
							echo str_replace( "if_", "", $element ) . ": " . $this->block_props_replace( $new_args, true ) . ",";
2448
						} elseif ( $element == 'style' ) {
2449
							echo $element . ": " . $this->block_props_replace( $new_args ) . ",";
2450
						} else {
2451
							echo $element . ": '" . $this->block_props_replace( $new_args ) . "',";
2452
						}
2453
2454
					}
2455
				}
2456
			}
2457
		}
2458
2459
		/**
2460
		 * Replace block attributes placeholders with the proper naming.
2461
		 *
2462
		 * @param $string
2463
		 *
2464
		 * @return mixed
2465
		 */
2466
		public function block_props_replace( $string, $no_wrap = false ) {
2467
2468
			if ( $no_wrap ) {
2469
				$string = str_replace( array( "[%", "%]" ), array( "props.attributes.", "" ), $string );
2470
			} else {
2471
				$string = str_replace( array( "[%", "%]" ), array( "'+props.attributes.", "+'" ), $string );
2472
			}
2473
2474
			return $string;
2475
		}
2476
2477
		/**
2478
		 * Outputs the content of the widget
2479
		 *
2480
		 * @param array $args
2481
		 * @param array $instance
2482
		 */
2483
		public function widget( $args, $instance ) {
2484
2485
			// get the filtered values
2486
			$argument_values = $this->argument_values( $instance );
2487
			$argument_values = $this->string_to_bool( $argument_values );
2488
			$output          = $this->output( $argument_values, $args );
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $output is correct as $this->output($argument_values, $args) targeting WP_Super_Duper::output() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
2489
2490
			$no_wrap = false;
2491
			if ( isset( $argument_values['no_wrap'] ) && $argument_values['no_wrap'] ) {
2492
				$no_wrap = true;
2493
			}
2494
2495
			ob_start();
2496
			if ( $output && ! $no_wrap ) {
0 ignored issues
show
introduced by
$output is defined implicitly as null, thus it is always evaluated to false.
Loading history...
2497
2498
				$class_original = $this->options['widget_ops']['classname'];
2499
				$class = $this->options['widget_ops']['classname']." sdel-".$this->get_instance_hash();
2500
2501
				// Before widget
2502
				$before_widget = $args['before_widget'];
2503
				$before_widget = str_replace($class_original,$class,$before_widget);
2504
				$before_widget = apply_filters( 'wp_super_duper_before_widget', $before_widget, $args, $instance, $this );
2505
				$before_widget = apply_filters( 'wp_super_duper_before_widget_' . $this->base_id, $before_widget, $args, $instance, $this );
2506
2507
				// After widget
2508
				$after_widget = $args['after_widget'];
2509
				$after_widget = apply_filters( 'wp_super_duper_after_widget', $after_widget, $args, $instance, $this );
2510
				$after_widget = apply_filters( 'wp_super_duper_after_widget_' . $this->base_id, $after_widget, $args, $instance, $this );
2511
2512
				echo $before_widget;
2513
				// elementor strips the widget wrapping div so we check for and add it back if needed
2514
				if ( $this->is_elementor_widget_output() ) {
2515
					echo ! empty( $this->options['widget_ops']['classname'] ) ? "<span class='" . esc_attr( $class  ) . "'>" : '';
2516
				}
2517
				echo $this->output_title( $args, $instance );
2518
				echo $output;
2519
				if ( $this->is_elementor_widget_output() ) {
2520
					echo ! empty( $this->options['widget_ops']['classname'] ) ? "</span>" : '';
2521
				}
2522
				echo $after_widget;
2523
			} elseif ( $this->is_preview() && $output == '' ) {// if preview show a placeholder if empty
2524
				$output = $this->preview_placeholder_text( "{{" . $this->base_id . "}}" );
2525
				echo $output;
2526
			} elseif ( $output && $no_wrap ) {
0 ignored issues
show
introduced by
$output is defined implicitly as null, thus it is always evaluated to false.
Loading history...
2527
				echo $output;
2528
			}
2529
			$output = ob_get_clean();
2530
2531
			$output = apply_filters( 'wp_super_duper_widget_output', $output, $instance, $args, $this );
2532
2533
			echo $output;
2534
		}
2535
2536
		/**
2537
		 * Tests if the current output is inside a elementor container.
2538
		 *
2539
		 * @since 1.0.4
2540
		 * @return bool
2541
		 */
2542
		public function is_elementor_widget_output() {
2543
			$result = false;
2544
			if ( defined( 'ELEMENTOR_VERSION' ) && isset( $this->number ) && $this->number == 'REPLACE_TO_ID' ) {
2545
				$result = true;
2546
			}
2547
2548
			return $result;
2549
		}
2550
2551
		/**
2552
		 * Tests if the current output is inside a elementor preview.
2553
		 *
2554
		 * @since 1.0.4
2555
		 * @return bool
2556
		 */
2557
		public function is_elementor_preview() {
2558
			$result = false;
2559
			if ( isset( $_REQUEST['elementor-preview'] ) || ( is_admin() && isset( $_REQUEST['action'] ) && $_REQUEST['action'] == 'elementor' ) || ( isset( $_REQUEST['action'] ) && $_REQUEST['action'] == 'elementor_ajax' ) ) {
2560
				$result = true;
2561
			}
2562
2563
			return $result;
2564
		}
2565
2566
		/**
2567
		 * Tests if the current output is inside a Divi preview.
2568
		 *
2569
		 * @since 1.0.6
2570
		 * @return bool
2571
		 */
2572
		public function is_divi_preview() {
2573
			$result = false;
2574
			if ( isset( $_REQUEST['et_fb'] ) || isset( $_REQUEST['et_pb_preview'] ) || ( is_admin() && isset( $_REQUEST['action'] ) && $_REQUEST['action'] == 'elementor' ) ) {
2575
				$result = true;
2576
			}
2577
2578
			return $result;
2579
		}
2580
2581
		/**
2582
		 * Tests if the current output is inside a Beaver builder preview.
2583
		 *
2584
		 * @since 1.0.6
2585
		 * @return bool
2586
		 */
2587
		public function is_beaver_preview() {
2588
			$result = false;
2589
			if ( isset( $_REQUEST['fl_builder'] ) ) {
2590
				$result = true;
2591
			}
2592
2593
			return $result;
2594
		}
2595
2596
		/**
2597
		 * Tests if the current output is inside a siteorigin builder preview.
2598
		 *
2599
		 * @since 1.0.6
2600
		 * @return bool
2601
		 */
2602
		public function is_siteorigin_preview() {
2603
			$result = false;
2604
			if ( ! empty( $_REQUEST['siteorigin_panels_live_editor'] ) ) {
2605
				$result = true;
2606
			}
2607
2608
			return $result;
2609
		}
2610
2611
		/**
2612
		 * Tests if the current output is inside a cornerstone builder preview.
2613
		 *
2614
		 * @since 1.0.8
2615
		 * @return bool
2616
		 */
2617
		public function is_cornerstone_preview() {
2618
			$result = false;
2619
			if ( ! empty( $_REQUEST['cornerstone_preview'] ) || basename( $_SERVER['REQUEST_URI'] ) == 'cornerstone-endpoint' ) {
2620
				$result = true;
2621
			}
2622
2623
			return $result;
2624
		}
2625
2626
		/**
2627
		 * Tests if the current output is inside a fusion builder preview.
2628
		 *
2629
		 * @since 1.1.0
2630
		 * @return bool
2631
		 */
2632
		public function is_fusion_preview() {
2633
			$result = false;
2634
			if ( ! empty( $_REQUEST['fb-edit'] ) || ! empty( $_REQUEST['fusion_load_nonce'] ) ) {
2635
				$result = true;
2636
			}
2637
2638
			return $result;
2639
		}
2640
2641
		/**
2642
		 * Tests if the current output is inside a Oxygen builder preview.
2643
		 *
2644
		 * @since 1.0.18
2645
		 * @return bool
2646
		 */
2647
		public function is_oxygen_preview() {
2648
			$result = false;
2649
			if ( ! empty( $_REQUEST['ct_builder'] ) || ( ! empty( $_REQUEST['action'] ) && ( substr( $_REQUEST['action'], 0, 11 ) === "oxy_render_" || substr( $_REQUEST['action'], 0, 10 ) === "ct_render_" ) ) ) {
2650
				$result = true;
2651
			}
2652
2653
			return $result;
2654
		}
2655
2656
		/**
2657
		 * General function to check if we are in a preview situation.
2658
		 *
2659
		 * @since 1.0.6
2660
		 * @return bool
2661
		 */
2662
		public function is_preview() {
2663
			$preview = false;
2664
			if ( $this->is_divi_preview() ) {
2665
				$preview = true;
2666
			} elseif ( $this->is_elementor_preview() ) {
2667
				$preview = true;
2668
			} elseif ( $this->is_beaver_preview() ) {
2669
				$preview = true;
2670
			} elseif ( $this->is_siteorigin_preview() ) {
2671
				$preview = true;
2672
			} elseif ( $this->is_cornerstone_preview() ) {
2673
				$preview = true;
2674
			} elseif ( $this->is_fusion_preview() ) {
2675
				$preview = true;
2676
			} elseif ( $this->is_oxygen_preview() ) {
2677
				$preview = true;
2678
			} elseif( $this->is_block_content_call() ) {
2679
				$preview = true;
2680
			}
2681
2682
			return $preview;
2683
		}
2684
2685
		/**
2686
		 * Output the super title.
2687
		 *
2688
		 * @param $args
2689
		 * @param array $instance
2690
		 *
2691
		 * @return string
2692
		 */
2693
		public function output_title( $args, $instance = array() ) {
2694
			$output = '';
2695
			if ( ! empty( $instance['title'] ) ) {
2696
				/** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */
2697
				$title  = apply_filters( 'widget_title', $instance['title'], $instance, $this->id_base );
2698
2699
				if(empty($instance['widget_title_tag'])){
2700
					$output = $args['before_title'] . $title . $args['after_title'];
2701
				}else{
2702
					$title_tag = esc_attr( $instance['widget_title_tag'] );
2703
2704
					// classes
2705
					$title_classes = array();
2706
					$title_classes[] = !empty( $instance['widget_title_size_class'] ) ? sanitize_html_class( $instance['widget_title_size_class'] ) : '';
2707
					$title_classes[] = !empty( $instance['widget_title_align_class'] ) ? sanitize_html_class( $instance['widget_title_align_class'] ) : '';
2708
					$title_classes[] = !empty( $instance['widget_title_color_class'] ) ? "text-".sanitize_html_class( $instance['widget_title_color_class'] ) : '';
2709
					$title_classes[] = !empty( $instance['widget_title_border_class'] ) ? sanitize_html_class( $instance['widget_title_border_class'] ) : '';
2710
					$title_classes[] = !empty( $instance['widget_title_border_color_class'] ) ? "border-".sanitize_html_class( $instance['widget_title_border_color_class'] ) : '';
2711
					$title_classes[] = !empty( $instance['widget_title_mt_class'] ) ? "mt-".absint( $instance['widget_title_mt_class'] ) : '';
2712
					$title_classes[] = !empty( $instance['widget_title_mr_class'] ) ? "mr-".absint( $instance['widget_title_mr_class'] ) : '';
2713
					$title_classes[] = !empty( $instance['widget_title_mb_class'] ) ? "mb-".absint( $instance['widget_title_mb_class'] ) : '';
2714
					$title_classes[] = !empty( $instance['widget_title_ml_class'] ) ? "ml-".absint( $instance['widget_title_ml_class'] ) : '';
2715
					$title_classes[] = !empty( $instance['widget_title_pt_class'] ) ? "pt-".absint( $instance['widget_title_pt_class'] ) : '';
2716
					$title_classes[] = !empty( $instance['widget_title_pr_class'] ) ? "pr-".absint( $instance['widget_title_pr_class'] ) : '';
2717
					$title_classes[] = !empty( $instance['widget_title_pb_class'] ) ? "pb-".absint( $instance['widget_title_pb_class'] ) : '';
2718
					$title_classes[] = !empty( $instance['widget_title_pl_class'] ) ? "pl-".absint( $instance['widget_title_pl_class'] ) : '';
2719
2720
					$class = !empty( $title_classes ) ? implode(" ",$title_classes) : '';
2721
					$output = "<$title_tag class='$class' >$title</$title_tag>";
2722
				}
2723
2724
			}
2725
2726
			return $output;
2727
		}
2728
2729
		/**
2730
		 * Outputs the options form inputs for the widget.
2731
		 *
2732
		 * @param array $instance The widget options.
2733
		 */
2734
		public function form( $instance ) {
2735
2736
			// set widget instance
2737
			$this->instance = $instance;
2738
2739
			// set it as a SD widget
2740
			echo $this->widget_advanced_toggle();
2741
2742
			echo "<p>" . esc_attr( $this->options['widget_ops']['description'] ) . "</p>";
2743
			$arguments_raw = $this->get_arguments();
2744
2745
			if ( is_array( $arguments_raw ) ) {
0 ignored issues
show
introduced by
The condition is_array($arguments_raw) is always true.
Loading history...
2746
2747
				$arguments = $this->group_arguments( $arguments_raw );
2748
2749
				// Do we have sections?
2750
				$has_sections = $arguments == $arguments_raw ? false : true;
2751
2752
2753
				if ( $has_sections ) {
2754
					$panel_count = 0;
2755
					foreach ( $arguments as $key => $args ) {
2756
2757
						?>
2758
						<script>
2759
							//							jQuery(this).find("i").toggleClass("fas fa-chevron-up fas fa-chevron-down");jQuery(this).next().toggle();
2760
						</script>
2761
						<?php
2762
2763
						$hide       = $panel_count ? ' style="display:none;" ' : '';
2764
						$icon_class = $panel_count ? 'fas fa-chevron-up' : 'fas fa-chevron-down';
2765
						echo "<button onclick='jQuery(this).find(\"i\").toggleClass(\"fas fa-chevron-up fas fa-chevron-down\");jQuery(this).next().slideToggle();' type='button' class='sd-toggle-group-button sd-input-group-toggle" . sanitize_title_with_dashes( $key ) . "'>" . esc_attr( $key ) . " <i style='float:right;' class='" . $icon_class . "'></i></button>";
2766
						echo "<div class='sd-toggle-group sd-input-group-" . sanitize_title_with_dashes( $key ) . "' $hide>";
2767
2768
						foreach ( $args as $k => $a ) {
2769
2770
							$this->widget_inputs_row_start($k, $a);
2771
							$this->widget_inputs( $a, $instance );
2772
							$this->widget_inputs_row_end($k, $a);
2773
2774
						}
2775
2776
						echo "</div>";
2777
2778
						$panel_count ++;
2779
2780
					}
2781
				} else {
2782
					foreach ( $arguments as $key => $args ) {
2783
						$this->widget_inputs_row_start($key, $args);
2784
						$this->widget_inputs( $args, $instance );
2785
						$this->widget_inputs_row_end($key, $args);
2786
					}
2787
				}
2788
2789
			}
2790
		}
2791
2792
		public function widget_inputs_row_start($key, $args){
0 ignored issues
show
Unused Code introduced by
The parameter $key is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

2792
		public function widget_inputs_row_start(/** @scrutinizer ignore-unused */ $key, $args){

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
2793
			if(!empty($args['row'])){
2794
				// maybe open
2795
				if(!empty($args['row']['open'])){
2796
					?>
2797
					<div class='bsui sd-argument ' data-argument='<?php echo esc_attr( $args['row']['key'] ); ?>' data-element_require='<?php if ( !empty($args['row']['element_require'])) {
2798
						echo $this->convert_element_require( $args['row']['element_require'] );
2799
					} ?>'>
2800
					<?php if(!empty($args['row']['title'])){ ?>
2801
					<label class="mb-0 "><?php echo esc_attr( $args['row']['title'] ); ?><?php echo $this->widget_field_desc( $args['row'] ); ?></label>
2802
					<?php }?>
2803
					<div class='row <?php if(!empty($args['row']['class'])){ echo esc_attr($args['row']['class']);} ?>'>
2804
					<div class='col pr-2'>
2805
					<?php
2806
				}elseif(!empty($args['row']['close'])){
2807
					echo "<div class='col pl-0'>";
2808
				}else{
2809
					echo "<div class='col pl-0 pr-2'>";
2810
				}
2811
			}
2812
		}
2813
2814
		public function widget_inputs_row_end($key, $args){
0 ignored issues
show
Unused Code introduced by
The parameter $key is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

2814
		public function widget_inputs_row_end(/** @scrutinizer ignore-unused */ $key, $args){

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
2815
2816
			if(!empty($args['row'])){
2817
				// maybe close
2818
				if(!empty($args['row']['close'])){
2819
					echo "</div></div>";
2820
				}
2821
2822
				echo "</div>";
2823
			}
2824
		}
2825
2826
		/**
2827
		 * Get the hidden input that when added makes the advanced button show on widget settings.
2828
		 *
2829
		 * @return string
2830
		 */
2831
		public function widget_advanced_toggle() {
2832
2833
			$output = '';
2834
			if ( $this->block_show_advanced() ) {
2835
				$val = 1;
2836
			} else {
2837
				$val = 0;
2838
			}
2839
2840
			$output .= "<input type='hidden'  class='sd-show-advanced' value='$val' />";
2841
2842
			return $output;
2843
		}
2844
2845
		/**
2846
		 * Convert require element.
2847
		 *
2848
		 * @since 1.0.0
2849
		 *
2850
		 * @param string $input Input element.
2851
		 *
2852
		 * @return string $output
2853
		 */
2854
		public function convert_element_require( $input ) {
2855
2856
			$input = str_replace( "'", '"', $input );// we only want double quotes
2857
2858
			$output = esc_attr( str_replace( array( "[%", "%]" ), array(
2859
				"jQuery(form).find('[data-argument=\"",
2860
				"\"]').find('input,select,textarea').val()"
2861
			), $input ) );
2862
2863
			return $output;
2864
		}
2865
2866
		/**
2867
		 * Builds the inputs for the widget options.
2868
		 *
2869
		 * @param $args
2870
		 * @param $instance
2871
		 */
2872
		public function widget_inputs( $args, $instance ) {
2873
2874
			$class             = "";
2875
			$element_require   = "";
2876
			$custom_attributes = "";
2877
2878
			// get value
2879
			if ( isset( $instance[ $args['name'] ] ) ) {
2880
				$value = $instance[ $args['name'] ];
2881
			} elseif ( ! isset( $instance[ $args['name'] ] ) && ! empty( $args['default'] ) ) {
2882
				$value = is_array( $args['default'] ) ? array_map( "esc_html", $args['default'] ) : esc_html( $args['default'] );
2883
			} else {
2884
				$value = '';
2885
			}
2886
2887
			// get placeholder
2888
			if ( ! empty( $args['placeholder'] ) ) {
2889
				$placeholder = "placeholder='" . esc_html( $args['placeholder'] ) . "'";
2890
			} else {
2891
				$placeholder = '';
2892
			}
2893
2894
			// get if advanced
2895
			if ( isset( $args['advanced'] ) && $args['advanced'] ) {
2896
				$class .= " sd-advanced-setting ";
2897
			}
2898
2899
			// element_require
2900
			if ( isset( $args['element_require'] ) && $args['element_require'] ) {
2901
				$element_require = $args['element_require'];
2902
			}
2903
2904
			// custom_attributes
2905
			if ( isset( $args['custom_attributes'] ) && $args['custom_attributes'] ) {
2906
				$custom_attributes = $this->array_to_attributes( $args['custom_attributes'], true );
2907
			}
2908
2909
2910
			// before wrapper
2911
			?>
2912
			<p class="sd-argument <?php echo esc_attr( $class ); ?>"
2913
			data-argument='<?php echo esc_attr( $args['name'] ); ?>'
2914
			data-element_require='<?php if ( $element_require ) {
2915
				echo $this->convert_element_require( $element_require );
2916
			} ?>'
2917
			>
2918
			<?php
2919
2920
2921
			switch ( $args['type'] ) {
2922
				//array('text','password','number','email','tel','url','color')
2923
				case "text":
2924
				case "password":
2925
				case "number":
2926
				case "email":
2927
				case "tel":
2928
				case "url":
2929
				case "color":
2930
					?>
2931
					<label
2932
						for="<?php echo esc_attr( $this->get_field_id( $args['name'] ) ); ?>"><?php echo $this->widget_field_title( $args );?><?php echo $this->widget_field_desc( $args ); ?></label>
2933
					<input <?php echo $placeholder; ?> class="widefat"
2934
						<?php echo $custom_attributes; ?>
2935
						                               id="<?php echo esc_attr( $this->get_field_id( $args['name'] ) ); ?>"
2936
						                               name="<?php echo esc_attr( $this->get_field_name( $args['name'] ) ); ?>"
2937
						                               type="<?php echo esc_attr( $args['type'] ); ?>"
2938
						                               value="<?php echo esc_attr( $value ); ?>">
2939
					<?php
2940
2941
					break;
2942
				case "select":
2943
					$multiple = isset( $args['multiple'] ) && $args['multiple'] ? true : false;
2944
					if ( $multiple ) {
2945
						if ( empty( $value ) ) {
2946
							$value = array();
2947
						}
2948
					}
2949
					?>
2950
					<label
2951
						for="<?php echo esc_attr( $this->get_field_id( $args['name'] ) ); ?>"><?php echo $this->widget_field_title( $args ); ?><?php echo $this->widget_field_desc( $args ); ?></label>
2952
					<select <?php echo $placeholder; ?> class="widefat"
2953
						<?php echo $custom_attributes; ?>
2954
						                                id="<?php echo esc_attr( $this->get_field_id( $args['name'] ) ); ?>"
2955
						                                name="<?php echo esc_attr( $this->get_field_name( $args['name'] ) );
2956
						                                if ( $multiple ) {
2957
							                                echo "[]";
2958
						                                } ?>"
2959
						<?php if ( $multiple ) {
2960
							echo "multiple";
2961
						} //@todo not implemented yet due to gutenberg not supporting it
2962
						?>
2963
					>
2964
						<?php
2965
2966
						if ( ! empty( $args['options'] ) ) {
2967
							foreach ( $args['options'] as $val => $label ) {
2968
								if ( $multiple ) {
2969
									$selected = in_array( $val, $value ) ? 'selected="selected"' : '';
2970
								} else {
2971
									$selected = selected( $value, $val, false );
2972
								}
2973
								echo "<option value='$val' " . $selected . ">$label</option>";
2974
							}
2975
						}
2976
						?>
2977
					</select>
2978
					<?php
2979
					break;
2980
				case "checkbox":
2981
					?>
2982
					<input <?php echo $placeholder; ?>
2983
						<?php checked( 1, $value, true ) ?>
2984
						<?php echo $custom_attributes; ?>
2985
						class="widefat" id="<?php echo esc_attr( $this->get_field_id( $args['name'] ) ); ?>"
2986
						name="<?php echo esc_attr( $this->get_field_name( $args['name'] ) ); ?>" type="checkbox"
2987
						value="1">
2988
					<label
2989
						for="<?php echo esc_attr( $this->get_field_id( $args['name'] ) ); ?>"><?php echo $this->widget_field_title( $args );?><?php echo $this->widget_field_desc( $args ); ?></label>
2990
					<?php
2991
					break;
2992
				case "textarea":
2993
					?>
2994
					<label
2995
						for="<?php echo esc_attr( $this->get_field_id( $args['name'] ) ); ?>"><?php echo $this->widget_field_title( $args ); ?><?php echo $this->widget_field_desc( $args ); ?></label>
2996
					<textarea <?php echo $placeholder; ?> class="widefat"
2997
						<?php echo $custom_attributes; ?>
2998
						                                  id="<?php echo esc_attr( $this->get_field_id( $args['name'] ) ); ?>"
2999
						                                  name="<?php echo esc_attr( $this->get_field_name( $args['name'] ) ); ?>"
3000
					><?php echo esc_attr( $value ); ?></textarea>
3001
					<?php
3002
3003
					break;
3004
				case "hidden":
3005
					?>
3006
					<input id="<?php echo esc_attr( $this->get_field_id( $args['name'] ) ); ?>"
3007
					       name="<?php echo esc_attr( $this->get_field_name( $args['name'] ) ); ?>" type="hidden"
3008
					       value="<?php echo esc_attr( $value ); ?>">
3009
					<?php
3010
					break;
3011
				default:
3012
					echo "No input type found!"; // @todo we need to add more input types.
3013
			}
3014
3015
			// after wrapper
3016
			?>
3017
			</p>
3018
			<?php
3019
3020
3021
		}
3022
3023
		public function get_widget_icon($icon = 'box-top', $title = ''){
3024
			if($icon=='box-top'){
3025
				return '<svg title="'.esc_attr($title).'" width="20px" height="20px" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.414" role="img" aria-hidden="true" focusable="false"><rect x="2.714" y="5.492" width="1.048" height="9.017" fill="#555D66"></rect><rect x="16.265" y="5.498" width="1.023" height="9.003" fill="#555D66"></rect><rect x="5.518" y="2.186" width="8.964" height="2.482" fill="#272B2F"></rect><rect x="5.487" y="16.261" width="9.026" height="1.037" fill="#555D66"></rect></svg>';
3026
			}elseif($icon=='box-right'){
3027
				return '<svg title="'.esc_attr($title).'" width="20px" height="20px" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.414" role="img" aria-hidden="true" focusable="false"><rect x="2.714" y="5.492" width="1.046" height="9.017" fill="#555D66"></rect><rect x="15.244" y="5.498" width="2.518" height="9.003" fill="#272B2F"></rect><rect x="5.518" y="2.719" width="8.964" height="0.954" fill="#555D66"></rect><rect x="5.487" y="16.308" width="9.026" height="0.99" fill="#555D66"></rect></svg>';
3028
			}elseif($icon=='box-bottom'){
3029
				return '<svg title="'.esc_attr($title).'" width="20px" height="20px" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.414" role="img" aria-hidden="true" focusable="false"><rect x="2.714" y="5.492" width="1" height="9.017" fill="#555D66"></rect><rect x="16.261" y="5.498" width="1.027" height="9.003" fill="#555D66"></rect><rect x="5.518" y="2.719" width="8.964" height="0.968" fill="#555D66"></rect><rect x="5.487" y="15.28" width="9.026" height="2.499" fill="#272B2F"></rect></svg>';
3030
			}elseif($icon=='box-left'){
3031
				return '<svg title="'.esc_attr($title).'" width="20px" height="20px" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.414" role="img" aria-hidden="true" focusable="false"><rect x="2.202" y="5.492" width="2.503" height="9.017" fill="#272B2F"></rect><rect x="16.276" y="5.498" width="1.012" height="9.003" fill="#555D66"></rect><rect x="5.518" y="2.719" width="8.964" height="0.966" fill="#555D66"></rect><rect x="5.487" y="16.303" width="9.026" height="0.995" fill="#555D66"></rect></svg>';
3032
			}
3033
		}
3034
3035
		/**
3036
		 * Get the widget input description html.
3037
		 *
3038
		 * @param $args
3039
		 *
3040
		 * @return string
3041
		 * @todo, need to make its own tooltip script
3042
		 */
3043
		public function widget_field_desc( $args ) {
3044
3045
			$description = '';
3046
			if ( isset( $args['desc'] ) && $args['desc'] ) {
3047
				if ( isset( $args['desc_tip'] ) && $args['desc_tip'] ) {
3048
					$description = $this->desc_tip( $args['desc'] );
3049
				} else {
3050
					$description = '<span class="description">' . wp_kses_post( $args['desc'] ) . '</span>';
3051
				}
3052
			}
3053
3054
			return $description;
3055
		}
3056
3057
		/**
3058
		 * Get the widget input title html.
3059
		 *
3060
		 * @param $args
3061
		 *
3062
		 * @return string
3063
		 */
3064
		public function widget_field_title( $args ) {
3065
3066
			$title = '';
3067
			if ( isset( $args['title'] ) && $args['title'] ) {
3068
				if ( isset( $args['icon'] ) && $args['icon'] ) {
3069
					$title = self::get_widget_icon( $args['icon'], $args['title']  );
0 ignored issues
show
Bug Best Practice introduced by
The method WP_Super_Duper::get_widget_icon() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

3069
					/** @scrutinizer ignore-call */ 
3070
     $title = self::get_widget_icon( $args['icon'], $args['title']  );
Loading history...
3070
				} else {
3071
					$title = esc_attr($args['title']);
3072
				}
3073
			}
3074
3075
			return $title;
3076
		}
3077
3078
		/**
3079
		 * Get the tool tip html.
3080
		 *
3081
		 * @param $tip
3082
		 * @param bool $allow_html
3083
		 *
3084
		 * @return string
3085
		 */
3086
		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...
3087
			if ( $allow_html ) {
3088
				$tip = $this->sanitize_tooltip( $tip );
3089
			} else {
3090
				$tip = esc_attr( $tip );
3091
			}
3092
3093
			return '<span class="gd-help-tip dashicons dashicons-editor-help" title="' . $tip . '"></span>';
3094
		}
3095
3096
		/**
3097
		 * Sanitize a string destined to be a tooltip.
3098
		 *
3099
		 * @param string $var
3100
		 *
3101
		 * @return string
3102
		 */
3103
		public function sanitize_tooltip( $var ) {
3104
			return htmlspecialchars( wp_kses( html_entity_decode( $var ), array(
3105
				'br'     => array(),
3106
				'em'     => array(),
3107
				'strong' => array(),
3108
				'small'  => array(),
3109
				'span'   => array(),
3110
				'ul'     => array(),
3111
				'li'     => array(),
3112
				'ol'     => array(),
3113
				'p'      => array(),
3114
			) ) );
3115
		}
3116
3117
		/**
3118
		 * Processing widget options on save
3119
		 *
3120
		 * @param array $new_instance The new options
3121
		 * @param array $old_instance The previous options
3122
		 *
3123
		 * @return array
3124
		 * @todo we should add some sanitation here.
3125
		 */
3126
		public function update( $new_instance, $old_instance ) {
3127
3128
			//save the widget
3129
			$instance = array_merge( (array) $old_instance, (array) $new_instance );
3130
3131
			// set widget instance
3132
			$this->instance = $instance;
3133
3134
			if ( empty( $this->arguments ) ) {
3135
				$this->get_arguments();
3136
			}
3137
3138
			// check for checkboxes
3139
			if ( ! empty( $this->arguments ) ) {
3140
				foreach ( $this->arguments as $argument ) {
3141
					if ( isset( $argument['type'] ) && $argument['type'] == 'checkbox' && ! isset( $new_instance[ $argument['name'] ] ) ) {
3142
						$instance[ $argument['name'] ] = '0';
3143
					}
3144
				}
3145
			}
3146
3147
			return $instance;
3148
		}
3149
3150
		/**
3151
		 * Checks if the current call is a ajax call to get the block content.
3152
		 *
3153
		 * This can be used in your widget to return different content as the block content.
3154
		 *
3155
		 * @since 1.0.3
3156
		 * @return bool
3157
		 */
3158
		public function is_block_content_call() {
3159
			$result = false;
3160
			if ( wp_doing_ajax() && isset( $_REQUEST['action'] ) && $_REQUEST['action'] == 'super_duper_output_shortcode' ) {
3161
				$result = true;
3162
			}
3163
3164
			return $result;
3165
		}
3166
3167
		/**
3168
		 * Get an instance hash that will be unique to the type and settings.
3169
		 *
3170
		 * @since 1.0.20
3171
		 * @return string
3172
		 */
3173
		public function get_instance_hash(){
3174
			$instance_string = $this->base_id.serialize($this->instance);
3175
			return hash('crc32b',$instance_string);
3176
		}
3177
3178
		/**
3179
		 * Generate and return inline styles from CSS rules that will match the unique class of the instance.
3180
		 *
3181
		 * @param array $rules
3182
		 *
3183
		 * @since 1.0.20
3184
		 * @return string
3185
		 */
3186
		public function get_instance_style($rules = array()){
3187
			$css = '';
3188
3189
			if(!empty($rules)){
3190
				$rules = array_unique($rules);
3191
				$instance_hash = $this->get_instance_hash();
3192
				$css .= "<style>";
3193
				foreach($rules as $rule){
3194
					$css .= ".sdel-$instance_hash $rule";
3195
				}
3196
				$css .= "</style>";
3197
			}
3198
3199
3200
			return $css;
3201
3202
		}
3203
3204
	}
3205
3206
}
3207