Passed
Push — master ( 26770f...806cdd )
by Chris
03:20
created

CMB_Post_Select::get_delegate_data()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 8
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 0
1
<?php
2
3
/**
4
 * Abstract class for all fields.
5
 * Subclasses need only override html()
6
 *
7
 * @abstract
8
 */
9
abstract class CMB_Field {
10
11
	public $value;
12
	public $field_index = 0;
13
14
	public function __construct( $name, $title, array $values, $args = array() ) {
15
16
		$this->id 		= $name;
0 ignored issues
show
Bug Best Practice introduced by
The property id does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
17
		$this->name		= $name . '[]';
0 ignored issues
show
Bug Best Practice introduced by
The property name does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
18
		$this->title 	= $title;
0 ignored issues
show
Bug Best Practice introduced by
The property title does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
19
		$this->args  = wp_parse_args( $args, $this->get_default_args() );
0 ignored issues
show
Bug Best Practice introduced by
The property args does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
20
21
		// Deprecated argument: 'std'
22
		if ( ! empty( $this->args['std'] ) && empty( $this->args['default'] ) ) {
23
			$this->args['default'] = $this->args['std'];
24
			_deprecated_argument( 'CMB_Field', '0.9', "field argument 'std' is deprecated, use 'default' instead" );
25
		}
26
27
		if ( ! empty( $this->args['options'] ) && is_array( reset( $this->args['options'] ) ) ) {
28
			$re_format = array();
29
			foreach ( $this->args['options'] as $option ) {
30
				$re_format[$option['value']] = $option['name'];
31
			}
32
			$this->args['options'] = $re_format;
33
		}
34
35
		// If the field has a custom value populator callback
36
		if ( ! empty( $args['values_callback'] ) )
37
			$this->values = call_user_func( $args['values_callback'], get_the_id() );
0 ignored issues
show
Bug Best Practice introduced by
The property values does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
38
		else
39
			$this->values = $values;
40
41
		$this->value = reset( $this->values );
42
43
	}
44
45
	/**
46
	 * Get the default args for the abstract field.
47
	 * These args are available to all fields.
48
	 *
49
	 * @return array $args
50
	 */
51
	public function get_default_args() {
52
		return apply_filters(
53
			'cmb_field_default_args',
54
			array(
55
				'desc'                => '',
56
				'repeatable'          => false,
57
				'sortable'            => false,
58
				'repeatable_max'      => null,
59
				'show_label'          => false,
60
				'readonly'            => false,
61
				'disabled'            => false,
62
				'default'             => '',
63
				'cols'                => '12',
64
				'style'               => '',
65
				'class'               => '',
66
				'data_delegate'       => null,
67
				'save_callback'       => null,
68
				'string-repeat-field' => __( 'Add New', 'cmb' ),
69
				'string-delete-field' => __( 'Remove Field', 'cmb' ),
70
			),
71
			get_class( $this )
72
		);
73
	}
74
75
	/**
76
	 * Enqueue all scripts required by the field.
77
	 *
78
	 * @uses wp_enqueue_script()
79
	 */
80
	public function enqueue_scripts() {
81
82
		if ( isset( $this->args['sortable'] ) && $this->args['sortable'] )
83
			wp_enqueue_script( 'jquery-ui-sortable' );
84
85
	}
86
87
	/**
88
	 * Enqueue all styles required by the field.
89
	 *
90
	 * @uses wp_enqueue_style()
91
	 */
92
	public function enqueue_styles() {}
93
94
	/**
95
	 * Output the field input ID attribute.
96
	 *
97
	 * If multiple inputs are required for a single field,
98
	 * use the append parameter to add unique identifier.
99
	 *
100
	 * @param  string $append
101
	 * @return null
102
	 */
103
	public function id_attr( $append = null ) {
104
105
		printf( 'id="%s"', esc_attr( $this->get_the_id_attr( $append ) ) );
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->get_the_id_attr($append) targeting CMB_Field::get_the_id_attr() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

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

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

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

Loading history...
106
107
	}
108
109
	/**
110
	 * Output the for attribute for the field.
111
	 *
112
	 *
113
	 *
114
	 * If multiple inputs are required for a single field,
115
	 * use the append parameter to add unique identifier.
116
	 *
117
	 * @param  string $append
118
	 * @return null
119
	 */
120
	public function get_the_id_attr( $append = null ) {
121
122
		$id = $this->id;
123
124
		if ( isset( $this->parent ) ) {
125
			$parent_id = preg_replace( '/cmb\-field\-(\d+|x)/', 'cmb-group-$1', $this->parent->get_the_id_attr() );
126
			$id = $parent_id . '[' . $id . ']';
127
		}
128
129
		$id .= '-cmb-field-' . $this->field_index;
130
131
		if ( ! is_null( $append ) )
132
			$id .= '-' . $append;
133
134
		$id = str_replace( array( '[', ']', '--' ), '-', $id );
135
136
		return $id;
137
138
	}
139
140
	/**
141
	 * Return the field input ID attribute value.
142
	 *
143
	 * If multiple inputs are required for a single field,
144
	 * use the append parameter to add unique identifier.
145
	 *
146
	 * @param  string $append
147
	 * @return string id attribute value.
148
	 */
149
	public function for_attr( $append = null ) {
150
151
		printf( 'for="%s"', esc_attr( $this->get_the_id_attr( $append ) ) );
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->get_the_id_attr($append) targeting CMB_Field::get_the_id_attr() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

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

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

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

Loading history...
152
153
	}
154
155
	public function name_attr( $append = null ) {
156
157
		printf( 'name="%s"', esc_attr( $this->get_the_name_attr( $append ) ) );
158
159
	}
160
161
	public function get_the_name_attr( $append = null ) {
162
163
		$name = str_replace( '[]', '', $this->name );
164
165
		if ( isset( $this->parent ) ) {
166
			$parent_name = preg_replace( '/cmb\-field\-(\d+|x)/', 'cmb-group-$1', $this->parent->get_the_name_attr() );
167
			$name = $parent_name . '[' . $name . ']';
168
		}
169
170
		$name .= "[cmb-field-$this->field_index]";
171
172
		if ( ! is_null( $append ) )
173
			$name .= $append;
174
175
		return $name;
176
177
	}
178
179
	public function class_attr( $classes = '' ) {
180
181
		if ( $classes = implode( ' ', array_map( 'sanitize_html_class', array_filter( array_unique( explode( ' ', $classes . ' ' . $this->args['class'] ) ) ) ) ) ) { ?>
182
183
			class="<?php echo esc_attr( $classes ); ?>"
184
185
		<?php }
186
187
	}
188
189
	/**
190
	 * Get JS Safe ID.
191
	 *
192
	 * For use as a unique field identifier in javascript.
193
	 */
194
	public function get_js_id() {
195
196
		return str_replace( array( '-', '[', ']', '--' ),'_', $this->get_the_id_attr() ); // JS friendly ID
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->get_the_id_attr() targeting CMB_Field::get_the_id_attr() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

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

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

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

Loading history...
197
198
	}
199
200
	public function boolean_attr( $attrs = array() ) {
201
202
		if ( $this->args['readonly'] )
203
			$attrs[] = 'readonly';
204
205
		if ( $this->args['disabled'] )
206
			$attrs[] = 'disabled';
207
208
		$attrs = array_filter( array_unique( $attrs ) );
209
210
		foreach ( $attrs as $attr )
211
			echo esc_html( $attr ) . '="' . esc_attr( $attr ) . '"';
212
213
	}
214
215
	/**
216
	 * Check if this field has a data delegate set
217
	 *
218
	 * @return boolean
219
	 */
220
	public function has_data_delegate() {
221
		return (bool) $this->args['data_delegate'];
222
	}
223
224
	/**
225
	 * Get the array of data from the data delegate
226
	 *
227
	 * @return array mixed
228
	 */
229
	protected function get_delegate_data() {
230
231
		if ( $this->args['data_delegate'] )
232
			return call_user_func_array( $this->args['data_delegate'], array( $this ) );
233
234
		return array();
235
236
	}
237
238
	public function get_value() {
239
	   return ( $this->value || $this->value === '0' ) ? $this->value : $this->args['default'];
240
	}
241
242
	public function &get_values() {
243
		return $this->values;
244
	}
245
246
	public function set_values( array $values ) {
247
248
		$this->values = $values;
0 ignored issues
show
Bug Best Practice introduced by
The property values does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
249
250
		unset( $this->value );
251
252
	}
253
254
	public function parse_save_values() {}
255
256
	public function parse_save_value() {}
257
258
	/**
259
	 * @todo this surely only works for posts
260
	 * @todo why do values need to be passed in, they can already be passed in on construct
261
	 */
262
	public function save( $post_id, $values ) {
263
264
		// Don't save readonly values.
265
		if ( $this->args['readonly'] )
266
			return;
267
268
		$this->values = $values;
0 ignored issues
show
Bug Best Practice introduced by
The property values does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
269
		$this->parse_save_values();
270
271
		// Allow override from args
272
		if ( ! empty( $this->args['save_callback'] ) ) {
273
274
			call_user_func( $this->args['save_callback'], $this->values, $post_id );
275
276
			return;
277
278
		}
279
280
		// If we are not on a post edit screen
281
		if ( ! $post_id )
282
			return;
283
284
		delete_post_meta( $post_id, $this->id );
285
286
		foreach( $this->values as $v ) {
287
288
			$this->value = $v;
289
			$this->parse_save_value();
290
291
			if ( $this->value || $this->value === '0' )
292
				add_post_meta( $post_id, $this->id, $this->value );
293
294
		}
295
	}
296
297
	public function title() {
298
299
		if ( $this->title ) { ?>
300
301
			<div class="field-title">
302
				<label <?php $this->for_attr(); ?>>
303
					<?php echo esc_html( $this->title ); ?>
304
				</label>
305
			</div>
306
307
		<?php }
308
309
	}
310
311
	public function description() {
312
313
		if ( ! empty( $this->args['desc'] ) ) { ?>
314
315
			<div class="cmb_metabox_description">
316
				<?php echo wp_kses_post( $this->args['desc'] ); ?>
317
			</div>
318
319
		<?php }
320
321
	}
322
323
	public function display() {
324
325
		// If there are no values and it's not repeateble, we want to do one with empty string
326
		if ( ! $this->get_values() && ! $this->args['repeatable'] )
327
			$values = array( '' );
328
		else
329
			$values = $this->get_values();
330
331
		$this->title();
332
333
		$this->description();
334
335
		$i = 0;
336
		if( isset( $this->args['type'] ) && $this->args['type'] == 'gmap' ) {
337
			$values = array( $values );
338
		}
339
		foreach ( $values as $key => $value ) {
340
341
			$this->field_index = $i;
342
			$this->value = $value; ?>
343
344
			<div class="field-item" data-class="<?php echo esc_attr( get_class( $this ) ); ?>" style="position: relative; <?php echo esc_attr( $this->args['style'] ); ?>">
345
346
			<?php if ( $this->args['repeatable'] ) : ?>
347
				<button class="cmb-delete-field" title="<?php echo esc_attr( $this->args['string-delete-field'] ); ?>">
348
					<span class="cmb-delete-field-icon">&times;</span>
349
				</button>
350
			<?php endif; ?>
351
352
			<?php $this->html(); ?>
0 ignored issues
show
Bug introduced by
The method html() does not exist on CMB_Field. Since it exists in all sub-types, consider adding an abstract or default implementation to CMB_Field. ( Ignorable by Annotation )

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

352
			<?php $this->/** @scrutinizer ignore-call */ html(); ?>
Loading history...
353
354
			</div>
355
356
		<?php
357
358
			$i++;
359
360
		}
361
362
		// Insert a hidden one if it's repeatable
363
		if ( $this->args['repeatable'] ) {
364
365
			$this->field_index = 'x'; // x used to distinguish hidden fields.
366
			$this->value = ''; ?>
367
368
			<div class="field-item hidden" data-class="<?php echo esc_attr( get_class( $this ) ); ?>" style="position: relative; <?php echo esc_attr( $this->args['style'] ); ?>">
369
370
			<?php if ( $this->args['repeatable'] ) : ?>
371
				<button class="cmb-delete-field" title="<?php echo esc_attr( $this->args['string-delete-field'] ); ?>">
372
					<span class="cmb-delete-field-icon">&times;</span>
373
					<?php echo esc_html( $this->args['string-delete-field'] ); ?>
374
				</button>
375
			<?php endif; ?>
376
377
			<?php $this->html(); ?>
378
379
			</div>
380
381
			<button class="button repeat-field"><?php echo esc_html( $this->args['string-repeat-field'] ); ?></button>
382
383
		<?php }
384
385
	}
386
387
}
388
389
/**
390
 * Standard text field.
391
 *
392
 * @extends CMB_Field
393
 */
