Passed
Pull Request — master (#185)
by
unknown
05:49
created

WP_Super_Duper::is_block_content_call()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

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

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

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

Loading history...
607
					global $post;
608
					$post = $post_obj;
609
				}
610
			}
611
612
			if ( isset( $_POST['shortcode'] ) && $_POST['shortcode'] ) {
613
				$shortcode_name   = sanitize_title_with_dashes( $_POST['shortcode'] );
614
				$attributes_array = isset( $_POST['attributes'] ) && $_POST['attributes'] ? $_POST['attributes'] : array();
615
				$attributes       = '';
616
				if ( ! empty( $attributes_array ) ) {
617
					foreach ( $attributes_array as $key => $value ) {
618
						$attributes .= " " . sanitize_title_with_dashes( $key ) . "='" . wp_slash( $value ) . "' ";
619
					}
620
				}
621
622
				$shortcode = "[" . $shortcode_name . " " . $attributes . "]";
623
624
				echo do_shortcode( $shortcode );
625
626
			}
627
			wp_die();
628
		}
629
630
		/**
631
		 * Output the shortcode.
632
		 *
633
		 * @param array $args
634
		 * @param string $content
635
		 */
636
		public function shortcode_output( $args = array(), $content = '' ) {
637
			$args = self::argument_values( $args );
638
639
			// add extra argument so we know its a output to gutenberg
640
			//$args
641
			$args = $this->string_to_bool( $args );
642
643
644
			$calss = isset($this->options['widget_ops']['classname']) ? esc_attr($this->options['widget_ops']['classname']) : '';
645
646
			$calss = apply_filters( 'wp_super_duper_div_classname', $calss, $args, $this );
647
			$calss = apply_filters( 'wp_super_duper_div_classname_' . $this->base_id, $calss, $args, $this );
648
649
			$attrs = apply_filters( 'wp_super_duper_div_attrs', '', $args, $this );
0 ignored issues
show
Unused Code introduced by
$attrs is not used, you could remove the assignment.

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

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

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

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

Loading history...
650
			$attrs = apply_filters( 'wp_super_duper_div_attrs_' . $this->base_id, '', $args, $this );
651
652
			$shortcode_args = array();
653
			$output = '';
654
			$no_wrap = isset($this->options['no_wrap']) && $this->options['no_wrap'] ?  true : false;
655
			$main_content = $this->output( $args, $shortcode_args, $content );
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $main_content is correct as $this->output($args, $shortcode_args, $content) (which targets WP_Super_Duper::output()) seems to always return null.

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

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

}

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

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

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

