Completed
Push — master ( 93d435...beebfe )
by Scott Kingsley
02:33
created

WP_Fields_API_Control::check_capabilities()   C

Complexity

Conditions 7
Paths 7

Size

Total Lines 31
Code Lines 12

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 31
rs 6.7273
cc 7
eloc 12
nc 7
nop 0
1
<?php
2
/**
3
 * Fields API Control Class
4
 *
5
 * @package WordPress
6
 * @subpackage Fields_API
7
 *
8
 * @property array $choices Key/Values used by Multiple choice control types
9
 */
10
class WP_Fields_API_Control {
11
12
	/**
13
	 * Incremented with each new class instantiation, then stored in $instance_number.
14
	 *
15
	 * Used when sorting two instances whose priorities are equal.
16
	 *
17
	 * @access protected
18
	 * @var int
19
	 */
20
	protected static $instance_count = 0;
21
22
	/**
23
	 * Order in which this instance was created in relation to other instances.
24
	 *
25
	 * @access public
26
	 * @var int
27
	 */
28
	public $instance_number = 0;
29
30
	/**
31
	 * Unique identifier.
32
	 *
33
	 * @access public
34
	 * @var string
35
	 */
36
	public $id = '';
37
38
	/**
39
	 * Object type.
40
	 *
41
	 * @access public
42
	 * @var string
43
	 */
44
	public $object_type = '';
45
46
	/**
47
	 * Object name (for post types and taxonomies).
48
	 *
49
	 * @access public
50
	 * @var string
51
	 */
52
	public $object_name = '';
53
54
	/**
55
	 * Item ID of current item passed to WP_Fields_API_Field for value()
56
	 *
57
	 * @access public
58
	 * @var int|string
59
	 */
60
	public $item_id;
61
62
	/**
63
	 * All fields tied to the control.
64
	 *
65
	 * @access public
66
	 * @var array
67
	 */
68
	public $fields = array();
69
70
	/**
71
	 * The primary field for the control (if there is one).
72
	 *
73
	 * @access public
74
	 * @var string|WP_Fields_API_Field
75
	 */
76
	public $field = 'default';
77
78
	/**
79
	 * The primary screen for the control (if there is one).
80
	 *
81
	 * @access public
82
	 * @var string|WP_Fields_API_Section
83
	 */
84
	public $section = '';
85
86
	/**
87
	 * The primary screen for the control (if there is one).
88
	 *
89
	 * @access public
90
	 * @var string|WP_Fields_API_Screen
91
	 */
92
	public $screen = '';
93
94
	/**
95
	 * @access public
96
	 * @var int
97
	 */
98
	public $priority = 10;
99
100
	/**
101
	 * @access public
102
	 * @var string
103
	 */
104
	public $label = '';
105
106
	/**
107
	 * @access public
108
	 * @var string
109
	 */
110
	public $description = '';
111
112
	/**
113
	 * @access public
114
	 * @var array
115
	 */
116
	public $input_attrs = array();
117
118
	/**
119
	 * @access public
120
	 * @var string
121
	 */
122
	public $type = 'text';
123
124
	/**
125
	 * Callback.
126
	 *
127
	 * @access public
128
	 *
129
	 * @see WP_Fields_API_Control::active()
130
	 *
131
	 * @var callable Callback is called with one argument, the instance of
132
	 *               WP_Fields_API_Control, and returns bool to indicate whether
133
	 *               the control is active (such as it relates to the URL
134
	 *               currently being previewed).
135
	 */
136
	public $active_callback = '';
137
138
	/**
139
	 * Capabilities Callback.
140
	 *
141
	 * @access public
142
	 *
143
	 * @see WP_Fields_API_Control::check_capabilities()
144
	 *
145
	 * @var callable Callback is called with one argument, the instance of
146
	 *               WP_Fields_API_Control, and returns bool to indicate whether
147
	 *               the control has capabilities to be used.
148
	 */
149
	public $capabilities_callback = '';
150
151
	/**
152
	 * Constructor.
153
	 *
154
	 * Parameters are not set to maintain PHP overloading compatibility (strict standards)
155
	 */
156
	public function __construct() {
157
158
		$args = func_get_args();
159
160
		call_user_func_array( array( $this, 'init' ), $args );
161
162
	}
163
164
	/**
165
	 * Secondary constructor; Any supplied $args override class property defaults.
166
	 *
167
	 * @param string $object_type   Object type.
168
	 * @param string $id            A specific ID of the control.
169
	 * @param array  $args          Control arguments.
170
	 */
171
	public function init( $object_type, $id, $args = array() ) {
172
173
		/**
174
		 * @var $wp_fields WP_Fields_API
175
		 */
176
		global $wp_fields;
177
178
		$this->object_type = $object_type;
179
180
		if ( is_array( $id ) ) {
181
			$args = $id;
182
183
			$id = '';
184
		} else {
185
			$this->id = $id;
186
		}
187
188
		$keys = array_keys( get_object_vars( $this ) );
189
190
		foreach ( $keys as $key ) {
191
			if ( isset( $args[ $key ] ) ) {
192
				$this->$key = $args[ $key ];
193
			}
194
		}
195
196
		if ( empty( $this->active_callback ) ) {
197
			$this->active_callback = array( $this, 'active_callback' );
198
		}
199
200
		self::$instance_count += 1;
201
		$this->instance_number = self::$instance_count;
202
203
		// Process fields.
204
		if ( empty( $this->fields ) ) {
205
			$this->fields = $id;
0 ignored issues
show
Documentation Bug introduced by
It seems like $id of type string is incompatible with the declared type array of property $fields.

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...
206
		}
207
208
		$fields = array();
209
210
		if ( is_array( $this->fields ) ) {
211
			foreach ( $this->fields as $key => $field ) {
212
				$field_obj = $wp_fields->get_field( $this->object_type, $field, $this->object_name );
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $field_obj is correct as $wp_fields->get_field($t...ld, $this->object_name) (which targets WP_Fields_API::get_field()) 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...
213
214
				if ( $field_obj ) {
215
					$fields[ $key ] = $field_obj;
216
				}
217
			}
218
		} else {
219
			$field_obj = $wp_fields->get_field( $this->object_type, $this->fields, $this->object_name );
220
221
			if ( $field_obj ) {
222
				$this->field       = $field_obj;
223
				$fields['default'] = $field_obj;
224
			}
225
		}
226
227
		$this->fields = $fields;
228
229
	}
230
231
	/**
232
	 * Setup the choices values and set the choices property to allow dynamic building
233
	 */
234
	public function setup_choices() {
235
236
		if ( ! isset( $this->choices ) ) {
237
			$choices = $this->choices();
238
239
			$this->choices = $choices;
240
		}
241
242
	}
243
244
	/**
245
	 * Get the choices values from the choices property and allow dynamic building
246
	 */
247
	public function choices() {
248
249
		return array();
250
251
	}
252
253
	/**
254
	 * Enqueue control related scripts/styles.
255
	 */
256
	public function enqueue() {}
257
258
	/**
259
	 * Check whether control is active to current Fields API preview.
260
	 *
261
	 * @access public
262
	 *
263
	 * @return bool Whether the control is active to the current preview.
264
	 */
265 View Code Duplication
	final public function active() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
266
267
		$control = $this;
268
		$active = true;
269
270
		if ( is_callable( $this->active_callback ) ) {
271
			$active = call_user_func( $this->active_callback, $this );
272
		}
273
274
		/**
275
		 * Filter response of WP_Fields_API_Control::active().
276
		 *
277
		 * @param bool                  $active  Whether the Field control is active.
278
		 * @param WP_Fields_API_Control $control WP_Fields_API_Control instance.
279
		 */
280
		$active = apply_filters( 'fields_control_active_' . $this->object_type, $active, $control );
281
282
		return $active;
283
284
	}
