Completed
Push — develop ( 7fd7c7...b66118 )
by Aristeides
03:45
created

Kirki_Field   D

Complexity

Total Complexity 121

Size/Duplication

Total Lines 877
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 0
Metric Value
dl 0
loc 877
rs 4.4444
c 0
b 0
f 0
wmc 121
lcom 1
cbo 1

32 Methods

Rating   Name   Duplication   Size   Complexity  
D __construct() 0 52 17
B set_field() 0 35 6
A get_property_classname() 0 13 4
A set_label() 0 1 1
A set_description() 0 1 1
A set_mode() 0 1 1
A set_fields() 0 1 1
A set_row_label() 0 1 1
A set_default() 0 1 1
A set_kirki_config() 0 5 1
A set_option_name() 0 5 1
A set_section() 0 5 1
A set_input_attrs() 0 6 2
A set_capability() 0 10 2
A set_option_type() 0 13 3
B set_partial_refresh() 0 17 8
C set_settings() 0 24 7
A set_tooltip() 0 7 2
B set_active_callback() 0 21 7
A set_type() 0 6 1
A set_id() 0 5 1
A set_sanitize_callback() 0 1 1
A set_choices() 0 6 2
A set_disable_output() 0 5 1
F set_output() 0 46 19
C set_js_vars() 0 53 14
B set_variables() 0 10 6
A set_help() 0 13 3
A set_transport() 0 6 2
A set_required() 0 6 2
A set_priority() 0 5 1
A set_collapsible() 0 5 1

How to fix   Complexity   

Complex Class

Complex classes like Kirki_Field often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Kirki_Field, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Creates and validates field parameters.
4
 *
5
 * @package     Kirki
6
 * @category    Core
7
 * @author      Aristeides Stathopoulos
8
 * @copyright   Copyright (c) 2017, Aristeides Stathopoulos
9
 * @license     http://opensource.org/licenses/https://opensource.org/licenses/MIT
10
 * @since       1.0
11
 */
12
13
/**
14
 * Please do not use this class directly.
15
 * You should instead extend it per-field-type.
16
 */