394
class CMB_Text_Field extends CMB_Field {
395
396
	public function html() { ?>
397
398
		<input type="text" <?php $this->id_attr(); ?> <?php $this->boolean_attr(); ?> <?php $this->class_attr(); ?> <?php $this->name_attr(); ?> value="<?php echo esc_attr( $this->get_value() ); ?>" />
399
400
	<?php }
401
}
402
403
class CMB_Text_Small_Field extends CMB_Text_Field {
404
405
	public function html() {
406
407
		$this->args['class'] .= ' cmb_text_small';
408
409
		parent::html();
410
411
	}
412
}
413
414
/**
415
 * Field for image upload / file updoad.
416
 *
417
 * @todo ability to set image size (preview image) from caller
418
 */
419
class CMB_File_Field extends CMB_Field {
420
421
	/**
422
	 * Return the default args for the File field.
423
	 *
424
	 * @return array $args
425
	 */
426
	public function get_default_args() {
427
		return array_merge(
428
			parent::get_default_args(),
429
			array(
430
				'library-type' => array( 'video', 'audio', 'text', 'application' )
431
			)
432
		);
433
	}
434
435
	function enqueue_scripts() {
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...
436
437
		global $post_ID;
438
		$post_ID = isset($post_ID) ? (int) $post_ID : 0;
439
440
		parent::enqueue_scripts();
441
442
		wp_enqueue_media( array( 'post' => $post_ID ));
443
		wp_enqueue_script( 'cmb-file-upload', trailingslashit( CMB_URL ) . 'js/file-upload.js', array( 'jquery', 'cmb-scripts' ) );
444
445
	}
446
447
	public function html() {
448
449
		if ( $this->get_value() ) {
450
			$src = wp_mime_type_icon( $this->get_value() );
451
			$size = getimagesize( str_replace( site_url(), ABSPATH, $src ) );
452
			$icon_img = '<img src="' . $src . '" ' . $size[3] . ' />';
0 ignored issues
show
Bug introduced by
Are you sure $src of type false|string can be used in concatenation? ( Ignorable by Annotation )

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

452
			$icon_img = '<img src="' . /** @scrutinizer ignore-type */ $src . '" ' . $size[3] . ' />';
Loading history...
453
		}
454
455
		$data_type = ( ! empty( $this->args['library-type'] ) ? implode( ',', $this->args['library-type'] ) : null );
456
457
		?>
458
459
		<div class="cmb-file-wrap" <?php echo 'data-type="' . esc_attr( $data_type ) . '"'; ?>>
460
461
			<div class="cmb-file-wrap-placeholder"></div>
462
463
			<button class="button cmb-file-upload <?php echo esc_attr( $this->get_value() ) ? 'hidden' : '' ?>">
464
				<?php esc_html_e( 'Add File', 'cmb' ); ?>
465
			</button>
466
467
			<div class="cmb-file-holder type-file <?php echo $this->get_value() ? '' : 'hidden'; ?>">
468
469
				<?php if ( $this->get_value() ) : ?>
470
471
					<?php if ( isset( $icon_img ) ) echo $icon_img; ?>
472
473
					<div class="cmb-file-name">
474
						<strong><?php echo esc_html( basename( get_attached_file( $this->get_value() ) ) ); ?></strong>
0 ignored issues
show
Bug introduced by
It seems like get_attached_file($this->get_value()) can also be of type false; however, parameter $path of basename() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

474
						<strong><?php echo esc_html( basename( /** @scrutinizer ignore-type */ get_attached_file( $this->get_value() ) ) ); ?></strong>
Loading history...
475
					</div>
476
477
				<?php endif; ?>
478
479
			</div>
480
481
			<button class="cmb-remove-file button <?php echo $this->get_value() ? '' : 'hidden'; ?>">
482
				<?php esc_html_e( 'Remove', 'cmb' ); ?>
483
			</button>
484
485
			<input type="hidden"
486
				<?php $this->class_attr( 'cmb-file-upload-input' ); ?>
487
				<?php $this->name_attr(); ?>
488
				value="<?php echo esc_attr( $this->value ); ?>"
489
			/>
490
491
		</div>
492
493
	<?php }
494
495
}
496
497
class CMB_Image_Field extends CMB_File_Field {
498
499
	/**
500
	 * Return the default args for the Image field.
501
	 *
502
	 * @return array $args
503
	 */
504
	public function get_default_args() {
505
		return array_merge(
506
			parent::get_default_args(),
507
			array(
508
			'size' => 'thumbnail',
509
			'library-type' => array( 'image' ),
510
			'show_size' => false
511
			)
512
		);
513
	}
514
515
	public function html() {
516
517
		if ( $this->get_value() )
518
			$image = wp_get_attachment_image_src( $this->get_value(), $this->args['size'], true );
519
520
		// Convert size arg to array of width, height, crop
521
		$size = $this->parse_image_size( $this->args['size'] );
522
523
		// Inline styles
524
		$styles              = sprintf( 'width: %1$dpx; height: %2$dpx; line-height: %2$dpx', intval( $size['width'] ), intval( $size['height'] ) );
525
		$placeholder_styles  = sprintf( 'width: %dpx; height: %dpx;', intval( $size['width'] ) - 8, intval( $size['height'] ) - 8 );
526
527
		$data_type           = ( ! empty( $this->args['library-type'] ) ? implode( ',', $this->args['library-type'] ) : null );
528
529
		?>
530
531
		<div class="cmb-file-wrap" style="<?php echo esc_attr( $styles ); ?>" data-type="<?php echo esc_attr( $data_type ); ?>">
532
533
			<div class="cmb-file-wrap-placeholder" style="<?php echo esc_attr( $placeholder_styles ); ?>">
534
535
				<?php if ( $this->args['show_size'] ) : ?>
536
					<span class="dimensions">
537
						<?php printf( '%dpx &times; %dpx', intval( $size['width'] ), intval( $size['height'] ) ); ?>
538
					</span>
539
				<?php endif; ?>
540
541
			</div>
542
543
			<button class="button cmb-file-upload <?php echo esc_attr( $this->get_value() ) ? 'hidden' : '' ?>" data-nonce="<?php echo wp_create_nonce( 'cmb-file-upload-nonce' ); ?>">
544
				<?php esc_html_e( 'Select', 'cmb' ); ?>
545
			</button>
546
547
			<div class="cmb-file-holder type-img <?php echo $this->get_value() ? '' : 'hidden'; ?>" data-crop="<?php echo (bool) $size['crop']; ?>">
548
549
				<?php if ( ! empty( $image ) ) : ?>
550
					<img src="<?php echo esc_url( $image[0] ); ?>" width="<?php echo intval( $image[1] ); ?>" height="<?php echo intval( $image[2] ); ?>" />
551
				<?php endif; ?>
552
553
			</div>
554
555
			<button class="cmb-remove-file button <?php echo $this->get_value() ? '' : 'hidden'; ?>">
556
				<?php esc_html_e( 'Remove', 'cmb' ); ?>
557
			</button>
558
559
			<input type="hidden"
560
				<?php $this->class_attr( 'cmb-file-upload-input' ); ?>
561
				<?php $this->name_attr(); ?>
562
				value="<?php echo esc_attr( $this->value ); ?>"
563
			/>
564
565
		</div>
566
567
	<?php }
568
569
	/**
570
	 * Parse the size argument to get pixel width, pixel height and crop information.
571
	 *
572
	 * @param  string $size
573
	 * @return array width, height, crop
574
	 */
575
	private function parse_image_size( $size ) {
576
577
		// Handle string for built-in image sizes
578
		if ( is_string( $size ) && in_array( $size, array( 'thumbnail', 'medium', 'large' ) ) ) {
579
			return array(
580
				'width'  => get_option( $size . '_size_w' ),
581
				'height' => get_option( $size . '_size_h' ),
582
				'crop'   => get_option( $size . '_crop' )
583
			);
584
		}
585
586
		// Handle string for additional image sizes
587
		global $_wp_additional_image_sizes;
588
		if ( is_string( $size ) && isset( $_wp_additional_image_sizes[$size] ) ) {
589
			return array(
590
				'width'  => $_wp_additional_image_sizes[$size]['width'],
591
				'height' => $_wp_additional_image_sizes[$size]['height'],
592
				'crop'   => $_wp_additional_image_sizes[$size]['crop']
593
			);
594
		}
595
596
		// Handle default WP size format.
597
		if ( is_array( $size ) && isset( $size[0] ) && isset( $size[1] ) )
598
			$size = array( 'width' => $size[0], 'height' => $size[1] );
599
600
		return wp_parse_args( $size, array(
601
			'width'  => get_option( 'thumbnail_size_w' ),
602
			'height' => get_option( 'thumbnail_size_h' ),
603
			'crop'   => get_option( 'thumbnail_crop' )
604
		) );
605
606
	}
607
608
	/**
609
	 * Ajax callback for outputing an image src based on post data.
610
	 *
611
	 * @return null
612
	 */
613
	static function request_image_ajax_callback() {
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...
614
615
		if ( ! ( isset( $_POST['nonce'] ) && wp_verify_nonce( $_POST['nonce'], 'cmb-file-upload-nonce' ) ) )
616
			return;
617
618
		$id = intval( $_POST['id'] );
619
620
		$size = array(
621
			intval( $_POST['width'] ),
622
			intval( $_POST['height'] ),
623
			'crop' => (bool) $_POST['crop']
624
		);
625
626
		$image = wp_get_attachment_image_src( $id, $size );
0 ignored issues
show
Bug introduced by
$size of type array<integer|string,boolean|integer> is incompatible with the type integer[]|string expected by parameter $size of wp_get_attachment_image_src(). ( Ignorable by Annotation )

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

626
		$image = wp_get_attachment_image_src( $id, /** @scrutinizer ignore-type */ $size );
Loading history...
627
		echo reset( $image );
0 ignored issues
show
Bug introduced by
It seems like $image can also be of type false; however, parameter $array of reset() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

627
		echo reset( /** @scrutinizer ignore-type */ $image );
Loading history...
628
629
		die(); // this is required to return a proper result
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
630
	}
631
632
}
633
add_action( 'wp_ajax_cmb_request_image', array( 'CMB_Image_Field', 'request_image_ajax_callback' ) );
634
635
/**
636
 * Standard text meta box for a URL.
637
 *
638
 */
