Completed
Push — milestone/2.0 ( 27edeb...debc3a )
by
unknown
02:20
created

Field::get_name()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
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\Value_Set\Value_Set;
8
use Carbon_Fields\Exception\Incorrect_Syntax_Exception;
9
10
/**
11
 * Base field class.
12
 * Defines the key container methods and their default implementations.
13
 * Implements factory design pattern.
14
 **/
15
class Field implements Datastore_Holder_Interface {
16
	/**
17
	 * Stores all the field Backbone templates
18
	 *
19
	 * @see factory()
20
	 * @see add_template()
21
	 * @var array
22
	 */
23
	protected $templates = array();
24
25
	/**
26
	 * Globally unique field identificator. Generated randomly
27
	 *
28
	 * @var string
29
	 */
30
	protected $id;
31
32
	/**
33
	 * Stores the initial <kbd>$type</kbd> variable passed to the <code>factory()</code> method
34
	 *
35
	 * @see factory
36
	 * @var string
37
	 */
38
	public $type;
39
40
	/**
41
	 * Array of ancestor field names
42
	 *
43
	 * @var array
44
	 **/
45
	protected $hierarchy = array();
46
47
	/**
48
	 * Array of complex entry ids
49
	 *
50
	 * @var array
51
	 **/
52
	protected $hierarchy_index = array();
53
54
	/**
55
	 * Field value
56
	 *
57
	 * @var Value_Set
58
	 */
59
	protected $value;
60
61
	/**
62
	 * Default field value
63
	 *
64
	 * @var mixed
65
	 */
66
	protected $default_value;
67
68
	/**
69
	 * Sanitized field name used as input name attribute during field render
70
	 *
71
	 * @see factory()
72
	 * @see set_name()
73
	 * @var string
74
	 */
75
	protected $name;
76
77
	/**
78
	 * The base field name which is used in the container.
79
	 *
80
	 * @see set_base_name()
81
	 * @var string
82
	 */
83
	protected $base_name;
84
85
	/**
86
	 * Field name used as label during field render
87
	 *
88
	 * @see factory()
89
	 * @see set_label()
90
	 * @var string
91
	 */
92
	protected $label;
93
94
	/**
95
	 * Additional text containing information and guidance for the user
96
	 *
97
	 * @see help_text()
98
	 * @var string
99
	 */
100
	protected $help_text;
101
102
	/**
103
	 * Field DataStore instance to which save, load and delete calls are delegated
104
	 *
105
	 * @see set_datastore()
106
	 * @see get_datastore()
107
	 * @var Datastore_Interface
108
	 */
109
	protected $datastore;
110
111
	/**
112
	 * Flag whether the datastore is the default one or replaced with a custom one
113
	 *
114
	 * @see set_datastore()
115
	 * @see get_datastore()
116
	 * @var boolean
117
	 */
118
	protected $has_default_datastore = true;
119
120
	/**
121
	 * The type of the container this field is in
122
	 *
123
	 * @see get_context()
124
	 * @var string
125
	 */
126
	protected $context;
127
128
	/**
129
	 * Whether or not this value should be auto loaded. Applicable to theme options only.
130
	 *
131
	 * @see set_autoload()
132
	 * @var bool
133
	 **/
134
	protected $autoload = false;
135
136
	/**
137
	 * Whether or not this field will be initialized when the field is in the viewport (visible).
138
	 *
139
	 * @see set_lazyload()
140
	 * @var bool
141
	 **/
142
	protected $lazyload = false;
143
144
	/**
145
	 * The width of the field.
146
	 *
147
	 * @see set_width()
148
	 * @var int
149
	 **/
150
	protected $width = 0;
151
152
	/**
153
	 * Custom CSS classes.
154
	 *
155
	 * @see add_class()
156
	 * @var array
157
	 **/
158
	protected $classes = array();
159
160
	/**
161
	 * Whether or not this field is required.
162
	 *
163
	 * @see set_required()
164
	 * @var bool
165
	 **/
166
	protected $required = false;
167
168
	/**
169
	 * Stores the field conditional logic rules.
170
	 *
171
	 * @var array
172
	 **/
173
	protected $conditional_logic = array();
174
175
	/**
176
	 * Clone the Value_Set object as well
177
	 *
178
	 * @var array
179
	 **/
180
    public function __clone() {
181
        $this->value = clone $this->value();
182
    }
183
184
	/**
185
	 * Create a new field of type $type and name $name and label $label.
186
	 *
187
	 * @param string $type
188
	 * @param string $name lower case and underscore-delimited
189
	 * @param string $label (optional) Automatically generated from $name if not present
190
	 * @return Field
191
	 **/
192 15
	public static function factory( $type, $name, $label = null ) {
193
		// backward compatibility: `file` type used to be called `attachment`
194 15
		if ( $type === 'attachment' ) {
195
			$type = 'file';
196
		}
197
198 15
		$type = str_replace( ' ', '_', ucwords( str_replace( '_', ' ', $type ) ) );
199
200 15
		$class = __NAMESPACE__ . '\\' . $type . '_Field';
201
202 15 View Code Duplication
		if ( ! class_exists( $class ) ) {
203 4
			Incorrect_Syntax_Exception::raise( 'Unknown field "' . $type . '".' );
204 1
			$class = __NAMESPACE__ . '\\Broken_Field';
205 1
		}
206
207 12
		$field = new $class( $name, $label );
208 10
		$field->type = $type;
209
210 10
		return $field;
211
	}
212
213
	/**
214
	 * An alias of factory().
215
	 *
216
	 * @see Field::factory()
217
	 * @return Field
218
	 **/
219 15
	public static function make( $type, $name, $label = null ) {
220 15
		return static::factory( $type, $name, $label );
221
	}
222
223
	/**
224
	 * Create a field from a certain type with the specified label.
225
	 * @param string $name  Field name
226
	 * @param string $label Field label
227
	 */
228 12 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...
229 12
		$this->set_base_name( $name );
230 12
		$this->set_name( $name );
231 10
		$this->set_label( $label );
232
233
		// Pick random ID
234 10
		$random_string = md5( mt_rand() . $this->get_name() . $this->get_label() );
235 10
		$random_string = substr( $random_string, 0, 5 ); // 5 chars should be enough
236 10
		$this->id = 'carbon-' . $random_string;
237
238 10
		$this->init();
239 10
	}