Loading history...
656
			if($main_content && !$no_wrap){
657
				// wrap the shortcode in a dive with the same class as the widget
658
				$output .= '<div class="'.$calss.'" ' . $attrs . '>';
659
				if(!empty($args['title'])){
660
					// if its a shortcode and there is a title try to grab the title wrappers
661
					$shortcode_args = array('before_title'=>'', 'after_title' => '');
662
					if(empty($instance)){
0 ignored issues
show
Bug introduced by
The variable $instance seems to never exist, and therefore empty should always return true. Did you maybe rename this variable?

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Loading history...
1010
									$onchange = "props.setAttributes({ $key: $key } )";
1011
									$value = "props.attributes.$key";
1012
									$text_type = array( 'text', 'password', 'number', 'email', 'tel', 'url', 'color' );
1013
									if ( in_array( $args['type'], $text_type ) ) {
1014
										$type = 'TextControl';
1015
									} elseif ( $args['type'] == 'checkbox' ) {
1016
										$type = 'CheckboxControl';
1017
										$extra .= "checked: props.attributes.$key,";
1018
										$onchange = "props.setAttributes({ $key: ! props.attributes.$key } )";
1019
									} elseif ( $args['type'] == 'select' || $args['type'] == 'multiselect' ) {
1020
										$type = 'SelectControl';
1021
										if ( ! empty( $args['options'] ) ) {
1022
											$options .= "options  : [";
1023
											foreach ( $args['options'] as $option_val => $option_label ) {
1024
												$options .= "{ value : '" . esc_attr( $option_val ) . "',     label : '" . esc_attr( $option_label ) . "'     },";
1025
											}
1026
											$options .= "],";
1027
										}
1028
										if ( isset( $args['multiple'] ) && $args['multiple'] ) { //@todo multiselect does not work at the moment: https://github.com/WordPress/gutenberg/issues/5550
1029
											$extra .= ' multiple: true, ';
1030
											//$onchange = "props.setAttributes({ $key: ['edit'] } )";
1031
											//$value = "['edit', 'delete']";
1032
										}
1033
									} elseif ( $args['type'] == 'alignment' ) {
1034
										$type = 'AlignmentToolbar'; // @todo this does not seem to work but cant find a example
1035
									} else {
1036
										continue;// if we have not implemented the control then don't break the JS.
1037
									}
1038
1039
									// add show only if advanced
1040
									if ( ! empty( $args['advanced'] ) ) {
1041
										echo "props.attributes.show_advanced && ";
1042
									}
1043
									// add setting require if defined
1044
									if ( ! empty( $args['element_require'] ) ) {
1045
										echo $this->block_props_replace( $args['element_require'], true ) . " && ";
1046
									}
1047
									?>
1048
									el(
1049
										wp.components.<?php echo esc_attr( $type );?>,
1050
										{
1051
											label: '<?php echo esc_attr( $args['title'] );?>',
1052
											help: '<?php if ( isset( $args['desc'] ) ) {
1053
												echo esc_attr( $args['desc'] );
1054
											}?>',
1055
											value: <?php echo $value;?>,
1056
											<?php if ( $type == 'TextControl' && $args['type'] != 'text' ) {
1057
											echo "type: '" . esc_attr( $args['type'] ) . "',";
1058
										}?>
1059
											<?php if ( ! empty( $args['placeholder'] ) ) {
1060
											echo "placeholder: '" . esc_attr( $args['placeholder'] ) . "',";
1061
										}?>
1062
											<?php echo $options;?>
1063
											<?php echo $extra;?>
1064
											<?php echo $custom_attributes;?>
1065
											onChange: function ( <?php echo $key;?> ) {
1066
												<?php echo $onchange;?>
1067
											}
1068
										}
1069
									),
1070
									<?php
1071
									}
1072
									}
1073
									?>
1074
1075
								),
1076
1077
								<?php
1078
								// If the user sets block-output array then build it
1079
								if ( ! empty( $this->options['block-output'] ) ) {
1080
								$this->block_element( $this->options['block-output'] );
1081
							}else{
1082
								// if no block-output is set then we try and get the shortcode html output via ajax.
1083
								?>
1084
								el('div', {
1085
									dangerouslySetInnerHTML: {__html: onChangeContent()},
1086
									className: props.className,
1087
									style: {'min-height': '30px'}
1088
								})
1089
								<?php
1090
								}
1091
								?>
1092
							]; // end return
1093
						},
1094
1095
						// The "save" property must be specified and must be a valid function.
1096
						save: function (props) {
1097
1098
							console.log(props);
1099
1100
1101
							var attr = props.attributes;
1102
							var align = '';
1103
1104
							// build the shortcode.
1105
							var content = "[<?php echo $this->options['base_id'];?>";
1106
							<?php
1107
1108
							if(! empty( $this->arguments )){
1109
							foreach($this->arguments as $key => $args){
1110
							?>
1111
							if (attr.hasOwnProperty("<?php echo esc_attr( $key );?>")) {
1112
								content += " <?php echo esc_attr( $key );?>='" + attr.<?php echo esc_attr( $key );?>+ "' ";
1113
							}
1114
							<?php
1115
							}
1116
							}
1117
1118
							?>
1119
							content += "]";
1120
1121
1122
							// @todo should we add inline style here or just css classes?
1123
							if (attr.alignment) {
1124
								if (attr.alignment == 'left') {
1125
									align = 'alignleft';
1126
								}
1127
								if (attr.alignment == 'center') {
1128
									align = 'aligncenter';
1129
								}
1130
								if (attr.alignment == 'right') {
1131
									align = 'alignright';
1132
								}
1133
							}
1134
1135
							console.log(content);
1136
							return el('div', {dangerouslySetInnerHTML: {__html: content}, className: align});
1137
1138
						}