285
286
	/**
287
	 * Default callback used when invoking WP_Fields_API_Control::active().
288
	 *
289
	 * Subclasses can override this with their specific logic, or they may
290
	 * provide an 'active_callback' argument to the constructor.
291
	 *
292
	 * @access public
293
	 *
294
	 * @return bool Always true.
295
	 */
296
	public function active_callback() {
297
298
		return true;
299
300
	}
301
302
	/**
303
	 * Fetch a field's value.
304
	 * Grabs the main field by default.
305
	 *
306
	 * @param string $field_key
307
	 * @return mixed The requested field's value, if the field exists.
308
	 */
309
	final public function value( $field_key = 'default' ) {
310
311
		if ( isset( $this->fields[ $field_key ] ) ) {
312
			/**
313
			 * @var $field WP_Fields_API_Field
314
			 */
315
			$field = $this->fields[ $field_key ];
316
317
			return $field->value( $this->item_id );
318
		}
319
320
		return null;
321
322
	}
323
324
	/**
325
	 * Get the data to export to the client via JSON.
326
	 *
327
	 * @return array Array of parameters passed to the JavaScript.
328
	 */
329
	public function json() {
330
331
		$array = array();
332
333
		$array['fields'] = wp_list_pluck( $this->fields, 'id' );
334
		$array['type'] = $this->type;
335
		$array['priority'] = $this->priority;
336
		$array['active'] = $this->active();
337
		$array['section'] = $this->section;
338
		$array['content'] = $this->get_content();
339
		$array['label'] = $this->label;
340
		$array['description'] = $this->description;
341
		$array['instanceNumber'] = $this->instance_number;
342
343
		return $array;
344
345
	}