240
241
	/**
242
	 * Boot the field once the container is attached.
243
	 **/
244
	public function boot() {
245
		$this->admin_init();
246
247
		$this->add_template( $this->get_type(), array( $this, 'template' ) );
248
249
		add_action( 'admin_footer', array( get_class(), 'admin_hook_scripts' ), 5 );
250
		add_action( 'admin_footer', array( get_class(), 'admin_hook_styles' ), 5 );
251
252
		add_action( 'admin_footer', array( get_class( $this ), 'admin_enqueue_scripts' ), 5 );
253
	}
254
255
	/**
256
	 * Set array of hierarchy field names
257
	 *
258
	 * @return array
259
	 **/
260
	public function set_hierarchy( $hierarchy ) {
261
		$this->hierarchy = $hierarchy;
262
	}
263
264
	/**
265
	 * Get array of hierarchy field names
266
	 *
267
	 * @return array
268
	 **/
269
	public function get_hierarchy() {
270
		return $this->hierarchy;
271
	}
272
273
	/**
274
	 * Set array of hierarchy indexes
275
	 *
276
	 * @return array
277
	 **/
278
	public function set_hierarchy_index( $hierarchy_index ) {
279
		$this->hierarchy_index = $hierarchy_index;
280
	}
281
282
	/**
283
	 * Get array of hierarchy indexes
284
	 *
285
	 * @return array
286
	 **/
287
	public function get_hierarchy_index() {
288
		return $this->hierarchy_index;
289
	}
290
291
	/**
292
	 * Return whether the field is a root field and holds a single value
293
	 *
294
	 * @return bool
295
	 **/