1139
					});
1140
				})();
1141
			</script>
1142
			<?php
1143
			$output = ob_get_clean();
1144
1145
			/*
1146
			 * We only add the <script> tags for code highlighting, so we strip them from the output.
1147
			 */
1148
1149
			return str_replace( array(
1150
				'<script>',
1151
				'</script>'
1152
			), '', $output );
1153
		}
1154
1155
		/**
1156
		 * Convert an array of attributes to block string.
1157
		 *
1158
		 * @todo there is prob a faster way to do this, also we could add some validation here.
1159
		 * @param $custom_attributes
1160
		 *
1161
		 * @return string
1162
		 */
1163
		public function array_to_attributes($custom_attributes, $html = false){
1164
			$attributes = '';
1165
			if(!empty($custom_attributes)){
1166
1167
				if($html){
1168
					foreach($custom_attributes as $key => $val){
1169
						$attributes .= " $key='$val' ";
1170
					}
1171
				}else{
1172
					foreach($custom_attributes as $key => $val){
1173
						$attributes .= "'$key': '$val',";
1174
					}
1175
				}
1176
			}
1177
1178
			return $attributes;
1179
		}
1180
1181
1182
		/**
1183
		 * A self looping function to create the output for JS block elements.
1184
		 *
1185
		 * This is what is output in the WP Editor visual view.
1186
		 *
1187
		 * @param $args
1188
		 */
1189
		public function block_element( $args ) {
1190
1191
1192
			if ( ! empty( $args ) ) {
1193
				foreach ( $args as $element => $new_args ) {
1194
1195
					if ( is_array( $new_args ) ) { // its an element
1196
1197
1198
						if ( isset( $new_args['element'] ) ) {
1199
1200
							//print_r($new_args);
1201
1202 View Code Duplication
							if ( isset( $new_args['element_require'] ) ) {
1203
								echo str_replace( array(
1204
										"'+",
1205
										"+'"
1206
									), '', $this->block_props_replace( $new_args['element_require'] ) ) . " &&  ";
1207
								unset( $new_args['element_require'] );
1208
							}
1209
1210
							echo "\n el( '" . $new_args['element'] . "', {";
1211
1212
							// get the attributes
1213
							foreach ( $new_args as $new_key => $new_value ) {
1214
1215
1216
								if ( $new_key == 'element' || $new_key == 'content' || $new_key == 'element_require' || $new_key == 'element_repeat' || is_array( $new_value ) ) {
1217
									// do nothing
1218
								} else {
1219
									echo $this->block_element( array( $new_key => $new_value ) );
1220
								}
1221
							}
1222
1223
							echo "},";// end attributes
1224
1225
							// get the content
1226
							$first_item = 0;
1227
							foreach ( $new_args as $new_key => $new_value ) {
1228
								if ( $new_key === 'content' || is_array( $new_value ) ) {
1229
									//echo ",".$first_item;// separate the children
1230
1231
1232
									if ( $first_item > 0 ) {
1233
										//echo ",";// separate the children
1234
									} else {
1235
										//echo '####'.$first_item;
1236
									}
1237
1238
									if ( $new_key === 'content' ) {
1239
										//print_r($new_args);
1240
										echo "'" . $this->block_props_replace( $new_value ) . "'";
1241
									}
1242
1243
									if ( is_array( $new_value ) ) {
1244
1245 View Code Duplication
										if ( isset( $new_value['element_require'] ) ) {
1246
											echo str_replace( array(
1247
													"'+",
1248
													"+'"
1249
												), '', $this->block_props_replace( $new_value['element_require'] ) ) . " &&  ";
1250
											unset( $new_value['element_require'] );
1251
										}
1252
1253
										if ( isset( $new_value['element_repeat'] ) ) {
1254
											$x = 1;
1255
											while ( $x <= absint( $new_value['element_repeat'] ) ) {
1256
												$this->block_element( array( '' => $new_value ) );
1257
												$x ++;
1258
											}
1259
										} else {
1260
											$this->block_element( array( '' => $new_value ) );
1261
										}
1262
										//print_r($new_value);
1263
									}
1264
									$first_item ++;
1265
								}
1266
							}
1267
1268
							echo ")";// end content
1269
1270
							//if($first_item>0){
1271
							echo ", \n";
1272
							//}
1273
1274
1275
						}
1276
						//$this->block_element($new_args);
1277
					} else {
1278
1279
						if ( substr( $element, 0, 3 ) === "if_" ) {
1280
							echo str_replace( "if_", "", $element ) . ": " . $this->block_props_replace( $new_args, true ) . ",";
1281
						} elseif ( $element == 'style' ) {
1282
							echo $element . ": " . $this->block_props_replace( $new_args ) . ",";
1283
						} else {
1284
							echo $element . ": '" . $this->block_props_replace( $new_args ) . "',";
1285
						}
1286
1287
					}
1288
1289
1290
				}
1291
			}
1292
		}