346
347
	/**
348
	 * Check if the theme supports the control and check user capabilities.
349
	 *
350
	 * @return bool False if theme doesn't support the control or user doesn't have the required permissions, otherwise true.
351
	 */
352
	final public function check_capabilities() {
353
354
		/**
355
		 * @var $wp_fields WP_Fields_API
356
		 */
357
		global $wp_fields;
358
359
		/**
360
		 * @var $field WP_Fields_API_Field
361
		 */
362
		foreach ( $this->fields as $field ) {
363
			if ( ! $field || ! $field->check_capabilities() ) {
364
				return false;
365
			}
366
		}
367
368
		$section = $wp_fields->get_section( $this->object_type, $this->section, $this->object_name );
0 ignored issues
show
Bug introduced by
It seems like $this->section can also be of type object<WP_Fields_API_Section>; however, WP_Fields_API::get_section() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
369
370
		if ( $section && ! $section->check_capabilities() ) {
371
			return false;
372
		}
373
374
		$access = true;
375
376
		if ( is_callable( $this->capabilities_callback ) ) {
377
			$access = call_user_func( $this->capabilities_callback, $this );
378
		}
379
380
		return $access;
381
382
	}
383
384
	/**
385
	 * Get the control's content for insertion.
386
	 *
387
	 * @return string Contents of the control.
388
	 */
389
	final public function get_content() {
390
391
		ob_start();
392
393
		$this->maybe_render();
394
395
		$template = trim( ob_get_clean() );
396
397
		return $template;
398
399
	}
400
401
	/**
402
	 * Check capabilities and render the control.
403
	 *
404
	 * @uses WP_Fields_API_Control::render()
405
	 */
406
	final public function maybe_render() {
407
408
		if ( ! $this->check_capabilities() ) {
409
			return;
410
		}
411
412
		/**
413
		 * Fires just before the current control is rendered.
414
		 *
415
		 * @param WP_Fields_API_Control $this WP_Fields_API_Control instance.
416
		 */
417
		do_action( 'fields_render_control_' . $this->object_type, $this );
418
419
		/**
420
		 * Fires just before a specific control is rendered.
421
		 *
422
		 * The dynamic portion of the hook name, `$this->id`, refers to
423
		 * the control ID.
424
		 *
425
		 * @param WP_Fields_API_Control $this {@see WP_Fields_API_Control} instance.
426
		 */
427
		do_action( 'fields_render_control_' . $this->object_type . '_' . $this->object_name . '_' . $this->id, $this );
428
429
		$this->render();
430
431
	}
432
433
	/**
434
	 * Renders the control wrapper and calls $this->render_content() for the internals.
435
	 *
436
	 */
437
	protected function render() {
438
439
		$id    = 'fields-control-' . str_replace( '[', '-', str_replace( ']', '', $this->id ) );
440
		$class = 'fields-control fields-control-' . $this->type;
441
442
		?><li id="<?php echo esc_attr( $id ); ?>" class="<?php echo esc_attr( $class ); ?>">
443
			<?php $this->render_content(); ?>
444
		</li><?php
445
446
	}
