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