1293
1294
		/**
1295
		 * Replace block attributes placeholders with the proper naming.
1296
		 *
1297
		 * @param $string
1298
		 *
1299
		 * @return mixed
1300
		 */
1301
		public function block_props_replace( $string, $no_wrap = false ) {
1302
1303
			if ( $no_wrap ) {
1304
				$string = str_replace( array( "[%", "%]" ), array( "props.attributes.", "" ), $string );
1305
			} else {
1306
				$string = str_replace( array( "[%", "%]" ), array( "'+props.attributes.", "+'" ), $string );
1307
			}
1308
1309
			return $string;
1310
		}
1311
1312
		/**
1313
		 * Outputs the content of the widget
1314
		 *
1315
		 * @param array $args
1316
		 * @param array $instance
1317
		 */
1318
		public function widget( $args, $instance ) {
1319
			// outputs the content of the widget
1320
1321
			// get the filtered values
1322
			$argument_values = $this->argument_values( $instance );
1323
			$argument_values = $this->string_to_bool( $argument_values );
1324
			$output = $this->output( $argument_values, $args );
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $output is correct as $this->output($argument_values, $args) (which targets WP_Super_Duper::output()) seems to always return null.

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

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

}

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

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

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

Loading history...
1325
1326
			if ( $output ) {
1327
				// Before widget
1328
				$before_widget = $args['before_widget'];
1329
				$before_widget = apply_filters( 'wp_super_duper_before_widget', $before_widget, $args, $instance, $this );
1330
				$before_widget = apply_filters( 'wp_super_duper_before_widget_' . $this->base_id, $before_widget, $args, $instance, $this );
1331
1332
				// After widget
1333
				$after_widget = $args['after_widget'];
1334
				$after_widget = apply_filters( 'wp_super_duper_after_widget', $after_widget, $args, $instance, $this );
1335
				$after_widget = apply_filters( 'wp_super_duper_after_widget_' . $this->base_id, $after_widget, $args, $instance, $this );
1336
1337
				echo $before_widget;
1338
				echo $this->output_title($args, $instance);
1339
				echo $output;
1340
				echo $after_widget;
1341
			}
1342
		}
1343
1344
		/**
1345
		 * Output the super title.
1346
		 *
1347
		 * @param $args
1348
		 * @param array $instance
1349
		 *
1350
		 * @return string
1351
		 */
1352
		public function output_title($args, $instance = array()){
1353
			$output = '';
1354
			if ( ! empty( $instance['title'] ) ) {
1355
				/** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */
1356
				$title = apply_filters( 'widget_title', $instance['title'], $instance, $this->id_base );
1357
				$output = $args['before_title'] . $title . $args['after_title'];
1358
			}
1359
			return $output;
1360
		}
1361
1362
		/**
1363
		 * Outputs the options form inputs for the widget.
1364
		 *
1365
		 * @param array $instance The widget options.
1366
		 */