17
class Kirki_Field {
18
19
	/**
20
	 * The ID of the kirki_config we're using.
21
	 *
22
	 * @see Kirki_Config
23
	 * @access protected
24
	 * @var string
25
	 */
26
	protected $kirki_config = 'global';
27
28
	/**
29
	 * Thje capability required so that users can edit this field.
30
	 *
31
	 * @access protected
32
	 * @var string
33
	 */
34
	protected $capability = 'edit_theme_options';
35
36
	/**
37
	 * If we're using options instead of theme_mods
38
	 * and we want them serialized, this is the option that
39
	 * will saved in the db.
40
	 *
41
	 * @access protected
42
	 * @var string
43
	 */
44
	protected $option_name = '';
45
46
	/**
47
	 * Custom input attributes (defined as an array).
48
	 *
49
	 * @access protected
50
	 * @var array
51
	 */
52
	protected $input_attrs = array();
53
54
	/**
55
	 * Use "theme_mod" or "option".
56
	 *
57
	 * @access protected
58
	 * @var string
59
	 */
60
	protected $option_type = 'theme_mod';
61
62
	/**
63
	 * The name of this setting (id for the db).
64
	 *
65
	 * @access protected
66
	 * @var string|array
67
	 */
68
	protected $settings = '';
69
70
	/**
71
	 * Set to true if you want to disable all CSS output for this field.
72
	 *
73
	 * @access protected
74
	 * @var bool
75
	 */
76
	protected $disable_output = false;
77
78
	/**
79
	 * The field type.
80
	 *
81
	 * @access protected
82
	 * @var string
83
	 */
84
	protected $type = 'kirki-generic';
85
86
	/**
87
	 * Some fields require options to be set.
88
	 * We're whitelisting the property here
89
	 * and suggest you validate this in a child class.
90
	 *
91
	 * @access protected
92
	 * @var array
93
	 */
94
	protected $choices = array();
95
96
	/**
97
	 * Assign this field to a section.
98
	 * Fields not assigned to a section will not be displayed in the customizer.
99
	 *
100
	 * @access protected
101
	 * @var string
102
	 */
103
	protected $section = '';
104
105
	/**
106
	 * The default value for this field.
107
	 *
108
	 * @access protected
109
	 * @var string|array|bool
110
	 */
111
	protected $default = '';
112
113
	/**
114
	 * Priority determines the position of a control inside a section.
115
	 * Lower priority numbers move the control to the top.
116
	 *
117
	 * @access protected
118
	 * @var int
119
	 */
120
	protected $priority = 10;
121
122
	/**
123
	 * Unique ID for this field.
124
	 * This is auto-calculated from the $settings argument.
125
	 *
126
	 * @access protected
127
	 * @var string
128
	 */
129
	protected $id = '';
130
131
	/**
132
	 * Use if you want to automatically generate CSS from this field's value.
133
	 *
134
	 * @see https://kirki.org/docs/arguments/output
135
	 * @access protected
136
	 * @var array
137
	 */
138
	protected $output = array();
139
140
	/**
141
	 * Use to automatically generate postMessage scripts.
142
	 * Not necessary to use if you use 'transport' => 'auto'
143
	 * and have already set an array for the 'output' argument.
144
	 *
145
	 * @see https://kirki.org/docs/arguments/js_vars
146
	 * @access protected
147
	 * @var array
148
	 */
149
	protected $js_vars = array();
150
151
	/**
152
	 * If you want to use a CSS compiler, then use this to set the variable names.
153
	 *
154
	 * @see https://kirki.org/docs/arguments/variables
155
	 * @access protected
156
	 * @var array
157
	 */
158
	protected $variables = array();
159
160
	/**
161
	 * Text that will be used in a tooltip to provide extra info for this field.
162
	 *
163
	 * @access protected
164
	 * @var string
165
	 */
166
	protected $tooltip = '';
167
168
	/**
169
	 * Whitelisting for backwards-compatibility.
170
	 *
171
	 * @access protected
172
	 * @var string
173
	 */
174
	protected $help = '';
175
176
	/**
177
	 * A custom callback to determine if the field should be visible or not.
178
	 *
179
	 * @access protected
180
	 * @var string|array
181
	 */
182
	protected $active_callback = '__return_true';
183
184
	/**
185
	 * A custom sanitize callback that will be used to properly save the values.
186
	 *
187
	 * @access protected
188
	 * @var string|array
189
	 */
190
	protected $sanitize_callback = '';
191
192
	/**
193
	 * Use 'refresh', 'postMessage' or 'auto'.
194
	 * 'auto' will automatically geberate any 'js_vars' from the 'output' argument.
195
	 *
196
	 * @access protected
197
	 * @var string
198
	 */
199
	protected $transport = 'refresh';
200
201
	/**
202
	 * Define dependencies to show/hide this field based on the values of other fields.
203
	 *
204
	 * @access protected
205
	 * @var array
206
	 */
207
	protected $required = array();
208
209
	/**
210
	 * Suggested width for cropped image.
211
	 *
212
	 * @access protected
213
	 * @var int
214
	 */
215
	protected $width = 150;
216
217
	/**
218
	 * Suggested height for cropped image.
219
	 *
220
	 * @access protected
221
	 * @var int
222
	 */
223
	protected $height = 150;
224
225
	/**
226
	 * Whether the width is flexible for cropped image.
227
	 *
228
	 * @access protected
229
	 * @var bool
230
	 */
231
	protected $flex_width = false;
232
233
	/**
234
	 * Whether the height is flexible for cropped image.
235
	 *
236
	 * @access protected
237
	 * @var bool
238
	 */
239
	protected $flex_height = false;
240
241
	/**
242
	 * Contain the settings for the repeater rows labels
243
	 *
244
	 * @access protected
245
	 * @var array
246
	 */
247
	protected $row_label = array();
248
249
	/**
250
	 * Partial Refreshes array.
251
	 *
252
	 * @access protected
253
	 * @var array
254
	 */
255
	protected $partial_refresh = array();
256
257
	/**
258
	 * Use only on image, cropped_image, upload controls.
259
	 * Limit the Media library to a specific mime type
260
	 *
261
	 * @access protected
262
	 * @var array
263
	 */
264
	protected $mime_type = '';
265
266
	/**
267
	 * Used by image fields.
268
	 *
269
	 * @access protected
270
	 * @var array
271
	 * @since 3.0.0
272
	 */
273
	protected $button_labels = array();
274
275
	/**
276
	 * Use only on select controls.
277
	 * Defines if this is a multi-select or not.
278
	 * If value is > 1, then the maximum number of selectable options
279
	 * is the number defined here.
280
	 *
281
	 * @access protected
282
	 * @var integer
283
	 */
284
	protected $multiple = 1;
285
286
	/**
287
	 * Allows fields to be collapsible.
288
	 *
289
	 * @access protected
290
	 * @since 3.0.0
291
	 * @var bool
292
	 */
293
	protected $collapsible = false;
294
295
	/**
296
	 * The class constructor.
297
	 * Parses and sanitizes all field arguments.
298
	 * Then it adds the field to Kirki::$fields.
299
	 *
300
	 * @access public
301
	 * @param string $config_id    The ID of the config we want to use.
302
	 *                             Defaults to "global".
303
	 *                             Configs are handled by the Kirki_Config class.
304
	 * @param array  $args         The arguments of the field.
305
	 */
306
	public function __construct( $config_id = 'global', $args = array() ) {
307
308
		if ( isset( $args['setting'] ) && ! empty( $args['setting'] ) && ( ! isset( $args['settings'] ) || empty( $args['settings'] ) ) ) {
309
			/* translators: %s represents the field ID where the error occurs. */
310
			_doing_it_wrong( __METHOD__, sprintf( esc_attr__( 'Typo found in field %s - setting instead of settings.', 'kirki' ), esc_attr( $args['settings'] ) ), '3.0.10' );
311
			$args['settings'] = $args['setting'];
312
			unset( $args['setting'] );
313
		}
314
315
		// In case the user only provides 1 argument,
316
		// assume that the provided argument is $args and set $config_id = 'global'.
317
		if ( is_array( $config_id ) && empty( $args ) ) {
318
			/* translators: %1$s represents the field ID where the error occurs. %2$s is the URL in the documentation site. */
319
			_doing_it_wrong( __METHOD__, sprintf( esc_attr__( 'Config not defined for field %1$s - See %2$s for details on how to properly add fields.', 'kirki' ), esc_attr( $args['settings'] ), 'https://aristath.github.io/kirki/docs/getting-started/fields.html' ), '3.0.10' );
320
			$args = $config_id;
321
			$config_id = 'global';
322
		}
323
324
		$args['kirki_config'] = $config_id;
325
326
		$this->kirki_config = trim( esc_attr( $config_id ) );
327
		if ( '' === $config_id ) {
328
			/* translators: %1$s represents the field ID where the error occurs. %2$s is the URL in the documentation site. */
329
			_doing_it_wrong( __METHOD__, sprintf( esc_attr__( 'Config not defined for field %1$s - See %2$s for details on how to properly add fields.', 'kirki' ), esc_attr( $args['settings'] ), 'https://aristath.github.io/kirki/docs/getting-started/fields.html' ), '3.0.10' );
330
			$this->kirki_config = 'global';
331
		}
332
333
		// Get defaults from the class.
334
		$defaults = get_class_vars( __CLASS__ );
335
336
		// Get the config arguments, and merge them with the defaults.
337
		$config_defaults = ( isset( Kirki::$config['global'] ) ) ? Kirki::$config['global'] : array();
338
		if ( 'global' !== $this->kirki_config && isset( Kirki::$config[ $this->kirki_config ] ) ) {
339
			$config_defaults = Kirki::$config[ $this->kirki_config ];
340
		}
341
		$config_defaults = ( is_array( $config_defaults ) ) ? $config_defaults : array();
342
		foreach ( $config_defaults as $key => $value ) {
343
			if ( isset( $defaults[ $key ] ) && ! empty( $value ) && $value != $defaults[ $key ] ) {
344
				$defaults[ $key ] = $value;
345
			}
346
		}
347
348
		// Merge our args with the defaults.
349
		$args = wp_parse_args( $args, $defaults );
350
351
		// Set the class properties using the parsed args.
352
		foreach ( $args as $key => $value ) {
353
			$this->$key = $value;
354
		}
355
356
		$this->set_field();
357
	}
358
359
	/**
360
	 * Processes the field arguments
361
	 *
362
	 * @access protected
363
	 */
364
	protected function set_field() {
365
366
		$properties = get_class_vars( __CLASS__ );
367
368
		// Some things must run before the others.
369
		$this->set_option_name();
370
		$this->set_option_type();
371
		$this->set_settings();
372
373
		// Sanitize the properties, skipping the ones that have already run above.
374
		foreach ( $properties as $property => $value ) {
375
			if ( in_array( $property, array( 'option_name', 'option_type', 'settings' ), true ) ) {
376
				continue;
377
			}
378
			$property_class_name = $this->get_property_classname( $property );
379
			if ( class_exists( $property_class_name ) ) {
380
				$property_obj   = new $property_class_name();
381
				$this->property = $property_obj->get_property();
0 ignored issues
show
Bug introduced by
The property property does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
382
			}
383
			if ( method_exists( $this, 'set_' . $property ) ) {
384
				$method_name = 'set_' . $property;
385
				$this->$method_name();
386
			}
387
		}
388
389
		// Get all arguments with their values.
390
		$args = get_object_vars( $this );
391
		foreach ( $args as $key => $default_value ) {
392
			$args[ $key ] = $this->$key;
393
		}
394
395
		// Add the field to the static $fields variable properly indexed.
396
		Kirki::$fields[ $this->settings ] = $args;
397
398
	}
399
400
	/**
401
	 * Gets the classname from a property.
402
	 *
403
	 * @access private
404
	 * @since 3.0.10
405
	 * @param string $property The property.
406
	 * @return string          A classname derived from the property.
407
	 */
408
	private function get_property_classname( $property ) {
409
		$property_parts = (array) $property;
410
		if ( false !== strpos( $property, '-' ) ) {
411
			$property_parts = explode( '-' );
412
		}
413
		if ( false !== strpos( $property, '_' ) ) {
414
			$property_parts = explode( '_' );
415
		}
416
		foreach( $property_parts as $property_part_k => $property_part_v ) {
0 ignored issues
show
introduced by
Space after opening control structure is required
Loading history...
introduced by
No space before opening parenthesis is prohibited
Loading history...
417
			$property_parts[ $property_part_k ] = ucfirst( $property_part_v );
418
		}
419
		return 'Kirki_Field_Property_' . implode( '_', $property_parts );
420
	}
421
422
	/**
423
	 * No need to do anything, these are escaped on the fields themselves.
424
	 *
425
	 * @access protected
426
	 */
427
	protected function set_label() {}
428
429
	/**
430
	 * No need to do anything, these are escaped on the fields themselves.
431
	 *
432
	 * @access protected
433
	 */
434
	protected function set_description() {}
435
436
	/**
437
	 * No need to do anything, these are escaped on the fields themselves.
438
	 *
439
	 * @access protected
440
	 */
441
	protected function set_mode() {}
442
443
	/**
444
	 * No need to do anything, these are escaped on the fields themselves.
445
	 * Only used in repeaters.
446
	 *
447
	 * @access protected
448
	 */
449
	protected function set_fields() {}
450
451
	/**
452
	 * No need to do anything, these are escaped on the fields themselves.
453
	 * Only used in repeaters.
454
	 *
455
	 * @access protected
456
	 */
457
	protected function set_row_label() {}
458
459
	/**
460
	 * This allows us to process this on a field-basis
461
	 * by using sub-classes which can override this method.
462
	 *
463
	 * @access protected
464
	 */
465
	protected function set_default() {}
466
467
	/**
468
	 * Escape $kirki_config.
469
	 *
470
	 * @access protected
471
	 */
472
	protected function set_kirki_config() {
473
474
		$this->kirki_config = esc_attr( $this->kirki_config );
475
476
	}
477
478
	/**
479
	 * Escape $option_name.
480
	 *
481
	 * @access protected
482
	 */
483
	protected function set_option_name() {
484
485
		$this->option_name = esc_attr( $this->option_name );
486
487
	}
488
489
	/**
490
	 * Escape the $section.
491
	 *
492
	 * @access protected
493
	 */
494
	protected function set_section() {
495
496
		$this->section = sanitize_key( $this->section );
497
498
	}
499
500
	/**
501
	 * Escape the $section.
502
	 *
503
	 * @access protected
504
	 */
505
	protected function set_input_attrs() {
506
507
		if ( ! is_array( $this->input_attrs ) ) {
508
			$this->input_attrs = array();
509
		}
510
	}
511
512
	/**
513
	 * Checks the capability chosen is valid.
514
	 * If not, then falls back to 'edit_theme_options'
515
	 *
516
	 * @access protected
517
	 */
518
	protected function set_capability() {
519
520
		// Early exit if we're using 'edit_theme_options'.
521
		if ( 'edit_theme_options' === $this->capability ) {
522
			return;
523
		}
524
		// Escape & trim the capability.
525
		$this->capability = trim( esc_attr( $this->capability ) );
526
527
	}
528
529
	/**
530
	 * Make sure we're using the correct option_type
531
	 *
532
	 * @access protected
533
	 */
534
	protected function set_option_type() {
535
536
		// Take care of common typos.
537
		if ( 'options' === $this->option_type ) {
538
			$this->option_type = 'option';
539
		}
540
		// Take care of common typos.
541
		if ( 'theme_mods' === $this->option_type ) {
542
			/* translators: %1$s represents the field ID where the error occurs. */
543
			_doing_it_wrong( __METHOD__, sprintf( esc_attr__( 'Typo found in field %s - "theme_mods" vs "theme_mod"', 'kirki' ), esc_attr( $this->settings ) ), '3.0.10' );
544
			$this->option_type = 'theme_mod';
545
		}
546
	}
547
548
	/**
549
	 * Modifications for partial refreshes.
550
	 *
551
	 * @access protected
552
	 */
553
	protected function set_partial_refresh() {
554
555
		if ( ! is_array( $this->partial_refresh ) ) {
556
			$this->partial_refresh = array();
557
		}
558
		foreach ( $this->partial_refresh as $id => $args ) {
559
			if ( ! is_array( $args ) || ! isset( $args['selector'] ) || ! isset( $args['render_callback'] ) || ! is_callable( $args['render_callback'] ) ) {
560
				/* translators: %1$s represents the field ID where the error occurs. */
561
				_doing_it_wrong( __METHOD__, sprintf( esc_attr__( '"partial_refresh" invalid entry in field %s', 'kirki' ), esc_attr( $this->settings ) ), '3.0.10' );
562
				unset( $this->partial_refresh[ $id ] );
563
				continue;
564
			}
565
		}
566
		if ( ! empty( $this->partial_refresh ) ) {
567
			$this->transport = 'postMessage';
568
		}
569
	}
570
571
	/**
572
	 * Sets the settings.
573
	 * If we're using serialized options it makes sure that settings are properly formatted.
574
	 * We'll also be escaping all setting names here for consistency.
575
	 *
576
	 * @access protected
577
	 */
578
	protected function set_settings() {
579
580
		// If settings is not an array, temporarily convert it to an array.
581
		// This is just to allow us to process everything the same way and avoid code duplication.
582
		// if settings is not an array then it will not be set as an array in the end.
583
		if ( ! is_array( $this->settings ) ) {
584
			$this->settings = array(
585
				'kirki_placeholder_setting' => $this->settings,
586
			);
587
		}
588
		$settings = array();
589
		foreach ( $this->settings as $setting_key => $setting_value ) {
590
			$settings[ sanitize_key( $setting_key ) ] = esc_attr( $setting_value );
591
			// If we're using serialized options then we need to spice this up.
592
			if ( 'option' === $this->option_type && '' !== $this->option_name && ( false === strpos( $setting_key, '[' ) ) ) {
593
				$settings[ sanitize_key( $setting_key ) ] = esc_attr( $this->option_name ) . '[' . esc_attr( $setting_value ) . ']';
594
			}
595
		}
596
		$this->settings = $settings;
597
		if ( isset( $this->settings['kirki_placeholder_setting'] ) ) {
598
			$this->settings = $this->settings['kirki_placeholder_setting'];
599
		}
600
601
	}
602
603
	/**
604
	 * Escapes the tooltip messages.
605
	 *
606
	 * @access protected
607
	 */
608
	protected function set_tooltip() {
609
610
		if ( '' !== $this->tooltip ) {
611
			$this->tooltip = wp_strip_all_tags( $this->tooltip );
612
			return;
613
		}
614
	}
615
616
	/**
617
	 * Sets the active_callback
618
	 * If we're using the $required argument,
619
	 * Then this is where the switch is made to our evaluation method.
620
	 *
621
	 * @access protected
622
	 */
623
	protected function set_active_callback() {
624
625
		if ( is_array( $this->active_callback ) && ! is_callable( $this->active_callback ) ) {
626
			if ( isset( $this->active_callback[0] ) ) {
627
				$this->required = $this->active_callback;
628
			}
629
		}
630
631
		if ( ! empty( $this->required ) ) {
632
			$this->active_callback = array( 'Kirki_Active_Callback', 'evaluate' );
633
			return;
634
		}
635
		// No need to proceed any further if we're using the default value.
636
		if ( '__return_true' === $this->active_callback ) {
637
			return;
638
		}
639
		// Make sure the function is callable, otherwise fallback to __return_true.
640
		if ( ! is_callable( $this->active_callback ) ) {
641
			$this->active_callback = '__return_true';
642
		}
643
	}
644
645
	/**
646
	 * Sets the control type.
647
	 *
648
	 * @access protected
649
	 */
650
	protected function set_type() {
651
652
		// Escape the control type (it doesn't hurt to be sure).
653
		$this->type = esc_attr( $this->type );
654
655
	}
656
657
	/**
658
	 * Sets the $id.
659
	 * Setting the ID should happen after the 'settings' sanitization.
660
	 * This way we can also properly handle cases where the option_type is set to 'option'
661
	 * and we're using an array instead of individual options.
662
	 *
663
	 * @access protected
664
	 */
665
	protected function set_id() {
666
667
		$this->id = sanitize_key( str_replace( '[', '-', str_replace( ']', '', $this->settings ) ) );
668
669
	}
670
671
	/**
672
	 * Sets the $sanitize_callback
673
	 *
674
	 * @access protected
675
	 */
676
	protected function set_sanitize_callback() {}
677
678
	/**
679
	 * Sets the $choices.
680
	 *
681
	 * @access protected
682
	 */
683
	protected function set_choices() {
684
685
		if ( ! is_array( $this->choices ) ) {
686
			$this->choices = array();
687
		}
688
	}
689
690
	/**
691
	 * Escapes the $disable_output.
692
	 *
693
	 * @access protected
694
	 */
695
	protected function set_disable_output() {
696
697
		$this->disable_output = (bool) $this->disable_output;
698
699
	}
700
701
	/**
702
	 * Sets the $sanitize_callback
703
	 *
704
	 * @access protected
705
	 */
706
	protected function set_output() {
707
708
		if ( empty( $this->output ) ) {
709
			return;
710
		}
711
		if ( ! empty( $this->output ) && ! is_array( $this->output ) ) {
712
			/* translators: %s represents the field ID where the error occurs. */
713
			_doing_it_wrong( __METHOD__, sprintf( esc_attr__( '"output" invalid format in field %s. The "output" argument should be defined as an array of arrays.', 'kirki' ), esc_attr( $this->settings ) ), '3.0.10' );
714
			$this->output = array(
715
				array(
716
					'element' => $this->output,
717
				),
718
			);
719
		}
720
		// Convert to array of arrays if needed.
721
		if ( isset( $this->output['element'] ) ) {
722
			/* translators: %s represents the field ID where the error occurs. */
723
			_doing_it_wrong( __METHOD__, sprintf( esc_attr__( '"output" invalid format in field %s. The "output" argument should be defined as an array of arrays.', 'kirki' ), esc_attr( $this->settings ) ), '3.0.10' );
724
			$this->output = array( $this->output );
725
		}
726
		$outputs = array();
727
		foreach ( $this->output as $output ) {
728
			if ( ! isset( $output['element'] ) || ( ! isset( $output['property'] ) && ! in_array( $this->type, array( 'kirki-typography', 'kirki-background' ), true ) ) ) {
729
				continue;
730
			}
731
			if ( ! isset( $output['sanitize_callback'] ) && isset( $output['callback'] ) ) {
732
				$output['sanitize_callback'] = $output['callback'];
733
			}
734
			// Convert element arrays to strings.
735
			if ( is_array( $output['element'] ) ) {
736
				$output['element'] = array_unique( $output['element'] );
737
				sort( $output['element'] );
738
				$output['element'] = implode( ',', $output['element'] );
739
			}
740
			$outputs[] = array(
741
				'element'           => $output['element'],
742
				'property'          => ( isset( $output['property'] ) ) ? $output['property'] : '',
743
				'media_query'       => ( isset( $output['media_query'] ) ) ? $output['media_query'] : 'global',
744
				'sanitize_callback' => ( isset( $output['sanitize_callback'] ) ) ? $output['sanitize_callback'] : '',
745
				'units'             => ( isset( $output['units'] ) ) ? $output['units'] : '',
746
				'prefix'            => ( isset( $output['prefix'] ) ) ? $output['prefix'] : '',
747
				'suffix'            => ( isset( $output['suffix'] ) ) ? $output['suffix'] : '',
748
				'exclude'           => ( isset( $output['exclude'] ) ) ? $output['exclude'] : false,
749
			);
750
		}
751
	}
752
753
	/**
754
	 * Sets the $js_vars
755
	 *
756
	 * @access protected
757
	 */
758
	protected function set_js_vars() {
759
760
		if ( ! is_array( $this->js_vars ) ) {
761
			$this->js_vars = array();
762
		}
763
764
		// Check if transport is set to auto.
765
		// If not, then skip the auto-calculations and exit early.
766
		if ( 'auto' !== $this->transport ) {
767
			return;
768
		}
769
770
		// Set transport to refresh initially.
771
		// Serves as a fallback in case we failt to auto-calculate js_vars.
772
		$this->transport = 'refresh';
773
774
		$js_vars = array();
775
776
		// Try to auto-generate js_vars.
777
		// First we need to check if js_vars are empty, and that output is not empty.
778
		if ( empty( $this->js_vars ) && ! empty( $this->output ) ) {
779
780
			// Start going through each item in the $output array.
781
			foreach ( $this->output as $output ) {
782
				$output['function'] = ( isset( $output['function'] ) ) ? $output['function'] : 'style';
783
784
				// If 'element' or 'property' are not defined, skip this.
785
				if ( ! isset( $output['element'] ) || ! isset( $output['property'] ) ) {
786
					continue;
787
				}
788
				if ( is_array( $output['element'] ) ) {
789
					$output['element'] = implode( ',', $output['element'] );
790
				}
791
792
				// If there's a sanitize_callback defined skip this, unless we also have a js_callback defined.
793
				if ( isset( $output['sanitize_callback'] ) && ! empty( $output['sanitize_callback'] ) && ! isset( $output['js_callback'] ) ) {
794
					continue;
795
				}
796
797
				// If we got this far, it's safe to add this.
798
				$js_vars[] = $output;
799
			}
800
801
			// Did we manage to get all the items from 'output'?
802
			// If not, then we're missing something so don't add this.
803
			if ( count( $js_vars ) !== count( $this->output ) ) {
804
				return;
805
			}
806
			$this->js_vars   = $js_vars;
807
			$this->transport = 'postMessage';
808
809
		}
810
	}
811
812
	/**
813
	 * Sets the $variables
814
	 *
815
	 * @access protected
816
	 */
817
	protected function set_variables() {
818
819
		if ( ! is_array( $this->variables ) ) {
820
			$variable = ( is_string( $this->variables ) && ! empty( $this->variables ) ) ? $this->variables : false;
821
			$this->variables = array();
822
			if ( $variable && empty( $this->variables ) ) {
823
				$this->variables[0]['name'] = $variable;
824
			}
825
		}
826
	}
827
828
	/**
829
	 * This is a fallback method:
830
	 * $help has now become $tooltip, so this just migrates the data
831
	 *
832
	 * @access protected
833
	 */
834
	protected function set_help() {
835
836
		if ( '' !== $this->tooltip ) {
837
			return;
838
		}
839
		if ( '' !== $this->help ) {
840
			/* translators: %s represents the field ID where the error occurs. */
841
			_doing_it_wrong( __METHOD__, sprintf( esc_attr__( '"help" argument has been deprecated in favor of "tooltip". Error in field %s.', 'kirki' ), esc_attr( $this->settings ) ), '3.0.10' );
842
			$this->tooltip = wp_strip_all_tags( $this->help );
843
			$this->help = '';
844
			return;
845
		}
846
	}
847
848
	/**
849
	 * Sets the $transport
850
	 *
851
	 * @access protected
852
	 */
853
	protected function set_transport() {
854
855
		if ( 'postmessage' === trim( strtolower( $this->transport ) ) ) {
856
			$this->transport = 'postMessage';
857
		}
858
	}
859
860
	/**
861
	 * Sets the $required
862
	 *
863
	 * @access protected
864
	 */
865
	protected function set_required() {
866
867
		if ( ! is_array( $this->required ) ) {
868
			$this->required = array();
869
		}
870
	}
871
872
	/**
873
	 * Sets the $priority
874
	 *
875
	 * @access protected
876
	 */
877
	protected function set_priority() {
878
879
		$this->priority = absint( $this->priority );
880
881
	}
882
883
	/**
884
	 * Sets the $collapsible var.
885
	 *
886
	 * @access protected
887
	 */
888
	protected function set_collapsible() {
889
890
		$this->collapsible = (bool) $this->collapsible;
891
892
	}
893
}
894