639
class CMB_Number_Field extends CMB_Field {
640
641
	public function get_default_args() {
642
		return array_merge(
643
			parent::get_default_args(),
644
			array(
645
				'step' => '',
646
			)
647
		);
648
	}
649
650
	public function html() { ?>
651
652
		<input step="<?php echo esc_attr( $this->args['step'] ); ?>" type="number" <?php $this->id_attr(); ?> <?php $this->boolean_attr(); ?> <?php $this->class_attr( 'cmb_text_number code' ); ?> <?php $this->name_attr(); ?> value="<?php echo esc_attr( $this->value ); ?>" />
653
654
	<?php }
655
}
656
657
/**
658
 * Standard text meta box for a URL.
659
 *
660
 */
661
class CMB_URL_Field extends CMB_Field {
662
663
	public function html() { ?>
664
665
		<input type="text" <?php $this->id_attr(); ?> <?php $this->boolean_attr(); ?> <?php $this->class_attr( 'cmb_text_url code' ); ?> <?php $this->name_attr(); ?> value="<?php echo esc_attr( esc_url( $this->value ) ); ?>" />
666
667
	<?php }
668
}
669
670
/**
671
 * Date picker box.
672
 *
673
 */
674
class CMB_Date_Field extends CMB_Field {
675
676
	public function enqueue_scripts() {
677
678
		parent::enqueue_scripts();
679
680
		wp_enqueue_style( 'cmb-jquery-ui', trailingslashit( CMB_URL ) . 'css/vendor/jquery-ui/jquery-ui.css', '1.10.3' );
0 ignored issues
show
Bug introduced by
'1.10.3' of type string is incompatible with the type string[] expected by parameter $deps of wp_enqueue_style(). ( Ignorable by Annotation )

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

680
		wp_enqueue_style( 'cmb-jquery-ui', trailingslashit( CMB_URL ) . 'css/vendor/jquery-ui/jquery-ui.css', /** @scrutinizer ignore-type */ '1.10.3' );
Loading history...
681
682
		wp_enqueue_script( 'cmb-datetime', trailingslashit( CMB_URL ) . 'js/field.datetime.js', array( 'jquery', 'jquery-ui-core', 'jquery-ui-datepicker', 'cmb-scripts' ) );
683
	}
684
685
	public function html() { ?>
686
687
		<input <?php $this->id_attr(); ?> <?php $this->boolean_attr(); ?> <?php $this->class_attr( 'cmb_text_small cmb_datepicker' ); ?> type="text" <?php $this->name_attr(); ?> value="<?php echo esc_attr( $this->value ); ?>" />
688
689
	<?php }
690
}
691
692
class CMB_Time_Field extends CMB_Field {
693
694
	public function enqueue_scripts() {
695
696
		parent::enqueue_scripts();
697
698
		wp_enqueue_style( 'cmb-jquery-ui', trailingslashit( CMB_URL ) . 'css/vendor/jquery-ui/jquery-ui.css', '1.10.3' );
0 ignored issues
show
Bug introduced by
'1.10.3' of type string is incompatible with the type string[] expected by parameter $deps of wp_enqueue_style(). ( Ignorable by Annotation )

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

698
		wp_enqueue_style( 'cmb-jquery-ui', trailingslashit( CMB_URL ) . 'css/vendor/jquery-ui/jquery-ui.css', /** @scrutinizer ignore-type */ '1.10.3' );
Loading history...
699
700
		wp_enqueue_script( 'cmb-timepicker', trailingslashit( CMB_URL ) . 'js/jquery.timePicker.min.js', array( 'jquery', 'cmb-scripts' ) );
701
		wp_enqueue_script( 'cmb-datetime', trailingslashit( CMB_URL ) . 'js/field.datetime.js', array( 'jquery', 'jquery-ui-core', 'jquery-ui-datepicker', 'cmb-scripts' ) );
702
	}
703
704
	public function html() { ?>
705
706
		<input <?php $this->id_attr(); ?> <?php $this->boolean_attr(); ?> <?php $this->class_attr( 'cmb_text_small cmb_timepicker' ); ?> type="text" <?php $this->name_attr(); ?> value="<?php echo esc_attr( $this->value ); ?>"/>
707
708
	<?php }
709
710
}
711
712
/**
713
 * Date picker for date only (not time) box.
714
 *
715
 */