296
	public function is_simple_root_field() {
297
		$hierarchy = $this->get_hierarchy();
298
		return (
299
			empty( $hierarchy )
300
			&&
301
			(
302
				$this->value()->get_type() === Value_Set::TYPE_SINGLE_VALUE
303
				||
304
				$this->value()->get_type() === Value_Set::TYPE_MULTIPLE_PROPERTIES
305
			)
306
		);
307
	}
308
309
	/**
310
	 * Perform instance initialization
311
	 **/
312
	public function init() {}
313
314
	/**
315
	 * Instance initialization when in the admin area.
316
	 * Called during field boot.
317
	 **/
318
	public function admin_init() {}
319
320
	/**
321
	 * Enqueue admin scripts.
322
	 * Called once per field type.
323
	 **/
324
	public static function admin_enqueue_scripts() {}
325
326
	/**
327
	 * Prints the main Underscore template
328
	 **/
329
	public function template() { }
330
331
	/**
332
	 * Returns all the Backbone templates
333
	 *
334
	 * @return array
335
	 **/
336
	public function get_templates() {
337
		return $this->templates;
338
	}
339
340
	/**
341
	 * Adds a new Backbone template
342
	 **/
343
	protected function add_template( $name, $callback ) {
344
		$this->templates[ $name ] = $callback;
345
	}
346
347
	/**
348
	 * Load value from datastore
349
	 **/
350 2
	public function load() {
351 2
		$raw_value_set_tree = $this->get_datastore()->load( $this );
352 2
		$value = null;
353 2
		if ( isset( $raw_value_set_tree[ $this->get_base_name() ] ) ) {
354 1
			$value = $raw_value_set_tree[ $this->get_base_name() ]['value_set'];
355 1
		}
356 2
		$this->set_value( $value );
357
358 2
		if ( $this->get_value() === null ) {
359 1
			$this->set_value( $this->get_default_value() );
360 1
		}
361 2
	}
362
363
	/**
364
	 * Save value to storage
365
	 **/
366 1
	public function save() {
367 1
		return $this->get_datastore()->save( $this );
368
	}
369
370
	/**
371
	 * Delete value from storage
372
	 */
373 1
	public function delete() {
374 1
		$this->get_datastore()->delete( $this );
375 1
	}
376
377
	/**
378
	 * Load the field value from an input array based on it's name
379
	 *
380
	 * @param array $input (optional) Array of field names and values. Defaults to $_POST
381
	 **/
382
	public function set_value_from_input( $input = null ) {
383
		if ( is_null( $input ) ) {
384
			$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...
385
		}
386
387
		if ( ! isset( $input[ $this->name ] ) ) {
388
			$this->set_value( array() );
389
		} else {
390
			$this->set_value( stripslashes_deep( $input[ $this->name ] ) );
391
		}
392
	}
393
394
	/**
395
	 * Return whether the datastore instance is the default one or has been overriden
396
	 *
397
	 * @return boolean
398
	 **/
399
	public function has_default_datastore() {
400
		return $this->has_default_datastore;
401
	}
402
403
	/**
404
	 * Set datastore instance
405
	 *
406
	 * @param Datastore_Interface $datastore
407
	 * @return object $this
408
	 **/
409 1
	public function set_datastore( Datastore_Interface $datastore, $set_as_default = false ) {
410 1
		if ( $set_as_default && ! $this->has_default_datastore() ) {
411
			return $this; // datastore has been overriden with a custom one - abort changing to a default one
412
		}
413 1
		$this->datastore = $datastore;
414 1
		$this->has_default_datastore = $set_as_default;
415 1
		return $this;
416
	}
417
418
	/**
419
	 * Get the DataStore instance
420
	 *
421
	 * @return Datastore_Interface $datastore
422
	 **/
423 1
	public function get_datastore() {
424 1
		return $this->datastore;
425
	}
426
427
	/**
428
	 * Assign the type of the container this field is in
429
	 *
430
	 * @param string
431
	 * @return object $this
432
	 **/
433
	public function set_context( $context ) {
434
		$this->context = $context;
435
		return $this;
436
	}
