Completed
Pull Request — master (#240)
by
unknown
02:44
created

Field::get_templates()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
ccs 0
cts 2
cp 0
crap 2
1
<?php
2
3
namespace Carbon_Fields\Field;
4
5
use Carbon_Fields\Datastore\Datastore_Interface;
6
use Carbon_Fields\Datastore\Datastore_Holder_Interface;
7
use Carbon_Fields\Exception\Incorrect_Syntax_Exception;
8
9
/**
10
 * Base field class.
11
 * Defines the key container methods and their default implementations.
12
 * Implements factory design pattern.
13
 **/
14
class Field implements Datastore_Holder_Interface {
15
	/**
16
	 * Stores all the field Backbone templates
17
	 *
18
	 * @see factory()
19
	 * @see add_template()
20
	 * @var array
21
	 */
22
	protected $templates = array();
23
24
	/**
25
	 * Globally unique field identificator. Generated randomly
26
	 *
27
	 * @var string
28
	 */
29
	protected $id;
30
31
	/**
32
	 * Stores the initial <kbd>$type</kbd> variable passed to the <code>factory()</code> method
33
	 *
34
	 * @see factory
35
	 * @var string
36
	 */
37
	public $type;
38
39
	/**
40
	 * Field value
41
	 *
42
	 * @var mixed
43
	 */
44
	protected $value;
45
46
	/**
47
	 * Default field value
48
	 *
49
	 * @var mixed
50
	 */
51
	protected $default_value;
52
53
	/**
54
	 * Sanitized field name used as input name attribute during field render
55
	 *
56
	 * @see factory()
57
	 * @see set_name()
58
	 * @var string
59
	 */
60
	protected $name;
61
62
	/**
63
	 * The base field name which is used in the container.
64
	 *
65
	 * @see set_base_name()
66
	 * @var string
67
	 */
68
	protected $base_name;
69
70
	/**
71
	 * Field name used as label during field render
72
	 *
73
	 * @see factory()
74
	 * @see set_label()
75
	 * @var string
76
	 */
77
	protected $label;
78
79
	/**
80
	 * Additional text containing information and guidance for the user
81
	 *
82
	 * @see help_text()
83
	 * @var string
84
	 */
85
	protected $help_text;
86
87
	/**
88
	 * Field DataStore instance to which save, load and delete calls are delegated
89
	 *
90
	 * @see set_datastore()
91
	 * @see get_datastore()
92
	 * @var Datastore_Interface
93
	 */
94
	protected $datastore;
95
96
	/**
97
	 * Flag whether the datastore is the default one or replaced with a custom one
98
	 *
99
	 * @see set_datastore()
100
	 * @see get_datastore()
101
	 * @var object
102
	 */
103
	protected $has_default_datastore = true;
104
105
	/**
106
	 * The type of the container this field is in
107
	 *
108
	 * @see get_context()
109
	 * @var string
110
	 */
111
	protected $context;
112
113
	/**
114
	 * Whether or not this value should be auto loaded. Applicable to theme options only.
115
	 *
116
	 * @see set_autoload()
117
	 * @var bool
118
	 **/
119
	protected $autoload = false;
120
121
	/**
122
	 * Whether or not this field will be initialized when the field is in the viewport (visible).
123
	 *
124
	 * @see set_lazyload()
125
	 * @var bool
126
	 **/
127
	protected $lazyload = false;
128
129
	/**
130
	 * The width of the field.
131
	 *
132
	 * @see set_width()
133
	 * @var int
134
	 **/
135
	protected $width = 0;
136
137
	/**
138
	 * Custom CSS classes.
139
	 *
140
	 * @see add_class()
141
	 * @var array
142
	 **/
143
	protected $classes = array();
144
145
	/**
146
	 * Whether or not this field is required.
147
	 *
148
	 * @see set_required()
149
	 * @var bool
150
	 **/
151
	protected $required = false;
152
153
	/**
154
	 * Prefix to be prepended to the field name during load, save, delete and <strong>render</strong>
155
	 *
156
	 * @var string
157
	 **/
158
	protected $name_prefix = '_';
159
160
	/**
161
	 * Stores the field conditional logic rules.
162
	 *
163
	 * @var array
164
	 **/
165
	protected $conditional_logic = array();
166
167
	/**
168
	 * Create a new field of type $type and name $name and label $label.
169
	 *
170
	 * @param string $type
171
	 * @param string $name lower case and underscore-delimited
172
	 * @param string $label (optional) Automatically generated from $name if not present
173
	 * @return object $field
174
	 **/
175 14
	public static function factory( $type, $name, $label = null ) {
176
		// backward compatibility: `file` type used to be called `attachment`
177 14
		if ( $type === 'attachment' ) {
178
			$type = 'file';
179
		}
180
181 14
		$type = str_replace( ' ', '_', ucwords( str_replace( '_', ' ', $type ) ) );
182
183 14
		$class = __NAMESPACE__ . '\\' . $type . '_Field';
184
185 14 View Code Duplication
		if ( ! class_exists( $class ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
186 4
			Incorrect_Syntax_Exception::raise( 'Unknown field "' . $type . '".' );
187 1
			$class = __NAMESPACE__ . '\\Broken_Field';
188 1
		}
189
190 11
		$field = new $class( $name, $label );
191 10
		$field->type = $type;
192
193 10
		return $field;
194
	}
195
196
	/**
197
	 * An alias of factory().
198
	 *
199
	 * @see Field::factory()
200
	 **/
201 14
	public static function make( $type, $name, $label = null ) {
202 14
		return self::factory( $type, $name, $label );
203
	}
204
205
	/**
206
	 * Create a field from a certain type with the specified label.
207
	 * @param string $name  Field name
208
	 * @param string $label Field label
209
	 */
210 11 View Code Duplication
	protected function __construct( $name, $label ) {
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...
211 11
		$this->set_name( $name );
212 10
		$this->set_label( $label );
213 10
		$this->set_base_name( $name );
214
215
		// Pick random ID
216 10
		$random_string = md5( mt_rand() . $this->get_name() . $this->get_label() );
217 10
		$random_string = substr( $random_string, 0, 5 ); // 5 chars should be enough
218 10
		$this->id = 'carbon-' . $random_string;
219
220 10
		$this->init();
221 10
	}
222
223
	/**
224
	 * Boot the field once the container is attached.
225
	 **/
226
	public function boot() {
227
		$this->admin_init();
228
229
		$this->add_template( $this->get_type(), array( $this, 'template' ) );
230
231
		add_action( 'admin_footer', array( get_class(), 'admin_hook_scripts' ), 5 );
232
		add_action( 'admin_footer', array( get_class(), 'admin_hook_styles' ), 5 );
233
234
		add_action( 'admin_footer', array( get_class( $this ), 'admin_enqueue_scripts' ), 5 );
235
	}
236
237
	/**
238
	 * Perform instance initialization after calling setup()
239
	 **/
240
	public function init() {}
241
242
	/**
243
	 * Instance initialization when in the admin area.
244
	 * Called during field boot.
245
	 **/
246
	public function admin_init() {}
247
248
	/**
249
	 * Enqueue admin scripts.
250
	 * Called once per field type.
251
	 **/
252
	public static function admin_enqueue_scripts() {}
253
254
	/**
255
	 * Prints the main Underscore template
256
	 **/
257
	public function template() { }
258
259
	/**
260
	 * Returns all the Backbone templates
261
	 *
262
	 * @return array
263
	 **/
264
	public function get_templates() {
265
		return $this->templates;
266
	}
267
268
	/**
269
	 * Adds a new Backbone template
270
	 **/
271
	public function add_template( $name, $callback ) {
272
		$this->templates[ $name ] = $callback;
273
	}
274
275
	/**
276
	 * Delegate load to the field DataStore instance
277
	 **/
278
	public function load() {
279
		$this->get_datastore()->load( $this );
280
281
		if ( $this->get_value() === false ) {
282
			$this->set_value( $this->default_value );
283
		}
284
	}
285
286
	/**
287
	 * Delegate save to the field DataStore instance
288
	 **/
289
	public function save() {
290
		return $this->get_datastore()->save( $this );
291
	}
292
293
	/**
294
	 * Delegate delete to the field DataStore instance
295
	 **/
296
	public function delete() {
297
		return $this->get_datastore()->delete( $this );
298
	}
299
300
	/**
301
	 * Load the field value from an input array based on it's name
302
	 *
303
	 * @param array $input (optional) Array of field names and values. Defaults to $_POST
304
	 **/
305
	public function set_value_from_input( $input = null ) {
306
		if ( is_null( $input ) ) {
307
			$input = $_POST;
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
308
		}
309
310
		if ( ! isset( $input[ $this->name ] ) ) {
311
			$this->set_value( null );
312
		} else {
313
			$this->set_value( stripslashes_deep( $input[ $this->name ] ) );
314
		}
315
	}
316
317
	/**
318
	 * Return whether the datastore instance is the default one or has been overriden
319
	 *
320
	 * @return Datastore_Interface $datastore
321
	 **/
322
	public function has_default_datastore() {
323
		return $this->has_default_datastore;
324
	}
325
326
	/**
327
	 * Assign DataStore instance for use during load, save and delete
328
	 *
329
	 * @param object $datastore
330
	 * @return object $this
331
	 **/
332
	public function set_datastore( Datastore_Interface $datastore, $set_as_default = false ) {
333
		if ( $set_as_default && !$this->has_default_datastore() ) {
0 ignored issues
show
introduced by
Expected 1 space after "!"; 0 found
Loading history...
334
			return $this; // datastore has been overriden with a custom one - abort changing to a default one
335
		}
336
		$this->datastore = $datastore;
337
		$this->has_default_datastore = $set_as_default;
0 ignored issues
show
Documentation Bug introduced by
It seems like $set_as_default of type boolean is incompatible with the declared type object of property $has_default_datastore.

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...
338
		return $this;
339
	}
340
341
	/**
342
	 * Return the DataStore instance used by the field
343
	 *
344
	 * @return object $datastore
345
	 **/
346
	public function get_datastore() {
347
		return $this->datastore;
348
	}
349
350
	/**
351
	 * Assign the type of the container this field is in
352
	 *
353
	 * @param string
354
	 * @return object $this
355
	 **/
356
	public function set_context( $context ) {
357
		$this->context = $context;
358
		return $this;
359
	}
360
361
	/**
362
	 * Return the type of the container this field is in
363
	 *
364
	 * @return string
365
	 **/
366
	public function get_context() {
367
		return $this->context;
368
	}
369
370
	/**
371
	 * Directly modify the field value
372
	 *
373
	 * @param mixed $value
374
	 **/
375
	public function set_value( $value ) {
376
		$this->value = $value;
377
	}
378
379
	/**
380
	 * Set default field value
381
	 *
382
	 * @param mixed $default_value
383
	 **/
384
	public function set_default_value( $default_value ) {
385
		$this->default_value = $default_value;
386
		return $this;
387
	}
388
389
	/**
390
	 * Get default field value
391
	 *
392
	 * @return mixed
393
	 **/
394
	public function get_default_value() {
395
		return $this->default_value;
396
	}
397
398
	/**
399
	 * Return the field value
400
	 *
401
	 * @return mixed
402
	 **/
403
	public function get_value() {
404
		return $this->value;
405
	}
406
407
	/**
408
	 * Set field name.
409
	 * Use only if you are completely aware of what you are doing.
410
	 *
411
	 * @param string $name Field name, either sanitized or not
412
	 **/
413
	public function set_name( $name ) {
414
		$name = preg_replace( '~\s+~', '_', mb_strtolower( $name ) );
415
416
		if ( empty( $name ) ) {
417
			Incorrect_Syntax_Exception::raise( 'Field name can\'t be empty' );
418
		}
419
420
		if ( $this->name_prefix && strpos( $name, $this->name_prefix ) !== 0 ) {
421
			$name = $this->name_prefix . $name;
422
		}
423
424
		$this->name = $name;
425
	}
426
427
	/**
428
	 * Return the field name
429
	 *
430
	 * @return string
431
	 **/
432
	public function get_name() {
433
		return $this->name;
434
	}
435
436
	/**
437
	 * Set field base name as defined in the container.
438
	 **/
439
	public function set_base_name( $name ) {
440
		$this->base_name = $name;
441
	}
442
443
	/**
444
	 * Return the field base name.
445
	 *
446
	 * @return string
447
	 **/
448
	public function get_base_name() {
449
		return $this->base_name;
450
	}
451
452
	/**
453
	 * Set field name prefix. Calling this method will update the current field
454
	 * name and the conditional logic fields.
455
	 *
456
	 * @param string $prefix
457
	 * @return object $this
458
	 **/
459
	public function set_prefix( $prefix ) {
460
		$escaped_prefix = preg_quote( $this->name_prefix, '~' );
461
		$this->name = preg_replace( '~^' . $escaped_prefix . '~', '', $this->name );
462
		$this->name_prefix = $prefix;
463
		$this->name = $this->name_prefix . $this->name;
464
465
		return $this;
466
	}
467
468
	/**
469
	 * Set field label.
470
	 *
471
	 * @param string $label If null, the label will be generated from the field name
472
	 **/
473
	public function set_label( $label ) {
474
		// Try to guess field label from it's name
475 View Code Duplication
		if ( is_null( $label ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
476
			// remove the leading underscore(if it's there)
477
			$label = preg_replace( '~^_~', '', $this->name );
478
479
			// remove the leading "crb_"(if it's there)
480
			$label = preg_replace( '~^crb_~', '', $label );
481
482
			// split the name into words and make them capitalized
483
			$label = mb_convert_case( str_replace( '_', ' ', $label ), MB_CASE_TITLE );
484
		}
485
486
		$this->label = $label;
487
	}
488
489
	/**
490
	 * Return field label.
491
	 *
492
	 * @return string
493
	 **/
494
	public function get_label() {
495
		return $this->label;
496
	}
497
498
	/**
499
	 * Set additional text to be displayed during field render,
500
	 * containing information and guidance for the user
501
	 *
502
	 * @return object $this
503
	 **/
504
	public function set_help_text( $help_text ) {
505
		$this->help_text = $help_text;
506
		return $this;
507
	}
508
509
	/**
510
	 * Alias for set_help_text()
511
	 *
512
	 * @see set_help_text()
513
	 * @return object $this
514
	 **/
515
	public function help_text( $help_text ) {
516
		return $this->set_help_text( $help_text );
517
	}
518
519
	/**
520
	 * Return the field help text
521
	 *
522
	 * @return object $this
523
	 **/
524
	public function get_help_text() {
525
		return $this->help_text;
526
	}
527
528
	/**
529
	 * Whether or not this value should be auto loaded. Applicable to theme options only.
530
	 *
531
	 * @param bool $autoload
532
	 * @return object $this
533
	 **/
534
	public function set_autoload( $autoload ) {
535
		$this->autoload = $autoload;
536
		return $this;
537
	}
538
539
	/**
540
	 * Return whether or not this value should be auto loaded.
541
	 *
542
	 * @return bool
543
	 **/
544
	public function get_autoload() {
545
		return $this->autoload;
546
	}
547
548
	/**
549
	 * Whether or not this field will be initialized when the field is in the viewport (visible).
550
	 *
551
	 * @param bool $lazyload
552
	 * @return object $this
553
	 **/
554
	public function set_lazyload( $lazyload ) {
555
		$this->lazyload = $lazyload;
556
		return $this;
557
	}
558
559
	/**
560
	 * Return whether or not this field should be lazyloaded.
561
	 *
562
	 * @return bool
563
	 **/
564
	public function get_lazyload() {
565
		return $this->lazyload;
566
	}
567
568
	/**
569
	 * Set the field width.
570
	 *
571
	 * @param int $width
572
	 * @return object $this
573
	 **/
574
	public function set_width( $width ) {
575
		$this->width = (int) $width;
576
		return $this;
577
	}
578
579
	/**
580
	 * Get the field width.
581
	 *
582
	 * @return int $width
583
	 **/
584
	public function get_width() {
585
		return $this->width;
586
	}
587
588
	/**
589
	 *  Add custom CSS class to the field html container.
590
	 *
591
	 * @param string|array $classes
592
	 * @return object $this
593
	 **/
594
	public function add_class( $classes ) {
595
		if ( ! is_array( $classes ) ) {
596
			$classes = array_values( array_filter( explode( ' ', $classes ) ) );
597
		}
598
599
		$this->classes = array_map( 'sanitize_html_class', $classes );
600
		return $this;
601
	}
602
603
	/**
604
	 * Get the field custom CSS classes.
605
	 *
606
	 * @return array
607
	 **/
608
	public function get_classes() {
609
		return $this->classes;
610
	}
611
612
	/**
613
	 * Whether this field is mandatory for the user
614
	 *
615
	 * @param bool $required
616
	 * @return object $this
617
	 **/
618
	public function set_required( $required = true ) {
619
		$this->required = $required;
620
		return $this;
621
	}
622
623
	/**
624
	 * HTML id attribute getter.
625
	 * @return string
626
	 */
627 1
	public function get_id() {
628 1
		return $this->id;
629
	}
630
631
	/**
632
	 * HTML id attribute setter
633
	 * @param string $id
634
	 */
635 1
	public function set_id( $id ) {
636 1
		$this->id = $id;
637 1
	}
638
639
	/**
640
	 * Return whether this field is mandatory for the user
641
	 *
642
	 * @return bool
643
	 **/
644
	public function is_required() {
645
		return $this->required;
646
	}
647
648
	/**
649
	 * Returns the type of the field based on the class.
650
	 * The class is stripped by the "CarbonFields" prefix.
651
	 * Also the "Field" suffix is removed.
652
	 * Then underscores and backslashes are removed.
653
	 *
654
	 * @return string
655
	 */
656
	public function get_type() {
657
		$class = get_class( $this );
658
659
		return $this->clean_type( $class );
660
	}
661
662
	/**
663
	 * Cleans up an object class for usage as HTML class
664
	 *
665
	 * @return string
666
	 */
667
	protected function clean_type( $type ) {
668
		$remove = array(
669
			'_',
670
			'\\',
671
			'CarbonFields',
672
			'Field',
673
		);
674
		$clean_class = str_replace( $remove, '', $type );
675
676
		return $clean_class;
677
	}
678
679
	/**
680
	 * Return an array of html classes to be used for the field container
681
	 *
682
	 * @return array
683
	 */
684
	public function get_html_class() {
685
		$html_classes = array();
686
687
		$object_class = get_class( $this );
688
		$html_classes[] = $this->get_type();
689
690
		$parent_class = $object_class;
691
		while ( $parent_class = get_parent_class( $parent_class ) ) {
692
			$clean_class = $this->clean_type( $parent_class );
693
694
			if ( $clean_class ) {
695
				$html_classes[] = $clean_class;
696
			}
697
		}
698
699
		return $html_classes;
700
	}
701
702
	/**
703
	 * Allows the value of a field to be processed after loading.
704
	 * Can be implemented by the extending class if necessary.
705
	 *
706
	 * @return array
707
	 */
708
	public function process_value() {
709
710
	}
711
712
	/**
713
	 * Returns an array that holds the field data, suitable for JSON representation.
714
	 * This data will be available in the Underscore template and the Backbone Model.
715
	 *
716
	 * @param bool $load  Should the value be loaded from the database or use the value from the current instance.
717
	 * @return array
718
	 */
719
	public function to_json( $load ) {
720
		if ( $load ) {
721
			$this->load();
722
		}
723
724
		$this->process_value();
725
726
		$field_data = array(
727
			'id' => $this->get_id(),
728
			'type' => $this->get_type(),
729
			'label' => $this->get_label(),
730
			'name' => $this->get_name(),
731
			'base_name' => $this->get_base_name(),
732
			'value' => $this->get_value(),
733
			'default_value' => $this->get_default_value(),
734
			'help_text' => $this->get_help_text(),
735
			'context' => $this->get_context(),
736
			'required' => $this->is_required(),
737
			'lazyload' => $this->get_lazyload(),
738
			'width' => $this->get_width(),
739
			'classes' => $this->get_classes(),
740
			'conditional_logic' => $this->get_conditional_logic(),
741
		);
742
743
		return $field_data;
744
	}
745
746
	/**
747
	 * Set the field visibility conditional logic.
748
	 *
749
	 * @param array
750
	 */
751 8
	public function set_conditional_logic( $rules ) {
752 8
		$this->conditional_logic = $this->parse_conditional_rules( $rules );
753
754 3
		return $this;
755
	}
756
757
	/**
758
	 * Get the conditional logic rules
759
	 *
760
	 * @return array
761
	 */
762 3
	public function get_conditional_logic() {
763 3
		return $this->conditional_logic;
764
	}
765
766
	/**
767
	 * Validate and parse the conditional logic rules.
768
	 *
769
	 * @param array $rules
770
	 * @return array
771
	 */
772
	protected function parse_conditional_rules( $rules ) {
773
		if ( ! is_array( $rules ) ) {
774
			Incorrect_Syntax_Exception::raise( 'Conditional logic rules argument should be an array.' );
775
		}
776
777
		$allowed_operators = array( '=', '!=', '>', '>=', '<', '<=', 'IN', 'NOT IN', 'INCLUDES', 'EXCLUDES' );
778
		$allowed_relations = array( 'AND', 'OR' );
779
780
		$parsed_rules = array(
781
			'relation' => 'AND',
782
			'rules' => array(),
783
		);
784
785
		foreach ( $rules as $key => $rule ) {
786
			// Check if we have a relation key
787 View Code Duplication
			if ( $key === 'relation' ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
788
				$relation = strtoupper( $rule );
789
790
				if ( ! in_array( $relation, $allowed_relations ) ) {
791
					Incorrect_Syntax_Exception::raise( 'Invalid relation type ' . $rule . '. ' .
792
					'The rule should be one of the following: "' . implode( '", "', $allowed_relations ) . '"' );
793
				}
794
795
				$parsed_rules['relation'] = $relation;
796
				continue;
797
			}
798
799
			// Check if the rule is valid
800
			if ( ! is_array( $rule ) || empty( $rule['field'] ) ) {
801
				Incorrect_Syntax_Exception::raise( 'Invalid conditional logic rule format. ' .
802
				'The rule should be an array with the "field" key set.' );
803
			}
804
805
			// Check the compare operator
806
			if ( empty( $rule['compare'] ) ) {
807
				$rule['compare'] = '=';
808
			}
809
			if ( ! in_array( $rule['compare'], $allowed_operators ) ) {
810
				Incorrect_Syntax_Exception::raise( 'Invalid conditional logic compare operator: <code>' .
811
					$rule['compare'] . '</code><br>Allowed operators are: <code>' .
812
				implode( ', ', $allowed_operators ) . '</code>' );
813
			}
814
			if ( $rule['compare'] === 'IN' || $rule['compare'] === 'NOT IN' ) {
815
				if ( ! is_array( $rule['value'] ) ) {
816
					Incorrect_Syntax_Exception::raise( 'Invalid conditional logic value format. ' .
817
					'An array is expected, when using the "' . $rule['compare'] . '" operator.' );
818
				}
819
			}
820
821
			// Check the value
822
			if ( ! isset( $rule['value'] ) ) {
823
				$rule['value'] = '';
824
			}
825
826
			$parsed_rules['rules'][] = $rule;
827
		}
828
829
		return $parsed_rules;
830
	}
831
832
833
	/**
834
	 * Hook administration scripts.
835
	 */
836
	public static function admin_hook_scripts() {
837
		wp_enqueue_media();
838
		wp_enqueue_script( 'carbon-fields', \Carbon_Fields\URL . '/assets/js/fields.js', array( 'carbon-app', 'carbon-containers' ), \Carbon_Fields\VERSION );
839
		wp_localize_script( 'carbon-fields', 'crbl10n',
840
			array(
841
				'title' => __( 'Files', 'carbon-fields' ),
842
				'geocode_zero_results' => __( 'The address could not be found. ', 'carbon-fields' ),
843
				'geocode_not_successful' => __( 'Geocode was not successful for the following reason: ', 'carbon-fields' ),
844
				'max_num_items_reached' => __( 'Maximum number of items reached (%s items)', 'carbon-fields' ),
845
				'max_num_rows_reached' => __( 'Maximum number of rows reached (%s rows)', 'carbon-fields' ),
846
				'cannot_create_more_rows' => __( 'Cannot create more than %s rows', 'carbon-fields' ),
847
				'complex_no_rows' => __( 'There are no %s yet. Click <a href="#">here</a> to add one.', 'carbon-fields' ),
848
				'complex_add_button' => __( 'Add %s', 'carbon-fields' ),
849
				'complex_min_num_rows_not_reached' => __( 'Minimum number of rows not reached (%1$d %2$s)', 'carbon-fields' ),
850
				'message_form_validation_failed' => __( 'Please fill out all fields correctly. ', 'carbon-fields' ),
851
				'message_required_field' => __( 'This field is required. ', 'carbon-fields' ),
852
				'message_choose_option' => __( 'Please choose an option. ', 'carbon-fields' ),
853
854
				'enter_name_of_new_sidebar' => __( 'Please enter the name of the new sidebar:', 'carbon-fields' ),
855
			)
856
		);
857
	}
858
859
	/**
860
	 * Hook administration styles.
861
	 */
862
	public static function admin_hook_styles() {
863
		wp_enqueue_style( 'thickbox' );
864
	}
865
} // END Field
866