1367
		public function form( $instance ) {
1368
1369
			// set widget instance
1370
			$this->instance = $instance;
1371
1372
			// set it as a SD widget
1373
			echo $this->widget_advanced_toggle();
1374
1375
1376
			echo "<p>" . esc_attr( $this->options['widget_ops']['description'] ) . "</p>";
1377
			$arguments = $this->get_arguments();
1378
//			print_r($instance );
1379
//			echo '###';
1380
//			print_r($arguments  );
1381
1382
			if ( is_array( $arguments ) ) {
1383
				foreach ( $arguments as $key => $args ) {
1384
					$this->widget_inputs( $args, $instance );
1385
				}
1386
			}
1387
		}
1388
1389
		/**
1390
		 * Get the hidden input that when added makes the advanced button show on widget settings.
1391
		 *
1392
		 * @return string
1393
		 */
1394
		public function widget_advanced_toggle() {
1395
1396
			$output = '';
1397
			if ( $this->block_show_advanced() ) {
1398
				$val = 1;
1399
			} else {
1400
				$val = 0;
1401
			}
1402
			if($val){
1403
//				$output .=  '<span class="sd-advanced-button-container"><button class="button button-primary right sd-advanced-button" onclick="sd_toggle_advanced(this);return false;"><i class="fas fa-sliders-h" aria-hidden="true"></i></button></span>';
1404
			}
1405
1406
			$output .= "<input type='hidden'  class='sd-show-advanced' value='$val' />";
1407
1408
1409
1410
1411
			return $output;
1412
1413
		}
1414
1415
		/**
1416
		 * Convert require element.
1417
		 *
1418
		 * @since 2.0.0
1419
		 *
1420
		 * @param string $input Input element.
1421
		 * @return string $output
1422
		 */
1423
		public function convert_element_require( $input ) {
1424
1425
			$input = str_replace( "'", '"', $input );// we only want double quotes
1426
1427
			$output = esc_attr( str_replace( array( "[%", "%]" ), array(
1428
				"jQuery(form).find('[data-argument=\"",
1429
				"\"]').find('input,select').val()"
1430
			), $input ) );
1431
1432
1433
			return $output;
1434
		}
1435
1436
		/**
1437
		 * Builds the inputs for the widget options.
1438
		 *
1439
		 * @param $args
1440
		 * @param $instance
1441
		 */
1442
		public function widget_inputs( $args, $instance ) {
1443
1444
//print_r($instance );echo '###';
1445
//print_r($args );
1446
			$class           = "";
1447
			$element_require = "";
1448
			$custom_attributes = "";
1449
1450
			// get value
1451
			if ( isset( $instance[ $args['name'] ] ) ) {
1452
				$value = $instance[ $args['name'] ];
1453
			} elseif ( ! isset( $instance[ $args['name'] ] ) && ! empty( $args['default'] ) ) {
1454
				$value = is_array($args['default']) ? array_map("esc_html",$args['default']) : esc_html( $args['default'] );
1455
			} else {
1456
				$value = '';
1457
			}
1458
1459
			// get placeholder
1460 View Code Duplication
			if ( ! empty( $args['placeholder'] ) ) {
1461
				$placeholder = "placeholder='" . esc_html( $args['placeholder'] ) . "'";
1462
			} else {
1463
				$placeholder = '';
1464
			}
1465
1466
			// get if advanced
1467
			if ( isset( $args['advanced'] ) && $args['advanced'] ) {
1468
				$class .= " sd-advanced-setting ";
1469
			}
1470
1471
			// element_require
1472
			if ( isset( $args['element_require'] ) && $args['element_require'] ) {
1473
				$element_require = $args['element_require'];
1474
			}
1475
1476
			// custom_attributes
1477
			if( isset( $args['custom_attributes']) && $args['custom_attributes']){
1478
				$custom_attributes = $this->array_to_attributes($args['custom_attributes'],true);
1479
			}
1480
1481
1482
1483
1484
			// before wrapper
1485
			?>
1486
			<p class="sd-argument <?php echo esc_attr( $class ); ?>"
1487
			   data-argument='<?php echo esc_attr( $args['name'] ); ?>'
1488
			   data-element_require='<?php if ( $element_require ) {
1489
				   echo $this->convert_element_require( $element_require );
1490
			   } ?>'