437
438
	/**
439
	 * Return the type of the container this field is in
440
	 *
441
	 * @return string
442
	 **/
443
	public function get_context() {
444
		return $this->context;
445
	}
446
447
	/**
448
	 * Return a reference to the Value_Set
449
	 *
450
	 * @return Value_Set
451
	 **/
452
	public function value() {
453
		if ( $this->value === null ) {
454
			$this->value = new Value_Set();
455
		}
456
		return $this->value;
457
	}
458
459
	/**
460
	 * Alias for $this->value()->get();
461
	 *
462
	 * @return mixed
463
	 **/
464 3
	public function get_value() {
465 3
		return $this->value()->get();
466
	}
467
468
	/**
469
	 * Return a differently formatted value for end-users
470
	 *
471
	 * @return mixed
472
	 **/
473
	public function get_formatted_value() {
474
		$value = $this->get_value();
475
		if ( $value === null ) {
476
			$value = $this->get_default_value();
477
		}
478
		return $value;
479
	}
480
481
	/**
482
	 * Alias for $this->value()->set( $value );
483
	 **/
484 1
	public function set_value( $value ) {
485 1
		return $this->value()->set( $value );
486
	}
487
488
	/**
489
	 * Set default field value
490
	 *
491
	 * @param mixed $default_value
492
	 **/
493 1
	public function set_default_value( $default_value ) {
494 1
		$this->default_value = $default_value;
495 1
		return $this;
496
	}
497
498
	/**
499
	 * Get default field value
500
	 *
501
	 * @return mixed
502
	 **/
503 1
	public function get_default_value() {
504 1
		return $this->default_value;
505
	}
506
507
	/**
508
	 * Set field name.
509
	 * Use only if you are completely aware of what you are doing.
510
	 *
511
	 * @param string $name Field name, either sanitized or not
512
	 **/
513 5
	public function set_name( $name ) {
514 5
		$name = mb_strtolower( $name );
515 5
		$name = preg_replace( '~\s+~', '_', $name );
516
517 5
		if ( empty( $name ) ) {
518
			Incorrect_Syntax_Exception::raise( 'Field name can\'t be empty' );
519
		}
520
521 5
		$regex = '/[\|\:]+/';
522 5
		if ( preg_match( $regex, $name ) ) {
523
			Incorrect_Syntax_Exception::raise( 'Field name "' . $name . '" cannot contain "|" or ":" characters.' );
524
		}
525
526
		// Prefix with an underscore
527 5
		$name = ( substr( $name, 0, 1 ) !== '_' ? '_' . $name : $name );
528
529 5
		$this->name = $name;
530 5
	}
531
532
	/**
533
	 * Return the field name
534
	 *
535
	 * @return string
536
	 **/
537 5
	public function get_name() {
538 5
		return $this->name;
539
	}
540
541
	/**
542
	 * Set field base name as defined in the container.
543
	 **/
544
	public function set_base_name( $name ) {
545
		$this->base_name = $name;
546
	}
547
548
	/**
549
	 * Return the field base name.
550
	 *
551
	 * @return string
552
	 **/
553
	public function get_base_name() {
554
		return $this->base_name;
555
	}
556
557
	/**
558
	 * Set field label.
559
	 *
560
	 * @param string $label If null, the label will be generated from the field name
561
	 **/
562 View Code Duplication
	public function set_label( $label ) {
1 ignored issue
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...
563
		// Try to guess field label from it's name
564
		if ( is_null( $label ) ) {
565
			// remove the leading underscore(if it's there)
566
			$label = preg_replace( '~^_~', '', $this->name );
567
568
			// remove the leading "crb_"(if it's there)
569
			$label = preg_replace( '~^crb_~', '', $label );
570
571
			// split the name into words and make them capitalized
572
			$label = mb_convert_case( str_replace( '_', ' ', $label ), MB_CASE_TITLE );
573
		}
574
575
		$this->label = $label;
576
	}