716
class CMB_Date_Timestamp_Field extends CMB_Field {
717
718
	public function enqueue_scripts() {
719
720
		parent::enqueue_scripts();
721
722
		wp_enqueue_style( 'cmb-jquery-ui', trailingslashit( CMB_URL ) . 'css/vendor/jquery-ui/jquery-ui.css', '1.10.3' );
0 ignored issues
show
Bug introduced by
'1.10.3' of type string is incompatible with the type string[] expected by parameter $deps of wp_enqueue_style(). ( Ignorable by Annotation )

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

722
		wp_enqueue_style( 'cmb-jquery-ui', trailingslashit( CMB_URL ) . 'css/vendor/jquery-ui/jquery-ui.css', /** @scrutinizer ignore-type */ '1.10.3' );
Loading history...
723
724
		wp_enqueue_script( 'cmb-timepicker', trailingslashit( CMB_URL ) . 'js/jquery.timePicker.min.js', array( 'jquery', 'cmb-scripts' ) );
725
		wp_enqueue_script( 'cmb-datetime', trailingslashit( CMB_URL ) . 'js/field.datetime.js', array( 'jquery', 'jquery-ui-core', 'jquery-ui-datepicker', 'cmb-scripts' ) );
726
727
	}
728
729
	public function html() { ?>
730
731
		<input <?php $this->id_attr(); ?> <?php $this->boolean_attr(); ?> <?php $this->class_attr( 'cmb_text_small cmb_datepicker' ); ?> type="text" <?php $this->name_attr(); ?>  value="<?php echo $this->value ? esc_attr( date( 'm\/d\/Y', $this->value ) ) : '' ?>" />
732
733
	<?php }
734
735
	public function parse_save_values() {
736
737
		foreach( $this->values as &$value )
738
			$value = strtotime( $value );
739
740
		sort( $this->values );
741
742
	}
743
744
}
745
746
/**
747
 * Date picker for date and time (seperate fields) box.
748
 *
749
 */
750
class CMB_Datetime_Timestamp_Field extends CMB_Field {
751
752
	public function enqueue_scripts() {
753
754
		parent::enqueue_scripts();
755
756
		wp_enqueue_style( 'cmb-jquery-ui', trailingslashit( CMB_URL ) . 'css/vendor/jquery-ui/jquery-ui.css', '1.10.3' );
0 ignored issues
show
Bug introduced by
'1.10.3' of type string is incompatible with the type string[] expected by parameter $deps of wp_enqueue_style(). ( Ignorable by Annotation )

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

756
		wp_enqueue_style( 'cmb-jquery-ui', trailingslashit( CMB_URL ) . 'css/vendor/jquery-ui/jquery-ui.css', /** @scrutinizer ignore-type */ '1.10.3' );
Loading history...
757
758
		wp_enqueue_script( 'cmb-timepicker', trailingslashit( CMB_URL ) . 'js/jquery.timePicker.min.js', array( 'jquery', 'cmb-scripts' ) );
759
		wp_enqueue_script( 'cmb-datetime', trailingslashit( CMB_URL ) . 'js/field.datetime.js', array( 'jquery', 'jquery-ui-core', 'jquery-ui-datepicker', 'cmb-scripts' ) );
760
	}
761
762
	public function html() { ?>
763
764
		<input <?php $this->id_attr('date'); ?> <?php $this->boolean_attr(); ?> <?php $this->class_attr( 'cmb_text_small cmb_datepicker' ); ?> type="text" <?php $this->name_attr( '[date]' ); ?>  value="<?php echo $this->value ? esc_attr( date( 'm\/d\/Y', $this->value ) ) : '' ?>" />
765
		<input <?php $this->id_attr('time'); ?> <?php $this->boolean_attr(); ?> <?php $this->class_attr( 'cmb_text_small cmb_timepicker' ); ?> type="text" <?php $this->name_attr( '[time]' ); ?> value="<?php echo $this->value ? esc_attr( date( 'h:i A', $this->value ) ) : '' ?>" />
766
767
	<?php }
768
769
	public function parse_save_values() {
770
771
		// Convert all [date] and [time] values to a unix timestamp.
772
		// If date is empty, assume delete. If time is empty, assume 00:00.
773
		foreach( $this->values as $key => &$value ) {
774
			if ( empty( $value['date'] ) )
775
				unset( $this->values[$key] );
776
			else
777
				$value = strtotime( $value['date'] . ' ' . $value['time'] );
778
		}
779
780
		$this->values = array_filter( $this->values );
0 ignored issues
show
Bug Best Practice introduced by
The property values does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
781
		sort( $this->values );
782
783
		parent::parse_save_values();
784
785
	}
786
787
}
788
789
/**
790
 * Standard text field.
791
 *
792
 * Args:
793
 *  - int "rows" - number of rows in the <textarea>
794
 */
795
class CMB_Textarea_Field extends CMB_Field {
796
797
	public function html() { ?>
798
799
		<textarea <?php $this->id_attr(); ?> <?php $this->boolean_attr(); ?> <?php $this->class_attr(); ?> rows="<?php echo ! empty( $this->args['rows'] ) ? esc_attr( $this->args['rows'] ) : 4; ?>" <?php $this->name_attr(); ?>><?php echo esc_html( $this->value ); ?></textarea>
800
801
	<?php }
802
803
}
804
805
/**
806
 * Code style text field.
807
 *
808
 * Args:
809
 *  - int "rows" - number of rows in the <textarea>
810
 */
811
class CMB_Textarea_Field_Code extends CMB_Textarea_Field {
812
813
	public function html() {
814
815
		$this->args['class'] .= ' code';
816
817
		parent::html();
818
819
	}
820
821
}
822
823
/**
824
 *  Colour picker
825
 *
826
 */