1491
			>
1492
				<?php
1493
1494
				switch ( $args['type'] ) {
1495
					//array('text','password','number','email','tel','url','color')
1496
					case "text":
1497
					case "password":
1498
					case "number":
1499
					case "email":
1500
					case "tel":
1501
					case "url":
1502 View Code Duplication
					case "color":
1503
						?>
1504
						<label
1505
							for="<?php echo esc_attr( $this->get_field_id( $args['name'] ) ); ?>"><?php echo esc_attr( $args['title'] ); ?><?php echo $this->widget_field_desc( $args ); ?></label>
1506
						<input <?php echo $placeholder; ?> class="widefat"
1507
							<?php echo $custom_attributes;?>
1508
							                               id="<?php echo esc_attr( $this->get_field_id( $args['name'] ) ); ?>"
1509
							                               name="<?php echo esc_attr( $this->get_field_name( $args['name'] ) ); ?>"
1510
							                               type="<?php echo esc_attr( $args['type'] ); ?>"
1511
							                               value="<?php echo esc_attr( $value ); ?>">
1512
						<?php
1513
1514
						break;
1515
					case "select":
1516
						$multiple = isset( $args['multiple'] ) && $args['multiple']  ? true : false;
1517
						if($multiple){if(empty($value)){$value = array();}}
1518
						?>
1519
						<label
1520
							for="<?php echo esc_attr( $this->get_field_id( $args['name'] ) ); ?>"><?php echo esc_attr( $args['title'] ); ?><?php echo $this->widget_field_desc( $args ); ?></label>
1521
						<select <?php echo $placeholder; ?> class="widefat"
1522
							<?php echo $custom_attributes;?>
1523
							                                id="<?php echo esc_attr( $this->get_field_id( $args['name'] ) ); ?>"
1524
							                                name="<?php echo esc_attr( $this->get_field_name( $args['name'] ) ); if($multiple){echo "[]";}?>"
1525
							<?php if ($multiple) {
1526
								echo "multiple";
1527
							} //@todo not implemented yet due to gutenberg not supporting it
1528
							?>
1529
						>
1530
							<?php
1531
1532
1533
							if ( ! empty( $args['options'] ) ) {
1534
								foreach ( $args['options'] as $val => $label ) {
1535
//									print_r($value);
1536
//									echo '@@@'.print_r($val,true),'@@@';
1537
//									echo '###'.$value.'###';
1538
									if ($multiple) {$selected = in_array($val,$value) ? 'selected="selected"' : ''; }else{$selected = selected( $value, $val, false );}
1539
									echo "<option value='$val' " . $selected . ">$label</option>";
1540
								}
1541
							}
1542
							?>
1543
						</select>
1544
						<?php
1545
						break;
1546 View Code Duplication
					case "checkbox":
1547
						?>
1548
						<input <?php echo $placeholder; ?>
1549
							<?php checked( 1, $value, true ) ?>
1550
							<?php echo $custom_attributes;?>
1551
							class="widefat" id="<?php echo esc_attr( $this->get_field_id( $args['name'] ) ); ?>"
1552
							name="<?php echo esc_attr( $this->get_field_name( $args['name'] ) ); ?>" type="checkbox"
1553
							value="1">
1554
						<label
1555
							for="<?php echo esc_attr( $this->get_field_id( $args['name'] ) ); ?>"><?php echo esc_attr( $args['title'] ); ?><?php echo $this->widget_field_desc( $args ); ?></label>
1556
						<?php
1557
						break;
1558
					case "hidden":
1559
						?>
1560
						<input id="<?php echo esc_attr( $this->get_field_id( $args['name'] ) ); ?>"
1561
						       name="<?php echo esc_attr( $this->get_field_name( $args['name'] ) ); ?>" type="hidden"
1562
						       value="<?php echo esc_attr( $value ); ?>">
1563
						<?php
1564
						break;
1565
					default:
1566
						echo "No input type found!"; // @todo we need to add more input types.
1567
				}