577
578
	/**
579
	 * Return field label.
580
	 *
581
	 * @return string
582
	 **/
583
	public function get_label() {
584
		return $this->label;
585
	}
586
587
	/**
588
	 * Set additional text to be displayed during field render,
589
	 * containing information and guidance for the user
590
	 *
591
	 * @return object $this
592
	 **/
593
	public function set_help_text( $help_text ) {
594
		$this->help_text = $help_text;
595
		return $this;
596
	}
597
598
	/**
599
	 * Alias for set_help_text()
600
	 *
601
	 * @see set_help_text()
602
	 * @return object $this
603
	 **/
604
	public function help_text( $help_text ) {
605
		return $this->set_help_text( $help_text );
606
	}
607
608
	/**
609
	 * Return the field help text
610
	 *
611
	 * @return object $this
612
	 **/
613
	public function get_help_text() {
614
		return $this->help_text;
615
	}
616
617
	/**
618
	 * Whether or not this value should be auto loaded. Applicable to theme options only.
619
	 *
620
	 * @param bool $autoload
621
	 * @return object $this
622
	 **/
623
	public function set_autoload( $autoload ) {
624
		$this->autoload = $autoload;
625
		return $this;
626
	}
627
628
	/**
629
	 * Return whether or not this value should be auto loaded.
630
	 *
631
	 * @return bool
632
	 **/
633
	public function get_autoload() {
634
		return $this->autoload;
635
	}
636
637
	/**
638
	 * Whether or not this field will be initialized when the field is in the viewport (visible).
639
	 *
640
	 * @param bool $lazyload
641
	 * @return object $this
642
	 **/
643
	public function set_lazyload( $lazyload ) {
644
		$this->lazyload = $lazyload;
645
		return $this;
646
	}
647
648
	/**
649
	 * Return whether or not this field should be lazyloaded.
650
	 *
651
	 * @return bool
652
	 **/
653
	public function get_lazyload() {
654
		return $this->lazyload;
655
	}
656
657
	/**
658
	 * Set the field width.
659
	 *
660
	 * @param int $width
661
	 * @return object $this
662
	 **/
663
	public function set_width( $width ) {
664
		$this->width = (int) $width;
665
		return $this;
666
	}
667
668
	/**
669
	 * Get the field width.
670
	 *
671
	 * @return int $width
672
	 **/
673
	public function get_width() {
674
		return $this->width;
675
	}
676
677
	/**
678
	 *  Add custom CSS class to the field html container.
679
	 *
680
	 * @param string|array $classes
681
	 * @return object $this
682
	 **/
683
	public function add_class( $classes ) {
684
		if ( ! is_array( $classes ) ) {
685
			$classes = array_values( array_filter( explode( ' ', $classes ) ) );
686
		}
687
688
		$this->classes = array_map( 'sanitize_html_class', $classes );
689
		return $this;
690
	}
691
692
	/**
693
	 * Get the field custom CSS classes.
694
	 *
695
	 * @return array
696
	 **/
697
	public function get_classes() {
698
		return $this->classes;
699
	}
700
701
	/**
702
	 * Whether this field is mandatory for the user
703
	 *
704
	 * @param bool $required
705
	 * @return object $this
706
	 **/
707
	public function set_required( $required = true ) {
708
		$this->required = $required;
709
		return $this;
710
	}
711
712
	/**
713
	 * HTML id attribute getter.
714
	 * @return string
715
	 */
716 1
	public function get_id() {
717 1
		return $this->id;
718
	}
719
720
	/**
721
	 * HTML id attribute setter
722
	 * @param string $id
723
	 */
724 1
	public function set_id( $id ) {
725 1
		$this->id = $id;
726 1
	}
727
728
	/**
729
	 * Return whether this field is mandatory for the user
730
	 *
731
	 * @return bool
732
	 **/
733
	public function is_required() {
734
		return $this->required;
735
	}
736
737
	/**
738
	 * Returns the type of the field based on the class.
739
	 * The class is stripped by the "CarbonFields" prefix.
740
	 * Also the "Field" suffix is removed.
741
	 * Then underscores and backslashes are removed.
742
	 *
743
	 * @return string
744
	 */