827
class CMB_Color_Picker extends CMB_Field {
828
829
	public function enqueue_scripts() {
830
831
		parent::enqueue_scripts();
832
833
		wp_enqueue_script( 'cmb-colorpicker', trailingslashit( CMB_URL ) . 'js/field.colorpicker.js', array( 'jquery', 'wp-color-picker', 'cmb-scripts' ) );
834
		wp_enqueue_style( 'wp-color-picker' );
835
	}
836
837
	public function html() { ?>
838
839
		<input <?php $this->id_attr(); ?> <?php $this->boolean_attr(); ?> <?php $this->class_attr( 'cmb_colorpicker cmb_text_small' ); ?> type="text" <?php $this->name_attr(); ?> value="<?php echo esc_attr( $this->get_value() ); ?>" />
840
841
	<?php }
842
843
}
844
845
/**
846
 * Standard radio field.
847
 *
848
 * Args:
849
 *  - bool "inline" - display the radio buttons inline
850
 */
851
class CMB_Radio_Field extends CMB_Field {
852
853
	/**
854
	 * Return the default args for the Radio input field.
855
	 *
856
	 * @return array $args
857
	 */
858
	public function get_default_args() {
859
		return array_merge(
860
			parent::get_default_args(),
861
			array(
862
				'options' => array(),
863
			)
864
		);
865
	}
866
867
	public function html() {
868
869
		if ( $this->has_data_delegate() )
870
			$this->args['options'] = $this->get_delegate_data(); ?>
0 ignored issues
show
Bug Best Practice introduced by
The property args does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
871
872
			<?php foreach ( $this->args['options'] as $key => $value ): ?>
873
874
			<input <?php $this->id_attr( 'item-' . $key ); ?> <?php $this->boolean_attr(); ?> <?php $this->class_attr(); ?> type="radio" <?php $this->name_attr(); ?>  value="<?php echo esc_attr( $key ); ?>" <?php checked( $key, $this->get_value() ); ?> />
875
			<label <?php $this->for_attr( 'item-' . $key ); ?> style="margin-right: 20px;">
876
				<?php echo esc_html( $value ); ?>
877
			</label>
878
879
			<?php endforeach; ?>
880
881
	<?php }
882
883
}
884
885
/**
886
 * Standard checkbox group field.
887
 *
888
 * Args:
889
 *  - bool "inline" - display the checkbox buttons inline
890
 */
891
class CMB_Checkbox_Group_Field extends CMB_Field {
892
893
	/**
894
	 * Return the default args for the Radio input field.
895
	 *
896
	 * @return array $args
897
	 */
898
	public function get_default_args() {
899
		return array_merge(
900
				parent::get_default_args(),
901
				array(
902
						'options' => array(),
903
				)
904
				);
905
	}
906
907
	public function html() {
908
909
		if ( $this->has_data_delegate() )
910
			$this->args['options'] = $this->get_delegate_data(); ?>
0 ignored issues
show
Bug Best Practice introduced by
The property args does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
911
912
			<?php foreach ( $this->args['options'] as $key => $value ): ?>
913
			<div class="cmb-cell-2">
914
			<input <?php $this->id_attr( 'item-' . $key ); ?> <?php $this->boolean_attr(); ?> <?php $this->class_attr(); ?> type="checkbox" <?php $this->name_attr(); ?>[]  value="<?php echo esc_attr( $key ); ?>" <?php checked( $key, $this->get_value() ); ?> />
915
			<label <?php $this->for_attr( 'item-' . $key ); ?> style="margin-right: 20px;">
916
				<?php echo esc_html( $value ); ?>
917
			</label>
918
			</div>
919
			<?php endforeach; ?>
920
921
	<?php }
922
923
	public function parse_save_values(){
924
		$this->values = array( $this->values );
0 ignored issues
show
Bug Best Practice introduced by
The property values does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
925
	}
926
927
}
928
929
/**
930
 * Standard checkbox field.
931
 *
932
 */
933
class CMB_Checkbox extends CMB_Field {
934
935
	public function html() { ?>
936
937
		<input <?php $this->id_attr(); ?> <?php $this->boolean_attr(); ?> <?php $this->class_attr(); ?> type="checkbox" <?php $this->name_attr(); ?>  value="1" <?php checked( $this->get_value() ); ?> />
938
939
	<?php }
940
941
}
942
943
944
/**
945
 * Standard title used as a splitter.
946
 *
947
 */
948
class CMB_Title extends CMB_Field {
949
950
	public function title() {
951
		?>
952
953
		<div class="field-title">
954
			<h3 <?php $this->class_attr(); ?>>
955
				<?php echo esc_html( $this->title ); ?>
956
			</h3>
957
		</div>
958
959
		<?php
960
961
	}
962
963
	public function html() {}
964
965
}
966
967
/**
968
 * wysiwyg field.
969
 *
970
 */
971
class CMB_wysiwyg extends CMB_Field {
972
973
	/**
974
	 * Return the default args for the WYSIWYG field.
975
	 *
976
	 * @return array $args
977
	 */
978
	public function get_default_args() {
979
		return array_merge(
980
			parent::get_default_args(),
981
			array(
982
				'options' => array(),
983
			)
984
		);
985
	}
986
987
	function enqueue_scripts() {
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...
988
989
		parent::enqueue_scripts();
990
991
		wp_enqueue_script( 'cmb-wysiwyg', trailingslashit( CMB_URL ) . 'js/field-wysiwyg.js', array( 'jquery', 'cmb-scripts' ) );
992
	}
993
994
	public function html() {
995
996
		$id   = $this->get_the_id_attr();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $id is correct as $this->get_the_id_attr() targeting CMB_Field::get_the_id_attr() 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...
997
		$name = $this->get_the_name_attr();
998
999
		$field_id = $this->get_js_id();
1000
1001
		printf( '<div class="cmb-wysiwyg" data-id="%s" data-name="%s" data-field-id="%s">', $id, $name, $field_id );
1002
1003
		if ( $this->is_placeholder() ) 	{
1004
1005
			// For placeholder, output the markup for the editor in a JS var.
1006
			ob_start();
1007
			$this->args['options']['textarea_name'] = 'cmb-placeholder-name-' . $field_id;
0 ignored issues
show
Bug Best Practice introduced by
The property args does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
1008
			wp_editor( '', 'cmb-placeholder-id-' . $field_id, $this->args['options'] );
1009
			$editor = ob_get_clean();
1010
			$editor = str_replace( array( "\n", "\r" ), "", $editor );
1011
			$editor = str_replace( array( "'" ), '"', $editor );
1012
1013
			?>
1014
1015
			<script>
1016
				if ( 'undefined' === typeof( cmb_wysiwyg_editors ) )
1017
					var cmb_wysiwyg_editors = {};
1018
				cmb_wysiwyg_editors.<?php echo $field_id; ?> = '<?php echo $editor; ?>';
1019
			</script>
1020
1021
			<?php
1022
1023
		} else {
1024
1025
			$this->args['options']['textarea_name'] = $name;
1026
			echo wp_editor( $this->get_value(), $id, $this->args['options'] );
0 ignored issues
show
Bug introduced by
Are you sure the usage of wp_editor($this->get_val...$this->args['options']) is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

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

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

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

Loading history...
1027
1028
		}
1029
1030
		echo '</div>';
1031
1032
	}
1033
1034
	/**
1035
	 * Check if this is a placeholder field.
1036
	 * Either the field itself, or because it is part of a repeatable group.
1037
	 *
1038
	 * @return bool
1039
	 */
1040
	public function is_placeholder() {
1041
1042
		if ( isset( $this->parent ) && ! is_int( $this->parent->field_index ) )
1043
			return true;
1044
1045
		else return ! is_int( $this->field_index );
1046
1047
	}
1048
1049
}
1050
1051
/**
1052
 * Standard select field.
1053
 *
1054
 * @supports "data_delegate"
1055
 * @args
1056
 *     'options'     => array Array of options to show in the select, optionally use data_delegate instead
1057
 *     'allow_none'   => bool|string Allow no option to be selected (will place a "None" at the top of the select)
1058
 *     'multiple'     => bool whether multiple can be selected
1059
 */
