1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Carbon_Fields\Field; |
4
|
|
|
|
5
|
|
|
use Carbon_Fields\Datastore\Datastore_Interface; |
6
|
|
|
use Carbon_Fields\Helper\Helper; |
7
|
|
|
use Carbon_Fields\Field\Field; |
8
|
|
|
use Carbon_Fields\Field\Group_Field; |
9
|
|
|
use Carbon_Fields\Exception\Incorrect_Syntax_Exception; |
10
|
|
|
|
11
|
|
|
/** |
12
|
|
|
* Complex field class. |
13
|
|
|
* Allows nested repeaters with multiple field groups to be created. |
14
|
|
|
*/ |
15
|
|
|
class Complex_Field extends Field { |
16
|
|
|
const LAYOUT_GRID = 'grid'; // default |
17
|
|
|
const LAYOUT_LIST = 'list'; // deprecated |
18
|
|
|
const LAYOUT_TABBED = 'tabbed'; // deprecated |
19
|
|
|
const LAYOUT_TABBED_HORIZONTAL = 'tabbed-horizontal'; |
20
|
|
|
const LAYOUT_TABBED_VERTICAL = 'tabbed-vertical'; |
21
|
|
|
|
22
|
|
|
protected $fields = array(); |
23
|
|
|
protected $values = array(); |
24
|
|
|
protected $groups = array(); |
25
|
|
|
|
26
|
|
|
protected $layout = self::LAYOUT_GRID; |
27
|
|
|
protected $values_min = -1; |
28
|
|
|
protected $values_max = -1; |
29
|
|
|
protected $collapsed = false; |
30
|
|
|
|
31
|
|
|
public $labels = array( |
32
|
|
|
'singular_name' => 'Entry', |
33
|
|
|
'plural_name' => 'Entries', |
34
|
|
|
); |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* Initialization tasks. |
38
|
|
|
*/ |
39
|
|
View Code Duplication |
public function init() { |
|
|
|
|
40
|
|
|
$this->labels = array( |
41
|
|
|
'singular_name' => __( 'Entry', 'carbon-fields' ), |
42
|
|
|
'plural_name' => __( 'Entries', 'carbon-fields' ), |
43
|
|
|
); |
44
|
|
|
|
45
|
|
|
// Include the complex group Underscore templates |
46
|
|
|
$this->add_template( 'Complex-Group', array( $this, 'template_group' ) ); |
47
|
|
|
$this->add_template( 'Complex-Group-Tab-Item', array( $this, 'template_group_tab_item' ) ); |
48
|
|
|
|
49
|
|
|
parent::init(); |
50
|
|
|
} |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* Add a set/group of fields. |
54
|
|
|
* |
55
|
|
|
* @return $this |
56
|
|
|
*/ |
57
|
|
View Code Duplication |
public function add_fields() { |
|
|
|
|
58
|
|
|
$argv = func_get_args(); |
59
|
|
|
$argc = count( $argv ); |
60
|
|
|
|
61
|
|
|
if ( $argc == 1 ) { |
62
|
|
|
$fields = $argv[0]; |
63
|
|
|
$name = ''; |
64
|
|
|
$label = null; |
65
|
|
|
} else if ( $argc == 2 ) { |
66
|
|
|
if ( is_array( $argv[0] ) ) { |
67
|
|
|
list( $fields, $name ) = $argv; |
68
|
|
|
} else { |
69
|
|
|
list( $name, $fields ) = $argv; |
70
|
|
|
} |
71
|
|
|
$label = null; |
72
|
|
|
} else if ( $argc == 3 ) { |
73
|
|
|
if ( is_array( $argv[0] ) ) { |
74
|
|
|
list( $fields, $name, $label ) = $argv; |
75
|
|
|
} else { |
76
|
|
|
list( $name, $label, $fields ) = $argv; |
77
|
|
|
} |
78
|
|
|
} |
79
|
|
|
|
80
|
|
|
if ( array_key_exists( '_' . $name, $this->groups ) ) { |
81
|
|
|
Incorrect_Syntax_Exception::raise( 'Group with name "' . $name . '" in Complex Field "' . $this->get_label() . '" already exists.' ); |
|
|
|
|
82
|
|
|
} |
83
|
|
|
|
84
|
|
|
$group = new Group_Field($name, $label, $fields); |
|
|
|
|
85
|
|
|
|
86
|
|
|
$this->groups[ $group->get_name() ] = $group; |
87
|
|
|
|
88
|
|
|
return $this; |
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
/** |
92
|
|
|
* Set the group label Underscore template. |
93
|
|
|
* |
94
|
|
|
* @param string|callable $template |
95
|
|
|
* @return $this |
96
|
|
|
*/ |
97
|
|
View Code Duplication |
public function set_header_template( $template ) { |
|
|
|
|
98
|
|
|
if ( count($this->groups) === 0 ) { |
|
|
|
|
99
|
|
|
Incorrect_Syntax_Exception::raise( "Can't set group label template. There are no present groups for Complex Field " . $this->get_label() . "." ); |
|
|
|
|
100
|
|
|
} |
101
|
|
|
|
102
|
|
|
$template = is_callable( $template ) ? call_user_func( $template ) : $template; |
103
|
|
|
|
104
|
|
|
// Assign the template to the group that was added last |
105
|
|
|
$values = array_values( $this->groups ); |
106
|
|
|
$group = end( $values ); |
107
|
|
|
$group->set_label_template( $template ); |
108
|
|
|
|
109
|
|
|
// Include the group label Underscore template |
110
|
|
|
$this->add_template( $group->get_group_id(), array( $group, 'template_label' ) ); |
111
|
|
|
|
112
|
|
|
$this->groups[ $group->get_name() ] = $group; |
113
|
|
|
|
114
|
|
|
return $this; |
115
|
|
|
} |
116
|
|
|
|
117
|
|
|
/** |
118
|
|
|
* Retrieve all groups of fields. |
119
|
|
|
* |
120
|
|
|
* @return array $fields |
121
|
|
|
*/ |
122
|
|
View Code Duplication |
public function get_fields() { |
|
|
|
|
123
|
|
|
$fields = array(); |
124
|
|
|
|
125
|
|
|
foreach ( $this->groups as $group ) { |
126
|
|
|
$group_fields = $group->get_fields(); |
127
|
|
|
|
128
|
|
|
$fields = array_merge( $fields, $group_fields ); |
129
|
|
|
} |
130
|
|
|
|
131
|
|
|
return $fields; |
132
|
|
|
} |
133
|
|
|
|
134
|
|
|
/** |
135
|
|
|
* Set the field labels. |
136
|
|
|
* Currently supported values: |
137
|
|
|
* - singular_name - the singular entry label |
138
|
|
|
* - plural_name - the plural entries label |
139
|
|
|
* |
140
|
|
|
* @param array $labels Labels |
141
|
|
|
*/ |
142
|
|
|
public function setup_labels( $labels ) { |
143
|
|
|
$this->labels = array_merge( $this->labels, $labels ); |
144
|
|
|
return $this; |
145
|
|
|
} |
146
|
|
|
|
147
|
|
|
/** |
148
|
|
|
* Set the datastore of this field. |
149
|
|
|
* |
150
|
|
|
* @param Datastore_Interface $store |
151
|
|
|
*/ |
152
|
|
|
public function set_datastore( Datastore_Interface $store ) { |
153
|
|
|
$this->store = $store; |
154
|
|
|
|
155
|
|
|
foreach ( $this->groups as $group ) { |
156
|
|
|
$group->set_datastore( $this->store ); |
157
|
|
|
} |
158
|
|
|
} |
159
|
|
|
|
160
|
|
|
/** |
161
|
|
|
* Load the field value from an input array based on it's name. |
162
|
|
|
* |
163
|
|
|
* @param array $input (optional) Array of field names and values. Defaults to $_POST |
164
|
|
|
**/ |
165
|
|
|
public function set_value_from_input( $input = null ) { |
166
|
|
|
$this->values = array(); |
167
|
|
|
|
168
|
|
|
if ( is_null( $input ) ) { |
169
|
|
|
$input = $_POST; |
|
|
|
|
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
if ( ! isset( $input[ $this->get_name() ] ) ) { |
173
|
|
|
return; |
174
|
|
|
} |
175
|
|
|
|
176
|
|
|
$input_groups = $input[ $this->get_name() ]; |
177
|
|
|
$index = 0; |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
180
|
|
|
foreach ( $input_groups as $values ) { |
181
|
|
|
$value_group = array(); |
182
|
|
View Code Duplication |
if ( ! isset( $values['group'] ) || ! isset( $this->groups[ $values['group'] ] ) ) { |
|
|
|
|
183
|
|
|
continue; |
184
|
|
|
} |
185
|
|
|
|
186
|
|
|
$group = $this->groups[ $values['group'] ]; |
187
|
|
|
unset( $values['group'] ); |
188
|
|
|
|
189
|
|
|
$group_fields = $group->get_fields(); |
190
|
|
|
|
191
|
|
|
// trim input values to those used by the field |
192
|
|
|
$group_field_names = array_flip( $group->get_field_names() ); |
193
|
|
|
$values = array_intersect_key( $values, $group_field_names ); |
194
|
|
|
|
195
|
|
|
foreach ( $group_fields as $field ) { |
196
|
|
|
// set value from the group |
197
|
|
|
$tmp_field = clone $field; |
198
|
|
|
if ( is_a( $tmp_field, __NAMESPACE__ . '\\Complex_Field' ) ) { |
199
|
|
|
if ( ! isset( $values[ $tmp_field->get_name() ] ) ) { |
200
|
|
|
continue; // bail if the complex field is empty |
201
|
|
|
} |
202
|
|
|
|
203
|
|
|
$new_name = $this->get_name() . $group->get_name() . '-' . $field->get_name() . '_' . $index; |
204
|
|
|
$new_values = array( $new_name => $values[ $tmp_field->get_name() ] ); |
205
|
|
|
|
206
|
|
|
$tmp_field->set_name( $new_name ); |
207
|
|
|
$tmp_field->set_value_from_input( $new_values ); |
208
|
|
|
} else { |
209
|
|
|
$tmp_field->set_value_from_input( $values ); |
210
|
|
|
} |
211
|
|
|
|
212
|
|
|
// update name to group name |
213
|
|
|
$tmp_field->set_name( $this->get_name() . $group->get_name() . '-' . $field->get_name() . '_' . $index ); |
214
|
|
|
$value_group[] = $tmp_field; |
215
|
|
|
} |
216
|
|
|
|
217
|
|
|
$this->values[] = $value_group; |
218
|
|
|
$index++; |
219
|
|
|
} |
220
|
|
|
} |
221
|
|
|
|
222
|
|
|
/** |
223
|
|
|
* Load all groups of fields and their data. |
224
|
|
|
*/ |
225
|
|
|
public function load() { |
226
|
|
|
// load existing groups |
227
|
|
|
$this->load_values(); |
228
|
|
|
} |
229
|
|
|
|
230
|
|
|
/** |
231
|
|
|
* Save all contained groups of fields. |
232
|
|
|
*/ |
233
|
|
|
public function save() { |
234
|
|
|
$this->delete(); |
235
|
|
|
|
236
|
|
|
foreach ( $this->values as $value ) { |
237
|
|
|
foreach ( $value as $field ) { |
238
|
|
|
$field->save(); |
239
|
|
|
} |
240
|
|
|
} |
241
|
|
|
} |
242
|
|
|
|
243
|
|
|
/** |
244
|
|
|
* Delete the values of all contained fields. |
245
|
|
|
*/ |
246
|
|
|
public function delete() { |
247
|
|
|
return $this->store->delete_values( $this ); |
248
|
|
|
} |
249
|
|
|
|
250
|
|
|
/** |
251
|
|
|
* Load and parse the field data. |
252
|
|
|
*/ |
253
|
|
|
public function load_values() { |
254
|
|
|
return $this->load_values_from_db(); |
255
|
|
|
} |
256
|
|
|
|
257
|
|
|
/** |
258
|
|
|
* Load and parse the field data from the database. |
259
|
|
|
*/ |
260
|
|
|
public function load_values_from_db() { |
261
|
|
|
$this->values = array(); |
262
|
|
|
|
263
|
|
|
$group_rows = $this->store->load_values( $this ); |
264
|
|
|
|
265
|
|
|
return $this->process_loaded_values( $group_rows ); |
266
|
|
|
} |
267
|
|
|
|
268
|
|
|
/** |
269
|
|
|
* Load and parse a raw set of field data. |
270
|
|
|
* |
271
|
|
|
* @param array $values Raw data entries |
272
|
|
|
* @return array Processed data entries |
273
|
|
|
*/ |
274
|
|
View Code Duplication |
public function load_values_from_array( $values ) { |
|
|
|
|
275
|
|
|
$this->values = array(); |
276
|
|
|
|
277
|
|
|
$group_rows = array(); |
278
|
|
|
|
279
|
|
|
$meta_key = $this->get_name(); |
280
|
|
|
|
281
|
|
|
foreach ( $values as $key => $value ) { |
282
|
|
|
if ( strpos( $key, $meta_key ) !== 0 ) { |
283
|
|
|
continue; |
284
|
|
|
} |
285
|
|
|
|
286
|
|
|
$group_rows[] = array( |
287
|
|
|
'field_key' => preg_replace( '~^(' . preg_quote( $this->name, '~' ) . ')_\d+_~', '$1_', $key ), |
288
|
|
|
'field_value' => $value, |
289
|
|
|
); |
290
|
|
|
} |
291
|
|
|
|
292
|
|
|
return $this->process_loaded_values( $group_rows ); |
293
|
|
|
} |
294
|
|
|
|
295
|
|
|
/** |
296
|
|
|
* Parse groups of raw field data into the actual field hierarchy. |
297
|
|
|
* |
298
|
|
|
* @param array $group_rows Group rows |
299
|
|
|
*/ |
300
|
|
View Code Duplication |
public function process_loaded_values( $group_rows ) { |
|
|
|
|
301
|
|
|
$input_groups = array(); |
302
|
|
|
|
303
|
|
|
// Set default values |
304
|
|
|
$field_names = array(); |
305
|
|
|
foreach ( $this->groups as $group ) { |
306
|
|
|
$group_fields = $group->get_fields(); |
307
|
|
|
foreach ( $group_fields as $field ) { |
308
|
|
|
$field_names[] = $field->get_name(); |
309
|
|
|
$field->set_value( $field->get_default_value() ); |
310
|
|
|
} |
311
|
|
|
} |
312
|
|
|
|
313
|
|
|
if ( empty( $group_rows ) ) { |
314
|
|
|
return; |
315
|
|
|
} |
316
|
|
|
|
317
|
|
|
// load and parse values and group type |
318
|
|
|
foreach ( $group_rows as $row ) { |
319
|
|
|
if ( ! preg_match( Helper::get_complex_field_regex( $this->name, array_keys( $this->groups ), $field_names ), $row['field_key'], $field_name ) ) { |
320
|
|
|
continue; |
321
|
|
|
} |
322
|
|
|
|
323
|
|
|
$row['field_value'] = maybe_unserialize( $row['field_value'] ); |
324
|
|
|
$input_groups[ $field_name['index'] ]['type'] = $field_name['group']; |
325
|
|
|
|
326
|
|
|
if ( ! empty( $field_name['trailing'] ) ) { |
327
|
|
|
$input_groups[ $field_name['index'] ][ $field_name['key'] . '_' . $field_name['sub'] . '-' . $field_name['trailing'] ] = $row['field_value']; |
328
|
|
|
} else if ( ! empty( $field_name['sub'] ) ) { |
329
|
|
|
$input_groups[ $field_name['index'] ][ $field_name['key'] ][ $field_name['sub'] ] = $row['field_value']; |
330
|
|
|
} else { |
331
|
|
|
$input_groups[ $field_name['index'] ][ $field_name['key'] ] = $row['field_value']; |
332
|
|
|
} |
333
|
|
|
} |
334
|
|
|
|
335
|
|
|
// create groups list with loaded fields |
336
|
|
|
ksort( $input_groups ); |
337
|
|
|
|
338
|
|
|
foreach ( $input_groups as $index => $values ) { |
339
|
|
|
$value_group = array( 'type' => $values['type'] ); |
340
|
|
|
$group_fields = $this->groups[ $values['type'] ]->get_fields(); |
341
|
|
|
unset( $values['type'] ); |
342
|
|
|
|
343
|
|
|
foreach ( $group_fields as $field ) { |
344
|
|
|
// set value from the group |
345
|
|
|
$tmp_field = clone $field; |
346
|
|
|
|
347
|
|
|
if ( is_a( $field, __NAMESPACE__ . '\\Complex_Field' ) ) { |
348
|
|
|
$tmp_field->load_values_from_array( $values ); |
349
|
|
|
} else { |
350
|
|
|
$tmp_field->set_value_from_input( $values ); |
351
|
|
|
} |
352
|
|
|
|
353
|
|
|
$value_group[] = $tmp_field; |
354
|
|
|
} |
355
|
|
|
|
356
|
|
|
$this->values[] = $value_group; |
357
|
|
|
} |
358
|
|
|
} |
359
|
|
|
|
360
|
|
|
/** |
361
|
|
|
* Retrieve the field values. |
362
|
|
|
* @return array |
363
|
|
|
*/ |
364
|
|
|
public function get_values() { |
365
|
|
|
return $this->values; |
366
|
|
|
} |
367
|
|
|
|
368
|
|
|
/** |
369
|
|
|
* Generate and set the field prefix. |
370
|
|
|
* @param string $prefix |
371
|
|
|
*/ |
372
|
|
|
public function set_prefix( $prefix ) { |
373
|
|
|
parent::set_prefix( $prefix ); |
374
|
|
|
|
375
|
|
|
foreach ( $this->groups as $group ) { |
376
|
|
|
$group->set_prefix( $prefix ); |
377
|
|
|
} |
378
|
|
|
} |
379
|
|
|
|
380
|
|
|
/** |
381
|
|
|
* Returns an array that holds the field data, suitable for JSON representation. |
382
|
|
|
* This data will be available in the Underscore template and the Backbone Model. |
383
|
|
|
* |
384
|
|
|
* @param bool $load Should the value be loaded from the database or use the value from the current instance. |
385
|
|
|
* @return array |
386
|
|
|
*/ |
387
|
|
View Code Duplication |
public function to_json( $load ) { |
|
|
|
|
388
|
|
|
$complex_data = parent::to_json( $load ); |
389
|
|
|
|
390
|
|
|
$groups_data = array(); |
391
|
|
|
$values_data = array(); |
392
|
|
|
|
393
|
|
|
foreach ( $this->groups as $group ) { |
394
|
|
|
$groups_data[] = $group->to_json( false ); |
395
|
|
|
} |
396
|
|
|
|
397
|
|
|
foreach ( $this->values as $fields ) { |
398
|
|
|
$group = $this->get_group_by_name( $fields['type'] ); |
399
|
|
|
unset( $fields['type'] ); |
400
|
|
|
|
401
|
|
|
$data = array( |
402
|
|
|
'name' => $group->get_name(), |
403
|
|
|
'label' => $group->get_label(), |
404
|
|
|
'group_id' => $group->get_group_id(), |
405
|
|
|
'fields' => array(), |
406
|
|
|
); |
407
|
|
|
|
408
|
|
|
foreach ( $fields as $index => $field ) { |
409
|
|
|
$data['fields'][] = $field->to_json( false ); |
410
|
|
|
} |
411
|
|
|
|
412
|
|
|
$values_data[] = $data; |
413
|
|
|
} |
414
|
|
|
|
415
|
|
|
$complex_data = array_merge( $complex_data, array( |
416
|
|
|
'layout' => $this->layout, |
417
|
|
|
'labels' => $this->labels, |
418
|
|
|
'min' => $this->get_min(), |
419
|
|
|
'max' => $this->get_max(), |
420
|
|
|
'multiple_groups' => count( $groups_data ) > 1, |
421
|
|
|
'groups' => $groups_data, |
422
|
|
|
'value' => $values_data, |
423
|
|
|
'collapsed' => $this->collapsed, |
424
|
|
|
) ); |
425
|
|
|
|
426
|
|
|
return $complex_data; |
427
|
|
|
} |
428
|
|
|
|
429
|
|
|
/** |
430
|
|
|
* The main Underscore template. |
431
|
|
|
*/ |
432
|
|
|
public function template() { |
433
|
|
|
?> |
434
|
|
|
<div class="carbon-subcontainer carbon-grid {{ multiple_groups ? 'multiple-groups' : '' }}"> |
435
|
|
|
<div class="carbon-empty-row carbon-empty-row-visible"> |
436
|
|
|
{{{ crbl10n.complex_no_rows.replace('%s', labels.plural_name) }}} |
437
|
|
|
</div> |
438
|
|
|
|
439
|
|
|
<div class="groups-wrapper layout-{{ layout }}"> |
440
|
|
|
<# if (layout === '<?php echo self::LAYOUT_TABBED_HORIZONTAL ?>' || layout === '<?php echo self::LAYOUT_TABBED_VERTICAL ?>' ) { #> |
|
|
|
|
441
|
|
|
<div class="group-tabs-nav-holder"> |
442
|
|
|
<ul class="group-tabs-nav"></ul> |
443
|
|
|
|
444
|
|
|
<div class="carbon-actions"> |
445
|
|
|
<div class="carbon-button"> |
446
|
|
|
<a href="#" class="button" data-group="{{{ multiple_groups ? '' : groups[0].name }}}"> |
447
|
|
|
+ |
448
|
|
|
</a> |
449
|
|
|
|
450
|
|
|
<# if (multiple_groups) { #> |
451
|
|
|
<ul> |
452
|
|
|
<# _.each(groups, function(group) { #> |
453
|
|
|
<li><a href="#" data-group="{{{ group.name }}}">{{{ group.label }}}</a></li> |
454
|
|
|
<# }); #> |
455
|
|
|
</ul> |
456
|
|
|
<# } #> |
457
|
|
|
</div> |
458
|
|
|
</div> |
459
|
|
|
</div><!-- /.group-tabs-nav-holder --> |
460
|
|
|
<# } #> |
461
|
|
|
|
462
|
|
|
<div class="carbon-groups-holder"></div> |
463
|
|
|
<div class="clear"></div> |
464
|
|
|
</div> |
465
|
|
|
|
466
|
|
|
<div class="carbon-actions"> |
467
|
|
|
<div class="carbon-button"> |
468
|
|
|
<a href="#" class="button" data-group="{{{ multiple_groups ? '' : groups[0].name }}}"> |
469
|
|
|
{{{ crbl10n.complex_add_button.replace('%s', labels.singular_name) }}} |
470
|
|
|
</a> |
471
|
|
|
|
472
|
|
|
<# if (multiple_groups) { #> |
473
|
|
|
<ul> |
474
|
|
|
<# _.each(groups, function(group) { #> |
475
|
|
|
<li><a href="#" data-group="{{{ group.name }}}">{{{ group.label }}}</a></li> |
476
|
|
|
<# }); #> |
477
|
|
|
</ul> |
478
|
|
|
<# } #> |
479
|
|
|
</div> |
480
|
|
|
</div> |
481
|
|
|
</div> |
482
|
|
|
<?php |
483
|
|
|
} |
484
|
|
|
|
485
|
|
|
/** |
486
|
|
|
* The Underscore template for the complex field group. |
487
|
|
|
*/ |
488
|
|
View Code Duplication |
public function template_group() { |
|
|
|
|
489
|
|
|
?> |
490
|
|
|
<div id="carbon-{{{ complex_name }}}-complex-container" class="carbon-row carbon-group-row" data-group-id="{{ id }}"> |
491
|
|
|
<input type="hidden" name="{{{ complex_name + '[' + index + ']' }}}[group]" value="{{ name }}" /> |
492
|
|
|
|
493
|
|
|
<div class="carbon-drag-handle"> |
494
|
|
|
<span class="group-number">{{{ order + 1 }}}</span><span class="group-name">{{{ label_template || label }}}</span> |
495
|
|
|
</div> |
496
|
|
|
|
497
|
|
|
<div class="carbon-group-actions carbon-group-actions-{{ layout }}"> |
498
|
|
|
<a class="carbon-btn-duplicate dashicons-before dashicons-admin-page" href="#" title="<?php esc_attr_e( 'Clone', 'carbon_fields' ); ?>"> |
499
|
|
|
<?php _e( 'Clone', 'carbon_fields' ); ?> |
500
|
|
|
</a> |
501
|
|
|
|
502
|
|
|
<a class="carbon-btn-remove dashicons-before dashicons-trash" href="#" title="<?php esc_attr_e( 'Remove', 'carbon_fields' ); ?>"> |
503
|
|
|
<?php _e( 'Remove', 'carbon_fields' ); ?> |
504
|
|
|
</a> |
505
|
|
|
|
506
|
|
|
<a class="carbon-btn-collapse dashicons-before dashicons-arrow-up" href="#" title="<?php esc_attr_e( 'Collapse/Expand', 'carbon_fields' ); ?>"> |
507
|
|
|
<?php _e( 'Collapse/Expand', 'carbon_fields' ); ?> |
508
|
|
|
</a> |
509
|
|
|
</div> |
510
|
|
|
|
511
|
|
|
<div class="fields-container"> |
512
|
|
|
<# _.each(fields, function(field) { #> |
513
|
|
|
<div class="carbon-row carbon-subrow subrow-{{{ field.type }}} {{{ field.classes.join(' ') }}}"> |
514
|
|
|
<label for="{{{ complex_id + '-' + field.id + '-' + index }}}"> |
515
|
|
|
{{ field.label }} |
516
|
|
|
|
517
|
|
|
<# if (field.required) { #> |
518
|
|
|
<span class="carbon-required">*</span> |
519
|
|
|
<# } #> |
520
|
|
|
</label> |
521
|
|
|
|
522
|
|
|
<div class="field-holder {{{ complex_id + '-' + field.id + '-' + index }}}"></div> |
523
|
|
|
|
524
|
|
|
<# if (field.help_text) { #> |
525
|
|
|
<em class="help-text"> |
526
|
|
|
{{{ field.help_text }}} |
527
|
|
|
</em> |
528
|
|
|
<# } #> |
529
|
|
|
|
530
|
|
|
<em class="carbon-error"></em> |
531
|
|
|
</div> |
532
|
|
|
<# }) #> |
533
|
|
|
</div> |
534
|
|
|
</div> |
535
|
|
|
<?php |
536
|
|
|
} |
537
|
|
|
|
538
|
|
|
/** |
539
|
|
|
* The Underscore template for the group item tab. |
540
|
|
|
*/ |
541
|
|
|
public function template_group_tab_item() { |
542
|
|
|
?> |
543
|
|
|
<li class="group-tab-item" data-group-id="{{ id }}"> |
544
|
|
|
<a href="#"> |
545
|
|
|
<span class="group-handle"></span> |
546
|
|
|
|
547
|
|
|
<# if (label_template || label) { #> |
548
|
|
|
<span class="group-name">{{{ label_template || label }}}</span> |
549
|
|
|
<# } #> |
550
|
|
|
<span class="group-number">{{{ order + 1 }}}</span> |
551
|
|
|
<span class="dashicons dashicons-warning carbon-complex-group-error-badge" ></span> |
552
|
|
|
</a> |
553
|
|
|
</li> |
554
|
|
|
<?php |
555
|
|
|
} |
556
|
|
|
|
557
|
|
|
/** |
558
|
|
|
* Modify the layout of this field. |
559
|
|
|
* |
560
|
|
|
* @param string $layout |
561
|
|
|
*/ |
562
|
|
View Code Duplication |
public function set_layout( $layout ) { |
|
|
|
|
563
|
|
|
$available_layouts = array( |
564
|
|
|
self::LAYOUT_GRID, |
565
|
|
|
self::LAYOUT_TABBED_HORIZONTAL, |
566
|
|
|
self::LAYOUT_TABBED_VERTICAL, |
567
|
|
|
self::LAYOUT_LIST, |
568
|
|
|
); |
569
|
|
|
|
570
|
|
|
if ( $layout === self::LAYOUT_TABBED ) { |
571
|
|
|
// The library used to provide just one kind of tabs -- horizontal ones. Later vertical tabs were added. |
572
|
|
|
// So the "tabbed" name was renamed to "tabbed-horizontal" and "tabbed-vertical" layout was introduced. |
573
|
|
|
_doing_it_wrong( __METHOD__, sprintf( __( 'Complex field "%1$s" layout is deprecated, please use "%2$s" or "%3$s" instead.', 'carbon_fields' ), self::LAYOUT_TABBED, self::LAYOUT_TABBED_HORIZONTAL, self::LAYOUT_TABBED_VERTICAL ), null ); |
574
|
|
|
|
575
|
|
|
$layout = self::LAYOUT_TABBED_HORIZONTAL; |
576
|
|
|
} |
577
|
|
|
|
578
|
|
|
if ( ! in_array( $layout, $available_layouts ) ) { |
579
|
|
|
$error_message = 'Incorrect layout ``' . $layout . '" specified. ' . |
580
|
|
|
'Available layouts: ' . implode( ', ', $available_layouts ); |
581
|
|
|
|
582
|
|
|
Incorrect_Syntax_Exception::raise( $error_message ); |
583
|
|
|
} |
584
|
|
|
|
585
|
|
|
if ( $layout === self::LAYOUT_LIST ) { |
586
|
|
|
_doing_it_wrong( __METHOD__, __( 'Complex field <code>' . self::LAYOUT_LIST . '</code> layout is deprecated, please use <code>set_width()</code> instead.', 'carbon_fields' ), null ); |
|
|
|
|
587
|
|
|
} |
588
|
|
|
|
589
|
|
|
$this->layout = $layout; |
590
|
|
|
|
591
|
|
|
return $this; |
592
|
|
|
} |
593
|
|
|
|
594
|
|
|
/** |
595
|
|
|
* Set the minimum number of entries. |
596
|
|
|
* |
597
|
|
|
* @param int $min |
598
|
|
|
*/ |
599
|
|
|
public function set_min( $min ) { |
600
|
|
|
$this->values_min = intval( $min ); |
601
|
|
|
return $this; |
602
|
|
|
} |
603
|
|
|
|
604
|
|
|
/** |
605
|
|
|
* Get the minimum number of entries. |
606
|
|
|
* |
607
|
|
|
* @return int $min |
608
|
|
|
*/ |
609
|
|
|
public function get_min() { |
610
|
|
|
return $this->values_min; |
611
|
|
|
} |
612
|
|
|
|
613
|
|
|
/** |
614
|
|
|
* Set the maximum number of entries. |
615
|
|
|
* |
616
|
|
|
* @param int $max |
617
|
|
|
*/ |
618
|
|
|
public function set_max( $max ) { |
619
|
|
|
$this->values_max = intval( $max ); |
620
|
|
|
return $this; |
621
|
|
|
} |
622
|
|
|
|
623
|
|
|
/** |
624
|
|
|
* Get the maximum number of entries. |
625
|
|
|
* |
626
|
|
|
* @return int $max |
627
|
|
|
*/ |
628
|
|
|
public function get_max() { |
629
|
|
|
return $this->values_max; |
630
|
|
|
} |
631
|
|
|
|
632
|
|
|
/** |
633
|
|
|
* Change the groups initial collapse state. |
634
|
|
|
* This state relates to the state of which the groups are rendered. |
635
|
|
|
* |
636
|
|
|
* @param bool $collapsed |
637
|
|
|
*/ |
638
|
|
|
public function set_collapsed( $collapsed = true ) { |
639
|
|
|
$this->collapsed = $collapsed; |
640
|
|
|
|
641
|
|
|
return $this; |
642
|
|
|
} |
643
|
|
|
|
644
|
|
|
/** |
645
|
|
|
* Retrieve the groups of this field. |
646
|
|
|
* |
647
|
|
|
* @return array |
648
|
|
|
*/ |
649
|
|
|
public function get_group_names() { |
650
|
|
|
return array_keys( $this->groups ); |
651
|
|
|
} |
652
|
|
|
|
653
|
|
|
/** |
654
|
|
|
* Retrieve a group by its name. |
655
|
|
|
* |
656
|
|
|
* @param string $group_name Group name |
657
|
|
|
* @return Group_Field $group_object Group object |
658
|
|
|
*/ |
659
|
|
View Code Duplication |
public function get_group_by_name( $group_name ) { |
|
|
|
|
660
|
|
|
$group_object = null; |
661
|
|
|
|
662
|
|
|
foreach ( $this->groups as $group ) { |
663
|
|
|
if ( $group->get_name() == $group_name ) { |
664
|
|
|
$group_object = $group; |
665
|
|
|
} |
666
|
|
|
} |
667
|
|
|
|
668
|
|
|
return $group_object; |
669
|
|
|
} |
670
|
|
|
} |
671
|
|
|
|
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.