745
	public function get_type() {
746
		$class = get_class( $this );
747
748
		return $this->clean_type( $class );
749
	}
750
751
	/**
752
	 * Cleans up an object class for usage as HTML class
753
	 *
754
	 * @return string
755
	 */
756
	protected function clean_type( $type ) {
757
		$remove = array(
758
			'_',
759
			'\\',
760
			'CarbonFields',
761
			'Field',
762
		);
763
		$clean_class = str_replace( $remove, '', $type );
764
765
		return $clean_class;
766
	}
767
768
	/**
769
	 * Return an array of html classes to be used for the field container
770
	 *
771
	 * @return array
772
	 */
773
	public function get_html_class() {
774
		$html_classes = array();
775
776
		$object_class = get_class( $this );
777
		$html_classes[] = $this->get_type();
778
779
		$parent_class = $object_class;
780
		while ( $parent_class = get_parent_class( $parent_class ) ) {
781
			$clean_class = $this->clean_type( $parent_class );
782
783
			if ( $clean_class ) {
784
				$html_classes[] = $clean_class;
785
			}
786
		}
787
788
		return $html_classes;
789
	}
790
791
	/**
792
	 * Returns an array that holds the field data, suitable for JSON representation.
793
	 * This data will be available in the Underscore template and the Backbone Model.
794
	 *
795
	 * @param bool $load  Should the value be loaded from the database or use the value from the current instance.
796
	 * @return array
797
	 */
798
	public function to_json( $load ) {
799
		if ( $load ) {
800
			$this->load();
801
		}
802
803
		$field_data = array(
804
			'id' => $this->get_id(),
805
			'type' => $this->get_type(),
806
			'label' => $this->get_label(),
807
			'name' => $this->get_name(),
808
			'base_name' => $this->get_base_name(),
809
			'value' => $this->get_value(),
810
			'default_value' => $this->get_default_value(),
811
			'help_text' => $this->get_help_text(),
812
			'context' => $this->get_context(),
813
			'required' => $this->is_required(),
814
			'lazyload' => $this->get_lazyload(),
815
			'width' => $this->get_width(),
816
			'classes' => $this->get_classes(),
817
			'conditional_logic' => $this->get_conditional_logic(),
818
		);
819
820
		return $field_data;
821
	}
822
823
	/**
824
	 * Set the field visibility conditional logic.
825
	 *
826
	 * @param array
827
	 */
828 8
	public function set_conditional_logic( $rules ) {
829 8
		$this->conditional_logic = $this->parse_conditional_rules( $rules );
830
831 3
		return $this;
832
	}
833
834
	/**
835
	 * Get the conditional logic rules
836
	 *
837
	 * @return array
838
	 */
839 3
	public function get_conditional_logic() {
840 3
		return $this->conditional_logic;
841
	}
842
843
	/**
844
	 * Validate and parse the conditional logic rules.
845
	 *
846
	 * @param array $rules
847
	 * @return array
848
	 */