1060
class CMB_Select extends CMB_Field {
1061
1062
	public function __construct() {
1063
1064
		$args = func_get_args();
1065
1066
		call_user_func_array( array( 'parent', '__construct' ), $args );
1067
1068
	}
1069
1070
	/**
1071
	 * Return the default args for the Select field.
1072
	 *
1073
	 * @return array $args
1074
	 */
1075
	public function get_default_args() {
1076
		return array_merge(
1077
			parent::get_default_args(),
1078
			array(
1079
				'options'         => array(),
1080
				'multiple'        => false,
1081
				'select2_options' => array(),
1082
				'allow_none'      => false,
1083
			)
1084
		);
1085
	}
1086
1087
	public function parse_save_values(){
1088
1089
		if ( isset( $this->parent ) && isset( $this->args['multiple'] ) && $this->args['multiple'] )
1090
			$this->values = array( $this->values );
0 ignored issues
show
Bug Best Practice introduced by
The property values does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
1091
1092
	}
1093
1094
	public function get_options() {
1095
1096
		if ( $this->has_data_delegate() )
1097
			$this->args['options'] = $this->get_delegate_data();
0 ignored issues
show
Bug Best Practice introduced by
The property args does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
1098
1099
		return $this->args['options'];
1100
	}
1101
1102
	public function enqueue_scripts() {
1103
1104
		parent::enqueue_scripts();
1105
1106
		global $pagenow, $typenow;
1107
1108
		$no_enqueue = array(
1109
			'product',
1110
			'shop_order',
1111
			'shop_coupon',
1112
			'shop_subscription',
1113
			'wishlist',
1114
			'wc_membership_plan',
1115
			'wc_user_membership',
1116
			'wc_product_tab',
1117
			'wc_product_retailer'
1118
		);
1119
1120
		if ( ! in_array( $typenow, $no_enqueue ) ) {
1121
			wp_enqueue_script( 'select2', trailingslashit( CMB_URL ) . 'js/vendor/select2/select2.js', array( 'jquery' ) );
1122
		}
1123
1124
		wp_enqueue_script( 'field-select', trailingslashit( CMB_URL ) . 'js/field.select.js', array( 'jquery', 'select2', 'cmb-scripts' ) );
1125
	}
1126
1127
	public function enqueue_styles() {
1128
1129
		parent::enqueue_styles();
1130
1131
		wp_enqueue_style( 'select2', trailingslashit( CMB_URL ) . 'js/vendor/select2/select2.css' );
1132
	}
1133
1134
	public function html() {
1135
1136
		if ( $this->has_data_delegate() )
1137
			$this->args['options'] = $this->get_delegate_data();
0 ignored issues
show
Bug Best Practice introduced by
The property args does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
1138
1139
		$this->output_field();
1140
1141
		$this->output_script();
1142
1143
	}
1144
1145
	public function output_field() {
1146
1147
		$val = (array) $this->get_value();
1148
1149
		$name = $this->get_the_name_attr();
1150
		$name .= ! empty( $this->args['multiple'] ) ? '[]' : null;
1151
1152
		$none = is_string( $this->args['allow_none'] ) ? $this->args['allow_none'] : __( 'None', 'cmb' );
1153
1154
		?>
1155
1156
		<select
1157
			<?php $this->id_attr(); ?>
1158
			<?php $this->boolean_attr(); ?>
1159
			<?php printf( 'name="%s"', esc_attr( $name ) ); ?>
1160
			<?php printf( 'data-field-id="%s" ', esc_attr( $this->get_js_id() ) ); ?>
1161
			<?php echo ! empty( $this->args['multiple'] ) ? 'multiple' : '' ?>
1162
			<?php $this->class_attr( 'cmb_select' ); ?>
1163
			style="width: 100%"
1164
		>
1165
1166
			<?php if ( $this->args['allow_none'] ) : ?>
1167
				<option value=""><?php echo $none; ?></option>
1168
			<?php endif; ?>
1169
1170
			<?php foreach ( $this->args['options'] as $value => $name ): ?>
1171
			   <option <?php selected( in_array( $value, $val ) ) ?> value="<?php echo esc_attr( $value ); ?>"><?php echo esc_html( $name ); ?></option>
1172
			<?php endforeach; ?>
1173
1174
		</select>
1175
1176
		<?php
1177
	}
1178
1179
	public function output_script() {
1180
1181
		$options = wp_parse_args( $this->args['select2_options'], array(
1182
			'placeholder' => __( 'Type to search', 'cmb' ),
1183
			'allowClear'  => true,
1184
		) );
1185
1186
		?>
1187
1188
		<script type="text/javascript">
1189
1190
			(function($) {
1191
1192
				var options = <?php echo  json_encode( $options ); ?>
1193
1194
				if ( 'undefined' === typeof( window.cmb_select_fields ) )
1195
					window.cmb_select_fields = {};
1196
1197
				var id = <?php echo json_encode( $this->get_js_id() ); ?>;
1198
				window.cmb_select_fields[id] = options;
1199
1200
			})( jQuery );
1201
1202
		</script>
1203
1204
		<?php
1205
	}
1206
1207
}
1208
1209
class CMB_Taxonomy extends CMB_Select {
1210
1211
	/**
1212
	 * Return the default args for the Taxonomy select field.
1213
	 *
1214
	 * @return array $args
1215
	 */
1216
	public function get_default_args() {
1217
		return array_merge(
1218
			parent::get_default_args(),
1219
			array(
1220
				'taxonomy'   => '',
1221
				'hide_empty' => false,
1222
			)
1223
		);
1224
	}
1225
1226
1227
	public function __construct() {
1228
1229
		$args = func_get_args();
1230
1231
		call_user_func_array( array( 'parent', '__construct' ), $args );
1232
1233
		$this->args['data_delegate'] = array( $this, 'get_delegate_data' );
0 ignored issues
show
Bug Best Practice introduced by
The property args does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
1234
1235
	}
1236
1237
	public function get_delegate_data() {
1238
1239
		$terms = $this->get_terms();
1240
1241
		if ( is_wp_error( $terms ) ) {
1242
			return array();
1243
		}
1244
1245
		$term_options = array();
1246
1247
		foreach ( $terms as $term )
1248
			$term_options[$term->term_id] = $term->name;
1249
1250
		return $term_options;
1251
1252
	}
1253
1254
	private function get_terms() {
1255
1256
		return get_terms( $this->args['taxonomy'], array( 'hide_empty' => $this->args['hide_empty'] ) );
1257
1258
	}
1259
1260
}
1261
1262
/**
1263
 * Post Select field.
1264
 *
1265
 * @supports "data_delegate"
1266
 * @args
1267
 *     'options'     => array Array of options to show in the select, optionally use data_delegate instead
1268
 *     'allow_none'   => bool Allow no option to be selected (will palce a "None" at the top of the select)
1269
 *     'multiple'     => bool whether multiple can be selected
1270
 */