1568
1569
				// after wrapper
1570
				?>
1571
			</p>
1572
			<?php
1573
1574
		}
1575
1576
1577
		/**
1578
		 * Get the widget input description html.
1579
		 *
1580
		 * @param $args
1581
		 *
1582
		 * @return string
1583
		 * @todo, need to make its own tooltip script
1584
		 */
1585
		public function widget_field_desc( $args ) {
1586
1587
			$description = '';
1588
			if ( isset( $args['desc'] ) && $args['desc'] ) {
1589
				if ( isset( $args['desc_tip'] ) && $args['desc_tip'] ) {
1590
					$description = $this->desc_tip( $args['desc'] );
1591
				} else {
1592
					$description = '<span class="description">' . wp_kses_post( $args['desc'] ) . '</span>';
1593
				}
1594
			}
1595
1596
			return $description;
1597
		}
1598
1599
1600
		/**
1601
		 * Get the tool tip html.
1602
		 *
1603
		 * @param $tip
1604
		 * @param bool $allow_html
1605
		 *
1606
		 * @return string
1607
		 */
1608
		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...
1609
			if ( $allow_html ) {
1610
				$tip = $this->sanitize_tooltip( $tip );
1611
			} else {
1612
				$tip = esc_attr( $tip );
1613
			}
1614
1615
			return '<span class="gd-help-tip dashicons dashicons-editor-help" title="' . $tip . '"></span>';
1616
		}
1617
1618
		/**
1619
		 * Sanitize a string destined to be a tooltip.
1620
		 *
1621
		 * @param string $var
1622
		 *
1623
		 * @return string
1624
		 */
1625
		public function sanitize_tooltip( $var ) {
1626
			return htmlspecialchars( wp_kses( html_entity_decode( $var ), array(
1627
				'br'     => array(),
1628
				'em'     => array(),
1629
				'strong' => array(),
1630
				'small'  => array(),
1631
				'span'   => array(),
1632
				'ul'     => array(),
1633
				'li'     => array(),
1634
				'ol'     => array(),
1635
				'p'      => array(),
1636
			) ) );
1637
		}
1638
1639
		/**
1640
		 * Processing widget options on save
1641
		 *
1642
		 * @param array $new_instance The new options
1643
		 * @param array $old_instance The previous options
1644
		 *
1645
		 * @return array
1646
		 * @todo we should add some sanitation here.
1647
		 */
1648
		public function update( $new_instance, $old_instance ) {
1649
//			print_r($new_instance);
1650
//			print_r($old_instance);
1651
//			exit;
1652
			//save the widget
1653
			$instance = array_merge( (array) $old_instance, (array) $new_instance );
1654
1655
			// set widget instance
1656
			$this->instance = $instance;
1657
1658
			if(empty($this->arguments)){
1659
				$this->get_arguments();
1660
			}
1661
1662
			// check for checkboxes
1663
			if ( ! empty( $this->arguments ) ) {
1664
				foreach ( $this->arguments as $argument ) {
1665
					if ( isset( $argument['type'] ) && $argument['type'] == 'checkbox' && ! isset( $new_instance[ $argument['name'] ] ) ) {
1666
						$instance[ $argument['name'] ] = '0';
1667
					}
1668
				}
1669
			}
1670
1671
			return $instance;
1672
		}
1673
1674
		/**
1675
		 * Checks if the current call is a ajax call to get the block content.
1676
		 *
1677
		 * This can be used in your widget to return different content as the block content.
1678
		 *
1679
		 * @since 1.0.3
1680
		 * @return bool
1681
		 */
1682
		public function is_block_content_call(){
1683
			$result = false;
1684
			if(wp_doing_ajax() && isset($_REQUEST['action']) && $_REQUEST['action'] =='super_duper_output_shortcode'){
1685
				$result = true;
1686
			}
1687
1688
			return $result;
1689
		}
1690
1691
	}
1692
1693
}
1694