447
448
	/**
449
	 * Get the data link attribute for a field.
450
	 *
451
	 *
452
	 * @param string $field_key
453
	 * @return string Data link parameter, if $field_key is a valid field, empty string otherwise.
454
	 */
455
	public function get_link( $field_key = 'default' ) {
456
457
		if ( ! isset( $this->fields[ $field_key ] ) ) {
458
			return '';
459
		}
460
461
		return 'data-fields-field-link="' . esc_attr( $this->fields[ $field_key ]->id ) . '"';
462
463
	}
464
465
	/**
466
	 * Render the data link attribute for the control's input element.
467
	 *
468
	 * @uses WP_Fields_API_Control::get_link()
469
	 *
470
	 * @param string $field_key
471
	 */
472
	public function link( $field_key = 'default' ) {
473
474
		echo $this->get_link( $field_key );
475
476
	}
477
478
	/**
479
	 * Render the custom attributes for the control's input element.
480
	 *
481
	 * @access public
482
	 */
483
	public function input_attrs() {
484
485
		foreach ( $this->input_attrs as $attr => $value ) {
486
			echo $attr . '="' . esc_attr( $value ) . '" ';
487
		}
488
489
	}
490
491
	/**
492
	 * Render the control's content.
493
	 *
494
	 * Allows the content to be overriden without having to rewrite the wrapper in $this->render().
495
	 *
496
	 * Supports basic input types `text`, `checkbox`, `textarea`, `radio`, `select` and `dropdown-pages`.
497
	 * Additional input types such as `email`, `url`, `number`, `hidden` and `date` are supported implicitly.
498
	 *
499
	 * Control content can alternately be rendered in JS. See {@see WP_Fields_API_Control::print_template()}.
500
	 */
501 View Code Duplication
	public function render_content() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
502
503
		?>
504
		<label>
505
			<?php if ( ! empty( $this->label ) ) : ?>
506
				<span class="fields-control-title"><?php echo esc_html( $this->label ); ?></span>
507
			<?php endif;
508
			if ( ! empty( $this->description ) ) : ?>
509
				<span class="description fields-control-description"><?php echo $this->description; ?></span>
510
			<?php endif; ?>
511
			<input type="<?php echo esc_attr( $this->type ); ?>" <?php $this->input_attrs(); ?> value="<?php echo esc_attr( $this->value( $this->item_id ) ); ?>" <?php $this->link(); ?> />
512
		</label>
513
		<?php
514
515
	}
516
517
	/**
518
	 * Render the control's JS template.
519
	 *
520
	 * This function is only run for control types that have been registered with
521
	 * {@see WP_Fields_API::register_control_type()}.
522
	 *
523
	 * In the future, this will also print the template for the control's container
524
	 * element and be override-able.
525
	 */
526
	public function print_template() {
527
528
?>
529
    <script type="text/html" id="tmpl-fields-<?php echo esc_attr( $this->object_type ); ?>-control-<?php echo esc_attr( $this->type ); ?>-content">
530
        <?php $this->content_template(); ?>
531
    </script>
532
<?php
533
534
	}
535
536
	/**
537
	 * An Underscore (JS) template for this control's content (but not its container).
538
	 *
539
	 * Class variables for this control class are available in the `data` JS object;
540
	 * export custom variables by overriding {@see WP_Fields_API_Control::to_json()}.
541
	 *
542
	 * @see WP_Fields_API_Control::print_template()
543
	 */
544
	public function content_template() {
545
546
		// Nothing by default
547
548
	}
549
550
	/**
551
	 * Magic method for handling backwards compatible properties / methods
552
	 *
553
	 * @param string $name Parameter name
554
	 *
555
	 * @return mixed|null
556
	 */
557
	public function &__get( $name ) {
558
559
		// Map $this->choices to $this->choices() for dynamic choice handling
560
		if ( 'choices' == $name ) {
561
			$this->setup_choices();
562
563
			return $this->choices;
564
		}
565
566
		return null;
567
568
	}
569
570
}