1271
class CMB_Post_Select extends CMB_Select {
1272
1273
	public function __construct() {
1274
1275
		$args = func_get_args();
1276
1277
		call_user_func_array( array( 'parent', '__construct' ), $args );
1278
1279
		if ( ! $this->args['use_ajax'] ) {
1280
1281
			$this->args['data_delegate'] = array( $this, 'get_delegate_data' );
0 ignored issues
show
Bug Best Practice introduced by
The property args does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
1282
1283
		}
1284
1285
		}
1286
1287
	/**
1288
	 * Return the default args for the Post select field.
1289
	 *
1290
	 * @return array $args
1291
	 */
1292
	public function get_default_args() {
1293
		return array_merge(
1294
			parent::get_default_args(),
1295
			array(
1296
				'query'    => array(),
1297
				'use_ajax' => false,
1298
				'multiple' => false,
1299
			)
1300
		);
1301
	}
1302
1303
	public function get_delegate_data() {
1304
1305
		$data = array();
1306
1307
		foreach ( $this->get_posts() as $post_id )
1308
			$data[$post_id] = get_the_title( $post_id );
1309
1310
		return $data;
1311
1312
	}
1313
1314
	private function get_posts() {
1315
1316
		$this->args['query']['fields'] = 'ids';
0 ignored issues
show
Bug Best Practice introduced by
The property args does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
1317
		$query = new WP_Query( $this->args['query'] );
1318
1319
		return isset( $query->posts ) ? $query->posts : array();
1320
1321
	}
1322
1323
	public function parse_save_value() {
1324
1325
		// AJAX multi select2 data is submitted as a string of comma separated post IDs.
1326
		// If empty, set to false instead of empty array to ensure the meta entry is deleted.
1327
		if ( $this->args['use_ajax'] && $this->args['multiple'] ) {
1328
			$this->value = ( ! empty( $this->value ) ) ? explode( ',', $this->value ) : false;
1329
		}
1330
1331
	}
1332
1333
	public function output_field() {
1334
1335
		// If AJAX, must use input type not standard select.
1336
		if ( $this->args['use_ajax'] ) :
1337
1338
			?>
1339
1340
			<input
1341
				<?php $this->id_attr(); ?>
1342
				<?php printf( 'value="%s" ', esc_attr( implode( ',' , (array) $this->value ) ) ); ?>
1343
				<?php printf( 'name="%s"', esc_attr( $this->get_the_name_attr() ) ); ?>
1344
				<?php printf( 'data-field-id="%s" ', esc_attr( $this->get_js_id() ) ); ?>
1345
				<?php $this->boolean_attr(); ?>
1346
				class="cmb_select"
1347
				style="width: 100%"
1348
			/>
1349
1350
			<?php
1351
1352
		else :
1353
1354
			parent::output_field();
1355
1356
		endif;
1357
1358
	}
1359
1360
	public function output_script() {
1361
1362
		parent::output_script();
1363
1364
		?>
1365
1366
		<script type="text/javascript">
1367
1368
			(function($) {
1369
1370
				if ( 'undefined' === typeof( window.cmb_select_fields ) )
1371
					return false;
1372
1373
				// Get options for this field so we can modify it.
1374
				var id = <?php echo json_encode( $this->get_js_id() ); ?>;
1375
				var options = window.cmb_select_fields[id];
1376
1377
				<?php if ( $this->args['use_ajax'] && $this->args['multiple'] ) : ?>
1378
					// The multiple setting is required when using ajax (because an input field is used instead of select)
1379
					options.multiple = true;
1380
				<?php endif; ?>
1381
1382
				<?php if ( $this->args['use_ajax'] && ! empty( $this->value ) ) : ?>
1383
1384
					options.initSelection = function( element, callback ) {
1385
1386
						var data = [];
1387
1388
						<?php if ( $this->args['multiple'] ) : ?>
1389
1390
							<?php foreach ( (array) $this->value as $post_id ) : ?>
1391
								data.push( <?php echo json_encode( array( 'id' => $post_id, 'text' => html_entity_decode( get_the_title( $post_id ) ) ) ); ?> );
1392
							<?php endforeach; ?>
1393
1394
						<?php else : ?>
1395
1396
							data = <?php echo json_encode( array( 'id' => $this->value, 'text' => html_entity_decode( get_the_title( $this->get_value() ) ) ) ); ?>;
1397
1398
						<?php endif; ?>
1399
1400
						callback( data );
1401
1402
					};
1403
1404
				<?php endif; ?>
1405
1406
				<?php if ( $this->args['use_ajax'] ) : ?>
1407
1408
					<?php $this->args['query']['fields'] = 'ids'; ?>
0 ignored issues
show
Bug Best Practice introduced by
The property args does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
1409
1410
					var ajaxData = {
1411
						action  : 'cmb_post_select',
1412
						post_id : '<?php echo intval( get_the_id() ); ?>', // Used for user capabilty check.
1413
						nonce   : <?php echo json_encode( wp_create_nonce( 'cmb_select_field' ) ); ?>,
1414
						query   : <?php echo json_encode( $this->args['query'] ); ?>
1415
					};
1416
1417
					options.ajax = {
1418
						url: <?php echo json_encode( esc_url( admin_url( 'admin-ajax.php' ) ) ); ?>,
1419
						type: 'POST',
1420
						dataType: 'json',
1421
						data: function( term, page ) {
1422
							ajaxData.query.s = term;
1423
							ajaxData.query.paged = page;
1424
							return ajaxData;
1425
						},
1426
						results : function( results, page ) {
1427
							var postsPerPage = ajaxData.query.posts_per_page = ( 'posts_per_page' in ajaxData.query ) ? ajaxData.query.posts_per_page : ( 'showposts' in ajaxData.query ) ? ajaxData.query.showposts : 10;
1428
							var isMore = ( page * postsPerPage ) < results.total;
1429
							return { results: results.posts, more: isMore };
1430
						}
1431
					}
1432
1433
				<?php endif; ?>
1434
1435
			})( jQuery );
1436
1437
		</script>
1438
1439
		<?php
1440
	}
1441
1442
}
1443
1444
// TODO this should be in inside the class
1445
function cmb_ajax_post_select() {
1446
1447
	$post_id = ! empty( $_POST['post_id'] ) ? intval( $_POST['post_id'] ) : false;
1448
	$nonce   = ! empty( $_POST['nonce'] ) ? $_POST['nonce'] : false;
1449
	$args    = ! empty( $_POST['query'] ) ? $_POST['query'] : array();
1450
1451
	if ( ! $nonce || ! wp_verify_nonce( $nonce, 'cmb_select_field' ) || ! current_user_can( 'edit_post', $post_id ) ) {
1452
		echo json_encode( array( 'total' => 0, 'posts' => array() ) );
1453
		exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
1454
	}
1455
1456
	$args['fields'] = 'ids'; // Only need to retrieve post IDs.
1457
1458
	$query = new WP_Query( $args );
1459
1460
	$json = array( 'total' => $query->found_posts, 'posts' => array() );
1461
1462
	foreach ( $query->posts as $post_id ) {
1463
		array_push( $json['posts'], array( 'id' => $post_id, 'text' => html_entity_decode( get_the_title( $post_id ) ) ) );
1464
	}
1465
1466
	echo json_encode( $json );
1467
1468
	exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
1469
1470
}
1471
add_action( 'wp_ajax_cmb_post_select', 'cmb_ajax_post_select' );
1472
1473
/**
1474
 * Field to group child fieids
1475
 * pass $args[fields] array for child fields
1476
 * pass $args['repeatable'] for cloing all child fields (set)
1477
 *
1478
 * @todo remove global $post reference, somehow
1479
 */
