Completed
Pull Request — master (#193)
by
unknown
02:22
created

Container   D

Complexity

Total Complexity 86

Size/Duplication

Total Lines 824
Duplicated Lines 1.7 %

Coupling/Cohesion

Components 3
Dependencies 1

Test Coverage

Coverage 8.79%

Importance

Changes 0
Metric Value
dl 14
loc 824
ccs 24
cts 273
cp 0.0879
rs 4.4444
c 0
b 0
f 0
wmc 86
lcom 3
cbo 1

50 Methods

Rating   Name   Duplication   Size   Complexity  
A get_active_fields() 0 3 1
init() 0 1 ?
A detach() 0 8 2
A is_tabbed() 0 3 1
A get_nonce_field() 0 3 1
A factory() 4 22 3
A make() 0 3 1
A init_containers() 0 7 2
A get_active_containers() 0 3 1
A activate_container() 0 7 1
A activate_field() 0 15 3
B template() 0 27 1
A __construct() 0 11 2
A boot() 0 6 1
A setup() 0 19 4
A check_setup_settings() 3 6 2
A _save() 0 6 2
A save() 0 6 2
A is_valid_save() 0 3 1
A load() 0 5 2
A _attach() 0 10 3
A _attach_all() 0 3 1
A _attach_containers() 0 8 2
A get_templates() 0 3 1
A add_template() 0 3 1
A attach() 0 1 1
A is_active() 0 3 1
A is_valid_attach() 0 3 1
A add_fields() 0 18 4
A add_tab() 0 8 1
A show_in_rest() 0 5 1
A set_rest_visibility() 0 3 1
A get_rest_visibility() 0 3 1
B create_tab() 0 21 5
B get_untabbed_fields() 0 22 5
A get_tabs() 0 9 2
A get_tabs_json() 0 12 3
A get_fields() 0 3 1
A has_fields() 0 3 1
A get_unique_panel_id() 0 11 2
A drop_unique_panel_id() 0 5 2
A verify_unique_field_name() 7 7 2
A drop_unique_field_name() 0 7 2
A set_datastore() 0 9 2
A get_datastore() 0 3 1
A get_nonce_name() 0 3 1
A to_json() 0 17 2
A template_tabs() 0 19 1
A admin_hook_scripts() 0 10 1
A admin_hook_styles() 0 3 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Container 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 Container, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Carbon_Fields\Container;
4
5
use Carbon_Fields\Field\Field;
6
use Carbon_Fields\Datastore\Datastore_Interface;
7
use Carbon_Fields\Exception\Incorrect_Syntax_Exception;
8
9
/**
10
 * Base container class.
11
 * Defines the key container methods and their default implementations.
12
 */
13
abstract class Container {
14
	/**
15
	 * Where to put a particular tab -- at the head or the tail. Tail by default
16
	 */
17
	const TABS_TAIL = 1;
18
	const TABS_HEAD = 2;
19
20
	/**
21
	 * List of registered unique panel identificators
22
	 *
23
	 * @see get_unique_panel_id()
24
	 * @var array
25
	 */
26
	public static $registered_panel_ids = array();
27
28
	/**
29
	 * List of containers created via factory that
30
	 * should be initialized
31
	 *
32
	 * @var array
33
	 */
34
	protected static $init_containers = array();
35
36
	/**
37
	 * List of containers attached to the current page view
38
	 *
39
	 * @see _attach()
40
	 * @var array
41
	 */
42
	public static $active_containers = array();
43
44
	/**
45
	 * List of fields attached to the current page view
46
	 *
47
	 * @see _attach()
48
	 * @var array
49
	 */
50
	protected static $active_fields = array();
51
52
	/**
53
	 * List of registered unique field names for this container instance
54
	 *
55
	 * @see verify_unique_field_name()
56
	 * @var array
57
	 */
58
	protected $registered_field_names = array();
1 ignored issue
show
Comprehensibility Naming introduced by
The variable name $registered_field_names 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...
59
60
	/**
61
	 * Stores all the container Backbone templates
62
	 *
63
	 * @see factory()
64
	 * @see add_template()
65
	 * @var array
66
	 */
67
	protected $templates = array();
68
69
	/**
70
	 * Tabs available
71
	 */
72
	protected $tabs = array();
73
74
	/**
75
	 * List of default container settings
76
	 *
77
	 * @see init()
78
	 * @var array
79
	 */
80
	public $settings = array();
81
82
	/**
83
	 * Title of the container
84
	 *
85
	 * @var string
86
	 */
87
	public $title = '';
88
89
	/**
90
	 * Whether the container was setup
91
	 *
92
	 * @var bool
93
	 */
94
	public $setup_ready = false;
95
96
	/**
97
	 * List of notification messages to be displayed on the front-end
98
	 *
99
	 * @var array
100
	 */
101
	protected $notifications = array();
102
103
	/**
104
	 * List of error messages to be displayed on the front-end
105
	 *
106
	 * @var array
107
	 */
108
	protected $errors = array();
109
110
	/**
111
	 * List of container fields
112
	 *
113
	 * @see add_fields()
114
	 * @var array
115
	 */
116
	protected $fields = array();
117
118
	/**
119
	 * Container DataStore. Propagated to all container fields
120
	 *
121
	 * @see set_datastore()
122
	 * @see get_datastore()
123
	 * @var object
124
	 */
125
	protected $store;
126
127
	/**
128
	 * Whether the container should be included in the response of the requests to the REST API
129
	 *
130
	 * @see  set_rest_visibility
131
	 * @see  get_rest_visibility
132
	 * @var boolean
133
	 */
134
	protected $visible_in_rest = true;
135
136
	/**
137
	 * Create a new container of type $type and name $name and label $label.
138
	 *
139
	 * @param string $type
140
	 * @param string $name Human-readable name of the container
141
	 * @return object $container
142
	 **/
143 11
	public static function factory( $type, $name ) {
144
		// backward compatibility: post_meta container used to be called custom_fields
145 11
		if ( $type === 'custom_fields' ) {
146 1
			$type = 'post_meta';
147 1
		}
148
149 11
		$type = str_replace( ' ', '_', ucwords( str_replace( '_', ' ', $type ) ) );
150
151 11
		$class = __NAMESPACE__ . '\\' . $type . '_Container';
152
153 11 View Code Duplication
		if ( ! class_exists( $class ) ) {
1 ignored issue
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...
154 3
			Incorrect_Syntax_Exception::raise( 'Unknown container "' . $type . '".' );
155 1
			$class = __NAMESPACE__ . '\\Broken_Container';
156 1
		}
157
158 9
		$container = new $class( $name );
159 8
		$container->type = $type;
160
161 8
		self::$init_containers[] = $container;
162
163 8
		return $container;
164
	}
165
166
	/**
167
	 * An alias of factory().
168
	 *
169
	 * @see Container::factory()
170
	 **/
171 11
	public static function make( $type, $name ) {
172 11
		return self::factory( $type, $name );
173
	}
174
175
	/**
176
	 * Initialize containers created via factory
177
	 *
178
	 * @return object
179
	 **/
180
	public static function init_containers() {
181
		while ( ( $container = array_shift( self::$init_containers ) ) ) {
182
			$container->init();
183
		}
184
185
		return $container;
186
	}
187
188
	/**
189
	 * Returns all the active containers created via factory
190
	 *
191
	 * @return array
192
	 **/
193
	public static function get_active_containers() {
194
		return self::$active_containers;
195
	}
196
197
	/**
198
	 * Adds a container to the active containers array and triggers an action
199
	 **/
200
	public static function activate_container( $container ) {
201
		self::$active_containers[] = $container;
202
203
		$container->boot();
204
205
		do_action( 'crb_container_activated', $container );
206
	}
207
208
	/**
209
	 * Returns all the active fields created via factory
210
	 *
211
	 * @return array
212
	 **/
213
	public static function get_active_fields() {
214
		return self::$active_fields;
215
	}
216
217
	/**
218
	 * Adds a field to the active fields array and triggers an action
219
	 **/
220
	public static function activate_field( $field ) {
221
		self::$active_fields[] = $field;
222
223
		if ( method_exists( $field, 'get_fields' ) ) {
224
			$fields = $field->get_fields();
225
226
			foreach ( $fields as $inner_field ) {
227
				self::activate_field( $inner_field );
228
			}
229
		}
230
231
		$field->boot();
232
233
		do_action( 'crb_field_activated', $field );
234
	}
235
236
	/**
237
	 * Perform instance initialization after calling setup()
238
	 **/
239
	abstract public function init();
240
241
	/**
242
	 * Prints the container Underscore template
243
	 **/
244
	public function template() {
245
		?>
246
		<div class="{{{ classes.join(' ') }}}">
247
			<# _.each(fields, function(field) { #>
248
				<div class="{{{ field.classes.join(' ') }}}">
249
					<label for="{{{ field.id }}}">
250
						{{ field.label }}
251
252
						<# if (field.required) { #>
253
							 <span class="carbon-required">*</span>
254
						<# } #>
255
					</label>
256
257
					<div class="field-holder {{{ field.id }}}"></div>
258
259
					<# if (field.help_text) { #>
260
						<em class="help-text">
261
							{{{ field.help_text }}}
262
						</em>
263
					<# } #>
264
265
					<em class="carbon-error"></em>
266
				</div>
267
			<# }); #>
268
		</div>
269
		<?php
270
	}
271
272
	/**
273
	 * Create a new container
274
	 *
275
	 * @param string $title Unique title of the container
276
	 **/
277 9
	public function __construct( $title ) {
278 9
		if ( empty( $title ) ) {
279 1
			Incorrect_Syntax_Exception::raise( 'Empty container title is not supported' );
280
		}
281
282 8
		$this->title = $title;
283 8
		$this->id = preg_replace( '~\W~u', '', remove_accents( $title ) );
284 8
		$this->id = self::get_unique_panel_id( $this->id );
285
286 8
		self::$registered_panel_ids[] = $this->id;
287 8
	}
288
289
	/**
290
	 * Boot the container once it's attached.
291
	 **/
292
	public function boot() {
293
		$this->add_template( $this->type, array( $this, 'template' ) );
294
295
		add_action( 'admin_footer', array( get_class(), 'admin_hook_scripts' ), 5 );
296
		add_action( 'admin_footer', array( get_class(), 'admin_hook_styles' ), 5 );
297
	}
298
299
	/**
300
	 * Update container settings and begin initialization
301
	 *
302
	 * @see init()
303
	 * @param array $settings
304
	 * @return object $this
305
	 **/
306
	public function setup( $settings = array() ) {
307
		if ( $this->setup_ready ) {
308
			Incorrect_Syntax_Exception::raise( 'Panel "' . $this->title . '" already setup' );
309
		}
310
311
		$this->check_setup_settings( $settings );
312
313
		$this->settings = array_merge( $this->settings, $settings );
314
315
		foreach ( $this->settings as $key => $value ) {
316
			if ( is_null( $value ) ) {
317
				unset( $this->settings[ $key ] );
318
			}
319
		}
320
321
		$this->setup_ready = true;
322
323
		return $this;
324
	}
325
326
	/**
327
	 * Check if all required container settings have been specified
328
	 *
329
	 * @param array $settings Container settings
330
	 **/
331
	public function check_setup_settings( &$settings = array() ) {
332
		$invalid_settings = array_diff_key( $settings, $this->settings );
333 View Code Duplication
		if ( ! empty( $invalid_settings ) ) {
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...
334
			Incorrect_Syntax_Exception::raise( 'Invalid settings supplied to setup(): "' . implode( '", "', array_keys( $invalid_settings ) ) . '"' );
335
		}
336
	}
337
338
	/**
339
	 * Called first as part of the container save procedure.
340
	 * Responsible for checking the request validity and
341
	 * calling the container-specific save() method
342
	 *
343
	 * @see save()
344
	 * @see is_valid_save()
345
	 **/
346
	public function _save() {
347
		$param = func_get_args();
348
		if ( call_user_func_array( array( $this, 'is_valid_save' ), $param ) ) {
349
			call_user_func_array( array( $this, 'save' ), $param );
350
		}
351
	}
352
353
	/**
354
	 * Load submitted data and save each field in the container
355
	 *
356
	 * @see is_valid_save()
357
	 **/
358
	public function save( $data ) {
359
		foreach ( $this->fields as $field ) {
360
			$field->set_value_from_input();
361
			$field->save();
362
		}
363
	}
364
365
	/**
366
	 * Checks whether the current request is valid
367
	 *
368
	 * @return bool
369
	 **/
370
	public function is_valid_save() {
371
		return false;
372
	}
373
374
	/**
375
	 * Load the value for each field in the container.
376
	 * Could be used internally during container rendering
377
	 **/
378
	public function load() {
379
		foreach ( $this->fields as $field ) {
380
			$field->load();
381
		}
382
	}
383
384
385
	/**
386
	 * Called first as part of the container attachment procedure.
387
	 * Responsible for checking it's OK to attach the container
388
	 * and if it is, calling the container-specific attach() method
389
	 *
390
	 * @see attach()
391
	 * @see is_valid_attach()
392
	 **/
393
	public function _attach() {
394
		$param = func_get_args();
395
		if ( call_user_func_array( array( $this, 'is_valid_attach' ), $param ) ) {
396
			call_user_func_array( array( $this, 'attach' ), $param );
397
398
			if ( call_user_func_array( array( $this, 'is_active' ), $param ) ) {
399
				$this->_attach_containers();
400
			}
401
		}
402
	}
403
404
	/**
405
	 * Attach all containers
406
	 * 
407
	 */
408
	public function _attach_all() {
409
		$this->_attach_containers();
410
	}
411
412
	/**
413
	 * Calls the container-specific attach() method
414
	 */
415
	private function _attach_containers() {
416
		self::activate_container( $this );
417
418
		$fields = $this->get_fields();
419
		foreach ( $fields as $field ) {
420
			self::activate_field( $field );
421
		}
422
	}
423
424
	/**
425
	 * Returns all the Backbone templates
426
	 *
427
	 * @return array
428
	 **/
429
	public function get_templates() {
430
		return $this->templates;
431
	}
432
433
	/**
434
	 * Adds a new Backbone template
435
	 **/
436
	public function add_template( $name, $callback ) {
437
		$this->templates[ $name ] = $callback;
438
	}
439
440
	/**
441
	 * Attach the container rendering and helping methods
442
	 * to concrete WordPress Action hooks
443
	 **/
444
	public function attach() {}
445
446
	/**
447
	 * Perform checks whether the container is active for current request
448
	 *
449
	 * @return bool True if the container is active
450
	 **/
451
	public function is_active() {
452
		return $this->is_valid_attach();
453
	}
454
455
	/**
456
	 * Perform checks whether the container should be attached during the current request
457
	 *
458
	 * @return bool True if the container is allowed to be attached
459
	 **/
460
	public function is_valid_attach() {
461
		return true;
462
	}
463
464
	/**
465
	 * Revert the result of attach()
466
	 **/
467
	public function detach() {
468
		self::drop_unique_panel_id( $this->id );
469
470
		// unregister field names
471
		foreach ( $this->fields as $field ) {
472
			$this->drop_unique_field_name( $field->get_name() );
473
		}
474
	}
475
476
	/**
477
	 * Append array of fields to the current fields set. All items of the array
478
	 * must be instances of Field and their names should be unique for all
479
	 * Carbon containers.
480
	 * If a field does not have DataStore already, the container data store is
481
	 * assigned to them instead.
482
	 *
483
	 * @param array $fields
484
	 * @return object $this
485
	 **/
486
	public function add_fields( $fields ) {
487
		foreach ( $fields as $field ) {
488
			if ( ! is_a( $field, 'Carbon_Fields\\Field\\Field' ) ) {
489
				Incorrect_Syntax_Exception::raise( 'Object must be of type Carbon_Fields\\Field\\Field' );
490
			}
491
492
			$this->verify_unique_field_name( $field->get_name() );
493
494
			$field->set_context( $this->type );
495
			if ( ! $field->get_datastore() ) {
496
				$field->set_datastore( $this->store );
497
			}
498
		}
499
500
		$this->fields = array_merge( $this->fields, $fields );
501
502
		return $this;
503
	}
504
505
	/**
506
	 * Configuration function for adding tab with fields
507
	 *
508
	 * @param string $tab_name
509
	 * @param array $fields
510
	 * @return object $this
511
	 */
512
	public function add_tab( $tab_name, $fields ) {
513
		$this->add_template( 'tabs', array( $this, 'template_tabs' ) );
514
515
		$this->add_fields( $fields );
516
		$this->create_tab( $tab_name, $fields );
517
518
		return $this;
519
	}
520
521
	/**
522
	 * Configuration function for setting the container visibility in the response of the requests to the REST API
523
	 * 
524
	 * @param  bool $visible
525
	 * @return object $this
526
	 */
527
	public function show_in_rest( $visible ) {
528
		$this->set_rest_visibility( $visible );
529
530
		return $this;
531
	}
532
533
	/**
534
	 * Set the REST visibility of the container
535
	 * 
536
	 * @param bool $visible
537
	 */
538
	public function set_rest_visibility( $visible ) {
539
		$this->visible_in_rest = $visible;
540
	}
541
542
	/**
543
	 * Get the REST visibility of the container
544
	 * 
545
	 * @return bool True if the container is visible
546
	 */
547
	public function get_rest_visibility() {
548
		return $this->visible_in_rest;
549
	}
550
551
	/**
552
	 * Internal function that creates the tab and associates it with particular field set
553
	 *
554
	 * @param string $tab_name
555
	 * @param array $fields
556
	 * @param int $queue_end
557
	 * @return object $this
558
	 */
559
	private function create_tab( $tab_name, $fields, $queue_end = self::TABS_TAIL ) {
560
		if ( isset( $this->tabs[ $tab_name ] ) ) {
561
			Incorrect_Syntax_Exception::raise( "Tab name duplication for $tab_name" );
562
		}
563
564
		if ( $queue_end === self::TABS_TAIL ) {
565
			$this->tabs[ $tab_name ] = array();
566
		} else if ( $queue_end === self::TABS_HEAD ) {
567
			$this->tabs = array_merge(
568
				array( $tab_name => array() ),
569
				$this->tabs
570
			);
571
		}
572
573
		foreach ( $fields as $field ) {
574
			$field_name = $field->get_name();
575
			$this->tabs[ $tab_name ][ $field_name ] = $field;
576
		}
577
578
		$this->settings['tabs'] = $this->get_tabs_json();
579
	}
580
581
	/**
582
	 * Whether the container is tabbed or not
583
	 *
584
	 * @return bool
585
	 */
586
	public function is_tabbed() {
587
		return (bool) $this->tabs;
588
	}
589
590
	/**
591
	 * Retrieve all fields that are not defined under a specific tab
592
	 *
593
	 * @return array
594
	 */
595
	public function get_untabbed_fields() {
596
		$tabbed_fields_names = array();
597
		foreach ( $this->tabs as $tab_fields ) {
598
			$tabbed_fields_names = array_merge( $tabbed_fields_names, array_keys( $tab_fields ) );
599
		}
600
601
		$all_fields_names = array();
602
		foreach ( $this->fields as $field ) {
603
			$all_fields_names[] = $field->get_name();
604
		}
605
606
		$fields_not_in_tabs = array_diff( $all_fields_names, $tabbed_fields_names );
607
608
		$untabbed_fields = array();
609
		foreach ( $this->fields as $field ) {
610
			if ( in_array( $field->get_name(), $fields_not_in_tabs ) ) {
611
				$untabbed_fields[] = $field;
612
			}
613
		}
614
615
		return $untabbed_fields;
616
	}
617
618
	/**
619
	 * Retrieve all tabs.
620
	 * Create a default tab if there are any untabbed fields.
621
	 *
622
	 * @return array
623
	 */
624
	public function get_tabs() {
625
		$untabbed_fields = $this->get_untabbed_fields();
626
627
		if ( ! empty( $untabbed_fields ) ) {
628
			$this->create_tab( __( 'General', 'carbon-fields' ), $untabbed_fields, self::TABS_HEAD );
629
		}
630
631
		return $this->tabs;
632
	}
633
634
	/**
635
	 * Build the tabs JSON
636
	 *
637
	 * @return array
638
	 */
639
	public function get_tabs_json() {
640
		$tabs_json = array();
641
		$tabs = $this->get_tabs();
642
643
		foreach ( $tabs as $tab_name => $fields ) {
644
			foreach ( $fields as $field_name => $field ) {
645
				$tabs_json[ $tab_name ][] = $field_name;
646
			}
647
		}
648
649
		return $tabs_json;
650
	}
651
652
	/**
653
	 * Returns the private container array of fields.
654
	 * Use only if you are completely aware of what you are doing.
655
	 *
656
	 * @return array
657
	 **/
658
	public function get_fields() {
659
		return $this->fields;
660
	}
661
662
	/**
663
	 * Perform a check whether the current container has fields
664
	 *
665
	 * @return bool
666
	 **/
667
	public function has_fields() {
668
		return (bool) $this->fields;
669
	}
670
671
	/**
672
	 * Perform checks whether there is a container registered with identificator $id
673
	 */
674
	public static function get_unique_panel_id( $id ) {
675
		$base = $id;
676
		$suffix = 0;
677
678
		while ( in_array( $id, self::$registered_panel_ids ) ) {
679
			$suffix++;
680
			$id = $base . strval( $suffix );
681
		}
682
683
		return $id;
684
	}
685
686
687
	/**
688
	 * Remove container identificator $id from the list of unique container ids
689
	 *
690
	 * @param string $id
691
	 **/
692
	public static function drop_unique_panel_id( $id ) {
693
		if ( in_array( $id, self::$registered_panel_ids ) ) {
694
			unset( self::$registered_panel_ids[ array_search( $id, self::$registered_panel_ids ) ] );
695
		}
696
	}
697
698
	/**
699
	 * Perform checks whether there is a field registered with the name $name.
700
	 * If not, the field name is recorded.
701
	 *
702
	 * @param string $name
703
	 **/
704 View Code Duplication
	public function verify_unique_field_name( $name ) {
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...
705
		if ( in_array( $name, $this->registered_field_names ) ) {
706
			Incorrect_Syntax_Exception::raise( 'Field name "' . $name . '" already registered' );
707
		}
708
709
		$this->registered_field_names[] = $name;
710
	}
711
712
	/**
713
	 * Remove field name $name from the list of unique field names
714
	 *
715
	 * @param string $name
716
	 **/
717
	public function drop_unique_field_name( $name ) {
718
		$index = array_search( $name, $this->registered_field_names );
719
720
		if ( $index !== false ) {
721
			unset( $this->registered_field_names[ $index ] );
722
		}
723
	}
724
725
	/**
726
	 * Assign DataStore instance for use by the container fields
727
	 *
728
	 * @param object $store
729
	 * @return object $this
730
	 **/
731
	public function set_datastore( $store ) {
732
		$this->store = $store;
733
734
		foreach ( $this->fields as $field ) {
735
			$field->set_datastore( $this->store );
736
		}
737
738
		return $this;
739
	}
740
741
	/**
742
	 * Return the DataStore instance used by container fields
743
	 *
744
	 * @return object $store
745
	 **/
746
	public function get_datastore() {
747
		return $this->store;
748
	}
749
750
	/**
751
	 * Return WordPress nonce name used to identify the current container instance
752
	 *
753
	 * @return string
754
	 **/
755
	public function get_nonce_name() {
756
		return 'carbon_panel_' . $this->id . '_nonce';
757
	}
758
759
	/**
760
	 * Return WordPress nonce field
761
	 *
762
	 * @return string
763
	 **/
764
	public function get_nonce_field() {
765
		return wp_nonce_field( $this->get_nonce_name(), $this->get_nonce_name(), /*referer?*/ false, /*echo?*/ false );
766
	}
767
768
	/**
769
	 * Returns an array that holds the container data, suitable for JSON representation.
770
	 * This data will be available in the Underscore template and the Backbone Model.
771
	 *
772
	 * @param bool $load  Should the value be loaded from the database or use the value from the current instance.
773
	 * @return array
774
	 */
775
	public function to_json( $load ) {
776
		$container_data = array(
777
			'id' => $this->id,
778
			'type' => $this->type,
779
			'title' => $this->title,
780
			'settings' => $this->settings,
781
			'fields' => array(),
782
		);
783
784
		$fields = $this->get_fields();
785
		foreach ( $fields as $field ) {
786
			$field_data = $field->to_json( $load );
787
			$container_data['fields'][] = $field_data;
788
		}
789
790
		return $container_data;
791
	}
792
793
	/**
794
	 * Underscore template for tabs
795
	 */
796
	public function template_tabs() {
797
		?>
798
		<div class="carbon-tabs">
799
			<ul class="carbon-tabs-nav">
800
				<# _.each(tabs, function (tab, tabName) { #>
801
					<li><a href="#" data-id="{{{ tab.id }}}">{{{ tabName }}}</a></li>
802
				<# }); #>
803
			</ul>
804
805
			<div class="carbon-tabs-body">
806
				<# _.each(tabs, function (tab) { #>
807
					<div class="carbon-fields-collection carbon-tab">
808
						{{{ tab.html }}}
809
					</div>
810
				<# }); #>
811
			</div>
812
		</div>
813
		<?php
814
	}
815
816
	/**
817
	 * Enqueue admin scripts
818
	 */
819
	public static function admin_hook_scripts() {
820
		wp_enqueue_script( 'carbon-containers', \Carbon_Fields\URL . '/assets/js/containers.js', array( 'carbon-app' ) );
821
822
		wp_localize_script( 'carbon-containers', 'carbon_containers_l10n',
823
			array(
824
				'please_fill_the_required_fields' => __( 'Please fill out all required fields highlighted below.', 'carbon-fields' ),
825
				'changes_made_save_alert' => __( 'The changes you made will be lost if you navigate away from this page.', 'carbon-fields' ),
826
			)
827
		);
828
	}
829
830
	/**
831
	 * Enqueue admin styles
832
	 */
833
	public static function admin_hook_styles() {
834
		wp_enqueue_style( 'carbon-main', \Carbon_Fields\URL . '/assets/bundle.css' );
835
	}
836
} // END Container
837
838