849
	protected function parse_conditional_rules( $rules ) {
850
		if ( ! is_array( $rules ) ) {
851
			Incorrect_Syntax_Exception::raise( 'Conditional logic rules argument should be an array.' );
852
		}
853
854
		$allowed_operators = array( '=', '!=', '>', '>=', '<', '<=', 'IN', 'NOT IN' );
855
		$allowed_relations = array( 'AND', 'OR' );
856
857
		$parsed_rules = array(
858
			'relation' => 'AND',
859
			'rules' => array(),
860
		);
861
862
		foreach ( $rules as $key => $rule ) {
863
			// Check if we have a relation key
864 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...
865
				$relation = strtoupper( $rule );
866
867
				if ( ! in_array( $relation, $allowed_relations ) ) {
868
					Incorrect_Syntax_Exception::raise( 'Invalid relation type ' . $rule . '. ' .
869
					'The rule should be one of the following: "' . implode( '", "', $allowed_relations ) . '"' );
870
				}
871
872
				$parsed_rules['relation'] = $relation;
873
				continue;
874
			}
875
876
			// Check if the rule is valid
877
			if ( ! is_array( $rule ) || empty( $rule['field'] ) ) {
878
				Incorrect_Syntax_Exception::raise( 'Invalid conditional logic rule format. ' .
879
				'The rule should be an array with the "field" key set.' );
880
			}
881
882
			// Check the compare operator
883
			if ( empty( $rule['compare'] ) ) {
884
				$rule['compare'] = '=';
885
			}
886
			if ( ! in_array( $rule['compare'], $allowed_operators ) ) {
887
				Incorrect_Syntax_Exception::raise( 'Invalid conditional logic compare operator: <code>' .
888
					$rule['compare'] . '</code><br>Allowed operators are: <code>' .
889
				implode( ', ', $allowed_operators ) . '</code>' );
890
			}
891
			if ( $rule['compare'] === 'IN' || $rule['compare'] === 'NOT IN' ) {
892
				if ( ! is_array( $rule['value'] ) ) {
893
					Incorrect_Syntax_Exception::raise( 'Invalid conditional logic value format. ' .
894
					'An array is expected, when using the "' . $rule['compare'] . '" operator.' );
895
				}
896
			}
897
898
			// Check the value
899
			if ( ! isset( $rule['value'] ) ) {
900
				$rule['value'] = '';
901
			}
902
903
			$parsed_rules['rules'][] = $rule;
904
		}
905
906
		return $parsed_rules;
907
	}
908
909
910
	/**
911
	 * Hook administration scripts.
912
	 */
913
	public static function admin_hook_scripts() {
914
		wp_enqueue_media();
915
		wp_enqueue_script( 'carbon-fields', \Carbon_Fields\URL . '/assets/js/fields.js', array( 'carbon-app', 'carbon-containers' ), \Carbon_Fields\VERSION );
916
		wp_localize_script( 'carbon-fields', 'crbl10n',
917
			array(
918
				'title' => __( 'Files', \Carbon_Fields\TEXT_DOMAIN ),
919
				'geocode_zero_results' => __( 'The address could not be found. ', \Carbon_Fields\TEXT_DOMAIN ),
920
				'geocode_not_successful' => __( 'Geocode was not successful for the following reason: ', \Carbon_Fields\TEXT_DOMAIN ),
921
				'max_num_items_reached' => __( 'Maximum number of items reached (%s items)', \Carbon_Fields\TEXT_DOMAIN ),
922
				'max_num_rows_reached' => __( 'Maximum number of rows reached (%s rows)', \Carbon_Fields\TEXT_DOMAIN ),
923
				'cannot_create_more_rows' => __( 'Cannot create more than %s rows', \Carbon_Fields\TEXT_DOMAIN ),
924
				'complex_no_rows' => __( 'There are no %s yet. Click <a href="#">here</a> to add one.', \Carbon_Fields\TEXT_DOMAIN ),
925
				'complex_add_button' => __( 'Add %s', \Carbon_Fields\TEXT_DOMAIN ),
926
				'complex_min_num_rows_not_reached' => __( 'Minimum number of rows not reached (%1$d %2$s)', \Carbon_Fields\TEXT_DOMAIN ),
927
				'message_form_validation_failed' => __( 'Please fill out all fields correctly. ', \Carbon_Fields\TEXT_DOMAIN ),
928
				'message_required_field' => __( 'This field is required. ', \Carbon_Fields\TEXT_DOMAIN ),
929
				'message_choose_option' => __( 'Please choose an option. ', \Carbon_Fields\TEXT_DOMAIN ),
930
931
				'enter_name_of_new_sidebar' => __( 'Please enter the name of the new sidebar:', \Carbon_Fields\TEXT_DOMAIN ),
932
			)
933
		);
934
	}
935
936
	/**
937
	 * Hook administration styles.
938
	 */
939
	public static function admin_hook_styles() {
940
		wp_enqueue_style( 'thickbox' );
941
	}
942
}
943