Completed
Push — milestone/2_0/react-ui ( 5b168c...b737dc )
by
unknown
04:15
created

Field::factory()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 21
Code Lines 14

Duplication

Lines 4
Ratio 19.05 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 3
eloc 14
nc 3
nop 3
dl 4
loc 21
rs 9.3142
c 1
b 1
f 0
1
<?php
2
3
namespace Carbon_Fields\Field;
4
5
use Carbon_Fields\Carbon_Fields;
6
use Carbon_Fields\Pimple\Container as PimpleContainer;
7
use Carbon_Fields\Datastore\Datastore_Interface;
8
use Carbon_Fields\Datastore\Datastore_Holder_Interface;
9
use Carbon_Fields\Value_Set\Value_Set;
10
use Carbon_Fields\Helper\Helper;
11
use Carbon_Fields\Exception\Incorrect_Syntax_Exception;
12
13
/**
14
 * Base field class.
15
 * Defines the key container methods and their default implementations.
16
 * Implements factory design pattern.
17
 */
18
class Field implements Datastore_Holder_Interface {
19
	
20
	/**
21
	 * Array of field class names that have had their activation method called
22
	 *
23
	 * @var array<string>
24
	 */
25
	protected static $activated_field_types = array();
1 ignored issue
show
Comprehensibility Naming introduced by
The variable name $activated_field_types exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
26
27
	/**
28
	 * Globally unique field identificator. Generated randomly
29
	 *
30
	 * @var string
31
	 */
32
	protected $id;
33
34
	/**
35
	 * Stores the initial <kbd>$type</kbd> variable passed to the <code>factory()</code> method
36
	 *
37
	 * @see factory
38
	 * @var string
39
	 */
40
	public $type;
41
42
	/**
43
	 * Array of ancestor field names
44
	 *
45
	 * @var array
46
	 */
47
	protected $hierarchy = array();
48
49
	/**
50
	 * Array of complex entry ids
51
	 *
52
	 * @var array
53
	 */
54
	protected $hierarchy_index = array();
55
56
	/**
57
	 * Field value
58
	 *
59
	 * @var Value_Set
60
	 */
61
	protected $value_set;
62
63
	/**
64
	 * Default field value
65
	 *
66
	 * @var mixed
67
	 */
68
	protected $default_value = '';
69
70
	/**
71
	 * Sanitized field name used as input name attribute during field render
72
	 *
73
	 * @see factory()
74
	 * @see set_name()
75
	 * @var string
76
	 */
77
	protected $name;
78
79
	/**
80
	 * Field name prefix
81
	 *
82
	 * @see set_name()
83
	 * @var string
84
	 */
85
	protected $name_prefix = '_';
86
87
	/**
88
	 * The base field name which is used in the container.
89
	 *
90
	 * @see set_base_name()
91
	 * @var string
92
	 */
93
	protected $base_name;
94
95
	/**
96
	 * Field name used as label during field render
97
	 *
98
	 * @see factory()
99
	 * @see set_label()
100
	 * @var string
101
	 */
102
	protected $label;
103
104
	/**
105
	 * Additional text containing information and guidance for the user
106
	 *
107
	 * @see help_text()
108
	 * @var string
109
	 */
110
	protected $help_text;
111
112
	/**
113
	 * Field DataStore instance to which save, load and delete calls are delegated
114
	 *
115
	 * @see set_datastore()
116
	 * @see get_datastore()
117
	 * @var Datastore_Interface
118
	 */
119
	protected $datastore;
120
121
	/**
122
	 * Flag whether the datastore is the default one or replaced with a custom one
123
	 *
124
	 * @see set_datastore()
125
	 * @see get_datastore()
126
	 * @var boolean
127
	 */
128
	protected $has_default_datastore = true;
129
130
	/**
131
	 * The type of the container this field is in
132
	 *
133
	 * @see get_context()
134
	 * @var string
135
	 */
136
	protected $context;
137
138
	/**
139
	 * Whether or not this value should be auto loaded. Applicable to theme options only.
140
	 *
141
	 * @see set_autoload()
142
	 * @var bool
143
	 */
144
	protected $autoload = false;
145
146
	/**
147
	 * Whether or not this field will be initialized when the field is in the viewport (visible).
148
	 *
149
	 * @see set_lazyload()
150
	 * @var bool
151
	 */
152
	protected $lazyload = false;
153
154
	/**
155
	 * The width of the field.
156
	 *
157
	 * @see set_width()
158
	 * @var int
159
	 */
160
	protected $width = 0;
161
162
	/**
163
	 * Custom CSS classes.
164
	 *
165
	 * @see set_classes()
166
	 * @var array
167
	 */
168
	protected $classes = array();
169
170
	/**
171
	 * Whether or not this field is required.
172
	 *
173
	 * @see set_required()
174
	 * @var bool
175
	 */
176
	protected $required = false;
177
178
	/**
179
	 * Stores the field conditional logic rules.
180
	 *
181
	 * @var array
182
	 */
183
	protected $conditional_logic = array();
184
185
	/**
186
	 * Whether the field should be included in the response of the requests to the REST API
187
	 *
188
	 * @see  set_visible_in_rest_api
189
	 * @see  get_visible_in_rest_api
190
	 * @var boolean
191
	 */
192
	protected $visible_in_rest_api = false;
193
194
	/**
195
	 * Clone the Value_Set object as well
196
	 *
197
	 * @var array
198
	 */
199
	public function __clone() {
200
		$this->set_value_set( clone $this->get_value_set() );
201
	}
202
203
	/**
204
	 * Create a new field of type $type and name $name and label $label.
205
	 *
206
	 * @param string $type
0 ignored issues
show
Bug introduced by
There is no parameter named $type. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
207
	 * @param string $name lower case and underscore-delimited
208
	 * @param string $label (optional) Automatically generated from $name if not present
209
	 * @return Field
210
	 */
211
	public static function factory( $raw_type, $name, $label = null ) {
212
		$type = Helper::normalize_type( $raw_type );
213
214
		if ( Carbon_Fields::has( $type, 'fields' ) ) {
215
			return Carbon_Fields::resolve_with_arguments( $type, array(
216
				'type' => $type,
217
				'name' => $name,
218
				'label' => $label,
219
			), 'fields' );
220
		}
221
222
		// Fallback to class name-based resolution
223
		$class = Helper::type_to_class( $type, __NAMESPACE__, '_Field' );
224 View Code Duplication
		if ( ! class_exists( $class ) ) {
225
			Incorrect_Syntax_Exception::raise( 'Unknown field "' . $raw_type . '".' );
226
			$class = __NAMESPACE__ . '\\Broken_Field';
227
		}
228
229
		$field = new $class( $type, $name, $label );
230
		return $field;
231
	}
232
233
	/**
234
	 * An alias of factory().
235
	 *
236
	 * @see Field::factory()
237
	 * @return Field
238
	 */
239
	public static function make( $type, $name, $label = null ) {
240
		return static::factory( $type, $name, $label );
241
	}
242
243
	/**
244
	 * Create a field from a certain type with the specified label.
245
	 * 
246
	 * @param string $type  Field type
247
	 * @param string $name  Field name
248
	 * @param string $label Field label
249
	 */
250
	public function __construct( $type, $name, $label ) {
251
		Carbon_Fields::verify_boot();
252
		
253
		$this->type = $type;
254
		$this->set_base_name( $name );
255
		$this->set_name( $name );
256
		$this->set_label( $label );
257
258
		// Pick random ID
259
		$random_string = md5( mt_rand() . $this->get_name() . $this->get_label() );
260
		$random_string = substr( $random_string, 0, 5 ); // 5 chars should be enough
261
		$this->id = 'carbon-' . $random_string;
262
263
		$this->init();
264
	}
265
266
	/**
267
	 * Returns the type of the field based on the class.
268
	 * The class is stripped by the "CarbonFields" prefix.
269
	 * Also the "Field" suffix is removed.
270
	 * Then underscores and backslashes are removed.
271
	 *
272
	 * @return string
273
	 */
274
	public function get_type() {
275
		$class = get_class( $this );
276
		return Helper::class_to_type( $class, '_Field' );
277
	}
278
279
	/**
280
	 * Activate the field once the container is attached.
281
	 */
282
	public function activate() {
283
		$this->admin_init();
284
285
		add_action( 'admin_print_footer_scripts', array( get_class(), 'admin_hook_scripts' ), 5 );
286
		add_action( 'admin_print_footer_scripts', array( get_class(), 'admin_hook_styles' ), 5 );
287
		static::activate_field_type( get_class( $this ) );
288
289
		do_action( 'carbon_fields_field_activated', $this );
290
	}
291
292
	/**
293
	 * Activate a field type
294
	 * @param string $class_name
295
	 */
296
	public static function activate_field_type( $class_name ) {
297
		if ( in_array( $class_name, static::$activated_field_types ) ) {
298
			return;
299
		}
300
301
		add_action( 'admin_print_footer_scripts', array( $class_name, 'admin_enqueue_scripts' ), 5 );
302
		call_user_func( array( $class_name, 'field_type_activated' ) );
303
304
		static::$activated_field_types[] = $class_name;
305
	}
306
307
	/**
308
	 * Prepare the field type for use
309
	 * Called once per field type when activated
310
	 */
311
	public static function field_type_activated() {}
312
313
	/**
314
	 * Get array of hierarchy field names
315
	 *
316
	 * @return array
317
	 */
318
	public function get_hierarchy() {
319
		return $this->hierarchy;
320
	}
321
322
	/**
323
	 * Set array of hierarchy field names
324
	 */
325
	public function set_hierarchy( $hierarchy ) {
326
		$this->hierarchy = $hierarchy;
327
	}
328
329
	/**
330
	 * Get array of hierarchy indexes
331
	 *
332
	 * @return array
333
	 */
334
	public function get_hierarchy_index() {
335
		return $this->hierarchy_index;
336
	}
337
338
	/**
339
	 * Set array of hierarchy indexes
340
	 */
341
	public function set_hierarchy_index( $hierarchy_index ) {
342
		$hierarchy_index = ( ! empty( $hierarchy_index ) ) ? $hierarchy_index : array( 0 );
343
		$this->hierarchy_index = $hierarchy_index;
344
	}
345
346
	/**
347
	 * Return whether the field is a root field and holds a single value
348
	 *
349
	 * @return bool
350
	 */
351
	public function is_simple_root_field() {
352
		$hierarchy = $this->get_hierarchy();
353
		return (
354
			empty( $hierarchy )
355
			&&
356
			(
357
				$this->get_value_set()->get_type() === Value_Set::TYPE_SINGLE_VALUE
358
				||
359
				$this->get_value_set()->get_type() === Value_Set::TYPE_MULTIPLE_PROPERTIES
360
			)
361
		);
362
	}
363
364
	/**
365
	 * Perform instance initialization
366
	 */
367
	public function init() {}
368
369
	/**
370
	 * Instance initialization when in the admin area
371
	 * Called during field boot
372
	 */
373
	public function admin_init() {}
374
375
	/**
376
	 * Enqueue scripts and styles in admin
377
	 * Called once per field type
378
	 */
379
	public static function admin_enqueue_scripts() {}
380
381
	/**
382
	 * Get value from datastore
383
	 *
384
	 * @param bool $fallback_to_default
385
	 * @return mixed
386
	 */
387
	protected function get_value_from_datastore( $fallback_to_default = true ) {
388
		$value_tree = $this->get_datastore()->load( $this );
389
		
390
		$value = null;
391
		if ( isset( $value_tree['value_set'] ) ) {
392
			$value = $value_tree['value_set'];
393
		}
394
395
		if ( $value === null && $fallback_to_default ) {
396
			$value = $this->get_default_value();
397
		}
398
399
		return $value;
400
	}
401
402
	/**
403
	 * Load value from datastore
404
	 */
405
	public function load() {
406
		$value = $this->get_value_from_datastore();
407
		$this->set_value( $value );
408
	}
409
410
	/**
411
	 * Save value to storage
412
	 */
413
	public function save() {
414
		$delete_on_save = ! in_array( $this->get_value_set()->get_type(), array( Value_Set::TYPE_SINGLE_VALUE, Value_Set::TYPE_MULTIPLE_PROPERTIES ) );
415
		$delete_on_save = apply_filters( 'carbon_fields_should_delete_field_value_on_save', $delete_on_save, $this );
416
		if ( $delete_on_save ) {
417
			$this->delete();
418
		}
419
420
		$save = apply_filters( 'carbon_fields_should_save_field_value', true, $this->get_value(), $this );
421
		if ( $save ) {
422
			$this->get_datastore()->save( $this );
423
		}
424
	}
425
426
	/**
427
	 * Delete value from storage
428
	 */
429
	public function delete() {
430
		$this->get_datastore()->delete( $this );
431
	}
432
433
	/**
434
	 * Load the field value from an input array based on it's name
435
	 *
436
	 * @param array $input Array of field names and values.
437
	 */
438
	public function set_value_from_input( $input ) {
439
		if ( isset( $input[ $this->get_name() ] ) ) {
440
			$this->set_value( $input[ $this->get_name() ] );
441
		} else {
442
			$this->clear_value();
443
		}
444
	}
445
446
	/**
447
	 * Return whether the datastore instance is the default one or has been overriden
448
	 *
449
	 * @return boolean
450
	 */
451
	public function has_default_datastore() {
452
		return $this->has_default_datastore;
453
	}
454
455
	/**
456
	 * Get the DataStore instance
457
	 *
458
	 * @return Datastore_Interface $datastore
459
	 */
460
	public function get_datastore() {
461
		return $this->datastore;
462
	}
463
464
	/**
465
	 * Set datastore instance
466
	 *
467
	 * @param Datastore_Interface $datastore
468
	 * @return object $this
469
	 */
470
	public function set_datastore( Datastore_Interface $datastore, $set_as_default = false ) {
471
		if ( $set_as_default && ! $this->has_default_datastore() ) {
472
			return $this; // datastore has been overriden with a custom one - abort changing to a default one
473
		}
474
		$this->datastore = $datastore;
475
		$this->has_default_datastore = $set_as_default;
476
		return $this;
477
	}
478
479
	/**
480
	 * Return the type of the container this field is in
481
	 *
482
	 * @return string
483
	 */
484
	public function get_context() {
485
		return $this->context;
486
	}
487
488
	/**
489
	 * Assign the type of the container this field is in
490
	 *
491
	 * @param string
492
	 * @return object $this
493
	 */
494
	public function set_context( $context ) {
495
		$this->context = $context;
496
		return $this;
497
	}
498
499
	/**
500
	 * Get the Value_Set object
501
	 *
502
	 * @return Value_Set
503
	 */
504
	public function get_value_set() {
505
		if ( $this->value_set === null ) {
506
			$this->set_value_set( new Value_Set() );
507
		}
508
		return $this->value_set;
509
	}
510
511
	/**
512
	 * Set the Value_Set object
513
	 *
514
	 * @param Value_Set $value_set
515
	 */
516
	public function set_value_set( $value_set ) {
517
		$this->value_set = $value_set;
518
	}
519
520
	/**
521
	 * Alias for $this->get_value_set()->get(); with fallback to default value
522
	 *
523
	 * @return mixed
524
	 */
525
	public function get_value() {
526
		if ( $this->get_value_set()->get() === null ) {
527
			$this->set_value( $this->get_default_value() );
528
		}
529
		return $this->get_value_set()->get();
530
	}
531
532
	/**
533
	 * Alias for $this->get_value_set()->get_set(); with fallback to default value
534
	 *
535
	 * @return array<array>
536
	 */
537
	public function get_full_value() {
538
		if ( $this->get_value_set()->get_set() === null ) {
539
			$this->set_value( $this->get_default_value() );
540
		}
541
		return $this->get_value_set()->get_set();
542
	}
543
544
	/**
545
	 * Return a differently formatted value for end-users
546
	 *
547
	 * @return mixed
548
	 */
549
	public function get_formatted_value() {
550
		return $this->get_value();
551
	}
552
553
	/**
554
	 * Alias for $this->get_value_set()->set( $value );
555
	 */
556
	public function set_value( $value ) {
557
		$this->get_value_set()->set( $value );
558
	}
559
560
	/**
561
	 * Clear the field value to a blank one (but not the default one)
562
	 */
563
	public function clear_value() {
564
		$this->get_value_set()->set( array() );
565
	}
566
567
	/**
568
	 * Get default field value
569
	 *
570
	 * @return mixed
571
	 */
572
	public function get_default_value() {
573
		return $this->default_value;
574
	}
575
576
	/**
577
	 * Set default field value
578
	 *
579
	 * @param mixed $default_value
580
	 */
581
	public function set_default_value( $default_value ) {
582
		$this->default_value = $default_value;
583
		return $this;
584
	}
585
586
	/**
587
	 * Return the field base name.
588
	 *
589
	 * @return string
590
	 */
591
	public function get_base_name() {
592
		return $this->base_name;
593
	}
594
595
	/**
596
	 * Set field base name as defined in the container.
597
	 */
598
	public function set_base_name( $name ) {
599
		$this->base_name = $name;
600
	}
601
602
	/**
603
	 * Return the field name
604
	 *
605
	 * @return string
606
	 */
607
	public function get_name() {
608
		return $this->name;
609
	}
610
611
	/**
612
	 * Set field name.
613
	 * Use only if you are completely aware of what you are doing.
614
	 *
615
	 * @param string $name Field name, either sanitized or not
616
	 */
617
	public function set_name( $name ) {
618
		if ( empty( $name ) ) {
619
			Incorrect_Syntax_Exception::raise( 'Field name can\'t be empty' );
620
			return;
621
		}
622
623
		// symbols ]-[ are supported in a hidden way - required for widgets to work (WP imposes dashes and square brackets on field names)
624
		$regex = '/\A[a-z0-9_\-\[\]]+\z/';
625
		if ( ! preg_match( $regex, $name ) ) {
626
			Incorrect_Syntax_Exception::raise( 'Field name can only contain lowercase alphanumeric characters and underscores ("' . $name . '" passed).' );
627
		}
628
629
		$name_prefix = $this->get_name_prefix();
630
		$name = ( substr( $name, 0, strlen( $name_prefix ) ) !== $name_prefix ? $name_prefix . $name : $name );
631
632
		$this->name = $name;
633
	}
634
635
	/**
636
	 * Return the field name prefix
637
	 *
638
	 * @return string
639
	 */
640
	public function get_name_prefix() {
641
		return $this->name_prefix;
642
	}
643
644
	/**
645
	 * Set field name prefix
646
	 * Use only if you are completely aware of what you are doing.
647
	 *
648
	 * @param string $name_prefix
649
	 */
650
	public function set_name_prefix( $name_prefix ) {
651
		$name_prefix = strval( $name_prefix );
652
		$old_prefix_length = strlen( $this->name_prefix );
653
		$this->name_prefix = '';
654
		$this->set_name( substr( $this->get_name(), $old_prefix_length ) );
655
656
		$this->name_prefix = $name_prefix;
657
		$this->set_name( $this->name_prefix . $this->get_name() );
658
	}
659
660
	/**
661
	 * Return field label.
662
	 *
663
	 * @return string
664
	 */
665
	public function get_label() {
666
		return $this->label;
667
	}
668
669
	/**
670
	 * Set field label.
671
	 *
672
	 * @param string $label If null, the label will be generated from the field name
673
	 */
674 View Code Duplication
	public function set_label( $label ) {
675
		// Try to guess field label from it's name
676
		if ( is_null( $label ) ) {
677
			// remove the leading underscore(if it's there)
678
			$label = preg_replace( '~^_~', '', $this->name );
679
680
			// remove the leading "crb_"(if it's there)
681
			$label = preg_replace( '~^crb_~', '', $label );
682
683
			// split the name into words and make them capitalized
684
			$label = mb_convert_case( str_replace( '_', ' ', $label ), MB_CASE_TITLE );
685
		}
686
687
		$this->label = $label;
688
	}
689
690
	/**
691
	 * Return the field help text
692
	 *
693
	 * @return object $this
694
	 */
695
	public function get_help_text() {
696
		return $this->help_text;
697
	}
698
699
	/**
700
	 * Set additional text to be displayed during field render,
701
	 * containing information and guidance for the user
702
	 *
703
	 * @return object $this
704
	 */
705
	public function set_help_text( $help_text ) {
706
		$this->help_text = $help_text;
707
		return $this;
708
	}
709
710
	/**
711
	 * Alias for set_help_text()
712
	 *
713
	 * @see set_help_text()
714
	 * @return object $this
715
	 */
716
	public function help_text( $help_text ) {
717
		return $this->set_help_text( $help_text );
718
	}
719
720
	/**
721
	 * Return whether or not this value should be auto loaded.
722
	 *
723
	 * @return bool
724
	 */
725
	public function get_autoload() {
726
		return $this->autoload;
727
	}
728
729
	/**
730
	 * Whether or not this value should be auto loaded. Applicable to theme options only.
731
	 *
732
	 * @param bool $autoload
733
	 * @return object $this
734
	 */
735
	public function set_autoload( $autoload ) {
736
		$this->autoload = $autoload;
737
		return $this;
738
	}
739
740
	/**
741
	 * Return whether or not this field should be lazyloaded.
742
	 *
743
	 * @return bool
744
	 */
745
	public function get_lazyload() {
746
		return $this->lazyload;
747
	}
748
749
	/**
750
	 * Whether or not this field will be initialized when the field is in the viewport (visible).
751
	 *
752
	 * @param bool $lazyload
753
	 * @return object $this
754
	 */
755
	public function set_lazyload( $lazyload ) {
756
		$this->lazyload = $lazyload;
757
		return $this;
758
	}
759
760
	/**
761
	 * Get the field width.
762
	 *
763
	 * @return int $width
764
	 */
765
	public function get_width() {
766
		return $this->width;
767
	}
768
769
	/**
770
	 * Set the field width.
771
	 *
772
	 * @param int $width
773
	 * @return object $this
774
	 */
775
	public function set_width( $width ) {
776
		$this->width = (int) $width;
777
		return $this;
778
	}
779
780
	/**
781
	 * Get custom CSS classes.
782
	 *
783
	 * @return array<string>
784
	 */
785
	public function get_classes() {
786
		return $this->classes;
787
	}
788
789
	/**
790
	 * Set CSS classes that the container should use.
791
	 *
792
	 * @param string|array<string> $classes
793
	 * @return object $this
794
	 */
795
	public function set_classes( $classes ) {
796
		$this->classes = Helper::sanitize_classes( $classes );
797
		return $this;
798
	}
799
800
	/**
801
	 * Whether this field is mandatory for the user
802
	 *
803
	 * @param bool $required
804
	 * @return object $this
805
	 */
806
	public function set_required( $required = true ) {
807
		$this->required = $required;
808
		return $this;
809
	}
810
811
	/**
812
	 * Return whether this field is mandatory for the user
813
	 *
814
	 * @return bool
815
	 */
816
	public function is_required() {
817
		return $this->required;
818
	}
819
820
	/**
821
	 * HTML id attribute getter.
822
	 * @return string
823
	 */
824
	public function get_id() {
825
		return $this->id;
826
	}
827
828
	/**
829
	 * HTML id attribute setter
830
	 * @param string $id
831
	 */
832
	public function set_id( $id ) {
833
		$this->id = $id;
834
	}
835
836
	/**
837
	 * Set the field visibility conditional logic.
838
	 *
839
	 * @param array
840
	 */
841
	public function set_conditional_logic( $rules ) {
842
		$this->conditional_logic = $this->parse_conditional_rules( $rules );
843
844
		return $this;
845
	}
846
847
	/**
848
	 * Get the conditional logic rules
849
	 *
850
	 * @return array
851
	 */
852
	public function get_conditional_logic() {
853
		return $this->conditional_logic;
854
	}
855
856
	/**
857
	 * Validate and parse the conditional logic rules.
858
	 *
859
	 * @param array $rules
860
	 * @return array
861
	 */
862
	protected function parse_conditional_rules( $rules ) {
863
		if ( ! is_array( $rules ) ) {
864
			Incorrect_Syntax_Exception::raise( 'Conditional logic rules argument should be an array.' );
865
			return array();
866
		}
867
868
		$allowed_operators = array( '=', '!=', '>', '>=', '<', '<=', 'IN', 'NOT IN' );
869
870
		$parsed_rules = array(
871
			'relation' => Helper::get_relation_type_from_array( $rules ),
872
			'rules' => array(),
873
		);
874
875
		foreach ( $rules as $key => $rule ) {
876
			if ( $key === 'relation' ) {
877
				continue; // Skip the relation key as it is already handled above
878
			}
879
880
			// Check if the rule is valid
881
			if ( ! is_array( $rule ) || empty( $rule['field'] ) ) {
882
				Incorrect_Syntax_Exception::raise( 'Invalid conditional logic rule format. ' .
883
				'The rule should be an array with the "field" key set.' );
884
				return array();
885
			}
886
887
			// Check the compare operator
888
			if ( empty( $rule['compare'] ) ) {
889
				$rule['compare'] = '=';
890
			}
891 View Code Duplication
			if ( ! in_array( $rule['compare'], $allowed_operators ) ) {
892
				Incorrect_Syntax_Exception::raise( 'Invalid conditional logic compare operator: <code>' .
893
					$rule['compare'] . '</code><br>Allowed operators are: <code>' .
894
				implode( ', ', $allowed_operators ) . '</code>' );
895
				return array();
896
			}
897
			if ( $rule['compare'] === 'IN' || $rule['compare'] === 'NOT IN' ) {
898
				if ( ! is_array( $rule['value'] ) ) {
899
					Incorrect_Syntax_Exception::raise( 'Invalid conditional logic value format. ' .
900
					'An array is expected, when using the "' . $rule['compare'] . '" operator.' );
901
					return array();
902
				}
903
			}
904
905
			// Check the value
906
			if ( ! isset( $rule['value'] ) ) {
907
				$rule['value'] = '';
908
			}
909
910
			$parsed_rules['rules'][] = $rule;
911
		}
912
913
		return $parsed_rules;
914
	}
915
916
	/**
917
	 * Set the REST visibility of the field
918
	 * 
919
	 * @param bool $visible
920
	 */
921
	public function set_visible_in_rest_api( $visible ) {
922
		$this->visible_in_rest_api = $visible;
923
	}
924
	
925
	/**
926
	 * Get the REST visibility of the field
927
	 * 
928
	 * @return bool
929
	 */
930
	public function get_visible_in_rest_api() {
931
		return $this->visible_in_rest_api;
932
	}
933
934
	/**
935
	 * Configuration function for setting the field visibility in the response of the requests to the REST API
936
	 * 
937
	 * @param bool $visible
938
	 * @return Field $this
939
	 */
940
	public function show_in_rest( $visible = true ) {
941
		$this->set_visible_in_rest_api( $visible );
942
		return $this;
943
	}
944
945
	/**
946
	 * Returns an array that holds the field data, suitable for JSON representation.
947
	 *
948
	 * @param bool $load  Should the value be loaded from the database or use the value from the current instance.
949
	 * @return array
950
	 */
951
	public function to_json( $load ) {
952
		if ( $load ) {
953
			$this->load();
954
		}
955
956
		$field_data = array(
957
			'id' => $this->get_id(),
958
			'type' => $this->get_type(),
959
			'label' => $this->get_label(),
960
			'name' => $this->get_name(),
961
			'base_name' => $this->get_base_name(),
962
			'value' => $this->get_value(),
963
			'default_value' => $this->get_default_value(),
964
			'help_text' => $this->get_help_text(),
965
			'context' => $this->get_context(),
966
			'required' => $this->is_required(),
967
			'lazyload' => $this->get_lazyload(),
968
			'width' => $this->get_width(),
969
			'classes' => $this->get_classes(),
970
			'conditional_logic' => $this->get_conditional_logic(),
971
		);
972
973
		return $field_data;
974
	}
975
976
	/**
977
	 * Hook administration scripts.
978
	 */
979
	public static function admin_hook_scripts() {
980
		wp_enqueue_media();
981
	}
982
983
	/**
984
	 * Hook administration styles.
985
	 */
986
	public static function admin_hook_styles() {
987
		wp_enqueue_style( 'thickbox' );
988
	}
989
}
990