1480
class CMB_Group_Field extends CMB_Field {
1481
1482
	static $added_js;
1483
	private $fields = array();
1484
1485
	function __construct() {
1486
1487
		$args = func_get_args(); // you can't just put func_get_args() into a function as a parameter
1488
		call_user_func_array( array( 'parent', '__construct' ), $args );
1489
1490
		if ( ! empty( $this->args['fields'] ) ) {
1491
			foreach ( $this->args['fields'] as $f ) {
1492
1493
				$class = _cmb_field_class_for_type( $f['type'] );
1494
				$this->add_field( new $class( $f['id'], $f['name'], array(), $f ) );
1495
1496
			}
1497
		}
1498
1499
	}
1500
1501
	/**
1502
	 * Return the default args for the Group field.
1503
	 *
1504
	 * @return array $args
1505
	 */
1506
	public function get_default_args() {
1507
		return array_merge(
1508
			parent::get_default_args(),
1509
			array(
1510
				'fields'              => array(),
1511
				'string-repeat-field' => __( 'Add New Group', 'cmb' ),
1512
				'string-delete-field' => __( 'Remove Group', 'cmb' ),
1513
			)
1514
		);
1515
	}
1516
1517
	public function enqueue_scripts() {
1518
1519
		parent::enqueue_scripts();
1520
1521
		foreach ( $this->args['fields'] as $f ) {
1522
			$class = _cmb_field_class_for_type( $f['type'] );
1523
			$field = new $class( '', '', array(), $f );
1524
			$field->enqueue_scripts();
1525
		}
1526
1527
	}
1528
1529
	public function enqueue_styles() {
1530
1531
		parent::enqueue_styles();
1532
1533
		foreach ( $this->args['fields'] as $f ) {
1534
			$class = _cmb_field_class_for_type( $f['type'] );
1535
			$field = new $class( '', '', array(), $f );
1536
			$field->enqueue_styles();
1537
		}
1538
1539
	}
1540
1541
	public function display() {
1542
1543
		global $post;
1544
1545
		$field = $this->args;
1546
		$values = $this->get_values();
1547
1548
		$this->title();
1549
		$this->description();
1550
1551
		if ( ! $this->args['repeatable'] && empty( $values ) ) {
1552
			$values = array( null );
1553
		}
1554
1555
		if ( $values ) {
1556
1557
			$i = 0;
1558
			foreach ( $values as $value ) {
1559
1560
				$this->field_index = $i;
1561
				$this->value = $value;
1562
1563
				?>
1564
1565
				<div class="field-item" data-class="<?php echo esc_attr( get_class($this) ) ?>" style="<?php echo esc_attr( $this->args['style'] ); ?>">
1566
					<?php $this->html(); ?>
1567
				</div>
1568
1569
				<?php
1570
1571
				$i++;
1572
1573
			}
1574
1575
		}
1576
1577
		if ( $this->args['repeatable'] ) {
1578
1579
			$this->field_index = 'x'; // x used to distinguish hidden fields.
1580
			$this->value = '';
1581
1582
			?>
1583
1584
				<div class="field-item hidden" data-class="<?php echo esc_attr( get_class( $this ) ); ?>" style="<?php echo esc_attr( $this->args['style'] ); ?>">
1585
					<?php $this->html(); ?>
1586
				</div>
1587
1588
				<?php
1589
				$button_name = 'Group';
1590
				if(isset($this->args['single_name'])){
1591
					$button_name = $this->args['single_name'];
1592
				}?>
1593
				<button class="button repeat-field">
1594
					Add New <?php echo $button_name; ?>
1595
				</button>
1596
1597
		<?php }
1598
1599
	}
1600
1601
	public function html() {
1602
1603
		$fields = &$this->get_fields();
1604
		$value  = $this->get_value();
1605
1606
		// Reset all field values.
1607
		foreach ( $fields as $field ) {
1608
			$field->set_values( array() );
1609
		}
1610
1611
		// Set values for this field.
1612
		if ( ! empty( $value ) ) {
1613
			foreach ( $value as $field_id => $field_value ) {
1614
				$field_value = ( ! empty( $field_value ) ) ? $field_value : array();
1615
				if ( ! empty( $fields[$field_id] ) ) {
1616
					$fields[$field_id]->set_values( (array) $field_value );
1617
				}
1618
			}
1619
		}
1620
1621
		?>
1622
1623
		<?php if ( $this->args['repeatable'] ) : ?>
1624
1625
1626
			<?php
1627
			$button_name = 'Group';
1628
			if(isset($this->args['single_name'])){
1629
				$button_name = $this->args['single_name'];
1630
			}?>
1631
1632
			<button class="cmb-collapse-field">
1633
				<span class="cmb-collapse-field-icon down">&darr;</span>
1634
			</button>
1635
			<button class="cmb-delete-field">
1636
				<span class="cmb-delete-field-icon ">&times;</span>
1637
				Remove <?php echo $button_name; ?>
1638
			</button>
1639
		<?php endif; ?>
1640
1641
		<?php CMB_Meta_Box::layout_fields( $fields ); ?>
1642
1643
	<?php }
1644
1645
	public function parse_save_values() {
1646
1647
		$fields = &$this->get_fields();
1648
		$values = &$this->get_values();
1649
1650
		foreach ( $values as &$group_value ) {
1651
			foreach ( $group_value as $field_id => &$field_value ) {
1652
1653
				if ( ! isset( $fields[$field_id] ) ) {
1654
					$field_value = array();
1655
					continue;
1656
				}
1657
1658
				$field = $fields[$field_id];
1659
				$field->set_values( $field_value );
1660
				$field->parse_save_values();
1661
1662
				$field_value = $field->get_values();
1663
1664
				// if the field is a repeatable field, store the whole array of them, if it's not repeatble,
1665
				// just store the first (and only) one directly
1666
				if ( ! $field->args['repeatable'] )
1667
					$field_value = reset( $field_value );
1668
			}
1669
		}
1670
1671
	}
1672
1673
	public function add_field( CMB_Field $field ) {
1674
		$field->parent = $this;
1675
		$this->fields[$field->id] = $field;
1676
	}
1677
1678
	public function &get_fields() {
1679
		return $this->fields;
1680
	}
1681
1682
	public function set_values( array $values ) {
1683
1684
		$fields       = &$this->get_fields();
1685
		$this->values = $values;
0 ignored issues
show
Bug Best Practice introduced by
The property values does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
1686
1687
		// Reset all field values.
1688
		foreach ( $fields as $field ) {
1689
			$field->set_values( array() );
1690
		}
1691
1692
		foreach ( $values as $value ) {
1693
			foreach ( $value as $field_id => $field_value ) {
1694
				$fields[$field_id]->set_values( (array) $field_value );
1695
			}
1696
		}
1697
1698
	}
1699
1700
}
1701
1702
1703
/**
1704
 * Google map field class for CMB
1705
 *
1706
 * It enables the google places API and doesn't store the place
1707
 * name. It only stores latitude and longitude of the selected area.
1708
 *
1709
 * Note
1710
 */
1711
class CMB_Gmap_Field extends CMB_Field {
1712
1713
	/**
1714
	 * Return the default args for the Map field.
1715
	 *
1716
	 * @return array $args
1717
	 */
1718
	public function get_default_args() {
1719
		return array_merge(
1720
			parent::get_default_args(),
1721
			array(
1722
				'field_width'         => '100%',
1723
				'field_height'        => '250px',
1724
				'default_lat'         => '-33.9296903',
1725
				'default_long'        => '18.4527097',
1726
				'default_zoom'        => '9',
1727
				'string-marker-title' => __( 'Drag to set the exact location', 'cmb' ),
1728
			)
1729
		);
1730
	}
1731
1732
	public function enqueue_scripts() {
1733
1734
		parent::enqueue_scripts();
1735
1736
		$options = get_option('_lsx_lsx-settings',false);
1737
1738
		if(false !== $options && isset($options['general']['googlemaps_key'])) {
1739
1740
			wp_enqueue_script( 'cmb-google-maps', 'https://maps.googleapis.com/maps/api/js?key='.$options['general']['googlemaps_key'].'&libraries=places' );
1741
			wp_enqueue_script( 'cmb-google-maps-script', trailingslashit( CMB_URL ) . 'js/field-gmap.js', array( 'jquery', 'cmb-google-maps' ) );
1742
1743
			wp_localize_script( 'cmb-google-maps-script', 'CMBGmaps', array(
1744
				'defaults' => array(
1745
					'latitude'  => $this->args['default_lat'],
1746
					'longitude' => $this->args['default_long'],
1747
					'zoom'      => $this->args['default_zoom'],
1748
				),
1749
				'strings'  => array(
1750
					'markerTitle' => $this->args['string-marker-title']
1751
				)
1752
			) );
1753
		}
1754
1755
	}
1756
1757
	public function html() {
1758
1759
		// Ensure all args used are set
1760
		$value = wp_parse_args(
1761
			$this->get_value(),
1762
			array( 'address' => null,'lat' => null, 'long' => null,'zoom' => null, 'elevation' => null )
1763
		);
1764
1765
		$style = array(
1766
			sprintf( 'width: %s;', $this->args['field_width'] ),
1767
			sprintf( 'height: %s;', $this->args['field_height'] ),
1768
			'border: 1px solid #eee;',
1769
			'margin-top: 8px;'
1770
		);
1771
1772
		?>
1773
1774
		<input type="text" <?php $this->class_attr( 'map-search' ); ?> <?php $this->id_attr(); ?> placeholder="Enter an address" value="<?php echo esc_attr( $value['address'] ); ?>" />
1775
		<select <?php $this->class_attr( 'map-zoom' ); ?>>
1776
			<option value="">Zoom</option>
1777
			<?php foreach(array('1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16','17','18','19','20','21') as $zoom_level) {
1778
				if($zoom_level === $value['zoom']) { $selected='selected="selected"'; }else{$selected='';}
1779
				echo '<option '.$selected.' value="'.$zoom_level.'">'.$zoom_level.'</option>';
1780
			}?>
1781
		</select>
1782
1783
		<div class="map" style="<?php echo esc_attr( implode( ' ', $style ) ); ?>"></div>
1784
1785
		<input type="hidden" class="address"  <?php $this->name_attr( '[address]' ); ?>    value="<?php echo esc_attr( $value['address'] ); ?>" />
1786
		<input type="hidden" class="latitude"  <?php $this->name_attr( '[lat]' ); ?>       value="<?php echo esc_attr( $value['lat'] ); ?>" />
1787
		<input type="hidden" class="longitude" <?php $this->name_attr( '[long]' ); ?>      value="<?php echo esc_attr( $value['long'] ); ?>" />
1788
		<input type="hidden" class="zoom"	 <?php $this->name_attr( '[zoom]' ); ?> value="<?php echo esc_attr( $value['zoom'] ); ?>" />
1789
		<input type="hidden" class="elevation" <?php $this->name_attr( '[elevation]' ); ?> value="<?php echo esc_attr( $value['elevation'] ); ?>" />
1790
1791
		<?php
1792
	}
1793
}
1794