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
|
|
|
public $static = false; |
28
|
|
|
protected $values_min = -1; |
29
|
|
|
protected $values_max = -1; |
30
|
|
|
|
31
|
|
|
public $labels = array( |
32
|
|
|
'singular_name' => 'Entry', |
33
|
|
|
'plural_name' => 'Entries', |
34
|
|
|
); |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* Initialization tasks. |
38
|
|
|
*/ |
39
|
|
|
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
|
|
|
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
|
|
View Code Duplication |
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
|
|
View Code Duplication |
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
View Code Duplication |
} 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
|
|
|
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
|
|
|
'static' => $this->static, |
406
|
|
|
'fields' => array(), |
407
|
|
|
); |
408
|
|
|
|
409
|
|
|
foreach ( $fields as $index => $field ) { |
410
|
|
|
$data['fields'][] = $field->to_json( false ); |
411
|
|
|
} |
412
|
|
|
|
413
|
|
|
$values_data[] = $data; |
414
|
|
|
} |
415
|
|
|
|
416
|
|
|
$complex_data = array_merge( $complex_data, array( |
417
|
|
|
'layout' => $this->layout, |
418
|
|
|
'static' => $this->static, |
419
|
|
|
'labels' => $this->labels, |
420
|
|
|
'min' => $this->static ? count( $groups_data ) : $this->get_min(), |
421
|
|
|
'max' => $this->static ? count( $groups_data ) : $this->get_max(), |
422
|
|
|
'multiple_groups' => count( $groups_data ) > 1, |
423
|
|
|
'groups' => $groups_data, |
424
|
|
|
'value' => $values_data, |
425
|
|
|
) ); |
426
|
|
|
|
427
|
|
|
return $complex_data; |
428
|
|
|
} |
429
|
|
|
|
430
|
|
|
/** |
431
|
|
|
* The main Underscore template. |
432
|
|
|
*/ |
433
|
|
|
public function template() { |
434
|
|
|
?> |
435
|
|
|
<div class="carbon-subcontainer carbon-grid {{ multiple_groups ? 'multiple-groups' : '' }}"> |
436
|
|
|
<div class="carbon-empty-row"> |
437
|
|
|
{{{ crbl10n.complex_no_rows.replace('%s', labels.plural_name) }}} |
438
|
|
|
</div> |
439
|
|
|
|
440
|
|
|
<div class="groups-wrapper layout-{{ layout }}"> |
441
|
|
|
<# if (layout === '<?php echo self::LAYOUT_TABBED_HORIZONTAL ?>' || layout === '<?php echo self::LAYOUT_TABBED_VERTICAL ?>' ) { #> |
|
|
|
|
442
|
|
|
<div class="group-tabs-nav-holder"> |
443
|
|
|
<ul class="group-tabs-nav"></ul> |
444
|
|
|
|
445
|
|
|
<div class="carbon-actions"> |
446
|
|
|
<div class="carbon-button"> |
447
|
|
|
<a href="#" class="button" data-group="{{{ multiple_groups ? '' : groups[0].name }}}"> |
448
|
|
|
+ |
449
|
|
|
</a> |
450
|
|
|
|
451
|
|
|
<# if (multiple_groups) { #> |
452
|
|
|
<ul> |
453
|
|
|
<# _.each(groups, function(group) { #> |
454
|
|
|
<li><a href="#" data-group="{{{ group.name }}}">{{{ group.label }}}</a></li> |
455
|
|
|
<# }); #> |
456
|
|
|
</ul> |
457
|
|
|
<# } #> |
458
|
|
|
</div> |
459
|
|
|
</div> |
460
|
|
|
</div><!-- /.group-tabs-nav-holder --> |
461
|
|
|
<# } #> |
462
|
|
|
|
463
|
|
|
<div class="carbon-groups-holder"></div> |
464
|
|
|
<div class="clear"></div> |
465
|
|
|
</div> |
466
|
|
|
|
467
|
|
|
<div class="carbon-actions"> |
468
|
|
|
<div class="carbon-button"> |
469
|
|
|
<a href="#" class="button" data-group="{{{ multiple_groups ? '' : groups[0].name }}}"> |
470
|
|
|
{{{ crbl10n.complex_add_button.replace('%s', labels.singular_name) }}} |
471
|
|
|
{{{ multiple_groups ? '⇩' : '' }}} |
472
|
|
|
</a> |
473
|
|
|
|
474
|
|
|
<# if (multiple_groups) { #> |
475
|
|
|
<ul> |
476
|
|
|
<# _.each(groups, function(group) { #> |
477
|
|
|
<li><a href="#" data-group="{{{ group.name }}}">{{{ group.label }}}</a></li> |
478
|
|
|
<# }); #> |
479
|
|
|
</ul> |
480
|
|
|
<# } #> |
481
|
|
|
</div> |
482
|
|
|
</div> |
483
|
|
|
</div> |
484
|
|
|
<?php |
485
|
|
|
} |
486
|
|
|
|
487
|
|
|
/** |
488
|
|
|
* The Underscore template for the complex field group. |
489
|
|
|
*/ |
490
|
|
|
public function template_group() { |
491
|
|
|
?> |
492
|
|
|
<div id="carbon-{{{ complex_name }}}-complex-container" class="carbon-row carbon-group-row {{ static ? 'static' : '' }}" data-group-id="{{ id }}"> |
493
|
|
|
<input type="hidden" name="{{{ complex_name + '[' + index + ']' }}}[group]" value="{{ name }}" /> |
494
|
|
|
|
495
|
|
|
<div class="carbon-drag-handle"> |
496
|
|
|
<span class="group-number">{{{ order + 1 }}}</span><span class="group-name">{{{ label_template || label }}}</span> |
497
|
|
|
</div> |
498
|
|
|
|
499
|
|
|
<div class="carbon-group-actions"> |
500
|
|
|
<a class="carbon-btn-collapse" href="#" title="<?php esc_attr_e( 'Collapse/Expand', 'carbon_fields' ); ?>"> |
501
|
|
|
<?php _e( 'Collapse/Expand', 'carbon_fields' ); ?> |
502
|
|
|
</a> |
503
|
|
|
|
504
|
|
|
<# if (!static) { #> |
505
|
|
|
<a class="carbon-btn-duplicate" href="#" title="<?php esc_attr_e( 'Clone', 'carbon_fields' ); ?>"> |
506
|
|
|
<?php _e( 'Clone', 'carbon_fields' ); ?> |
507
|
|
|
</a> |
508
|
|
|
|
509
|
|
|
<a class="carbon-btn-remove" href="#" title="<?php esc_attr_e( 'Remove', 'carbon_fields' ); ?>"> |
510
|
|
|
<?php _e( 'Remove', 'carbon_fields' ); ?> |
511
|
|
|
</a> |
512
|
|
|
<# } #> |
513
|
|
|
</div> |
514
|
|
|
|
515
|
|
|
<div class="fields-container"> |
516
|
|
|
<# _.each(fields, function(field) { #> |
517
|
|
|
<div class="carbon-row carbon-subrow subrow-{{{ field.type }}} {{{ field.classes.join(' ') }}}"> |
518
|
|
|
<label for="{{{ complex_id + '-' + field.id + '-' + index }}}"> |
519
|
|
|
{{ field.label }} |
520
|
|
|
|
521
|
|
|
<# if (field.required) { #> |
522
|
|
|
<span class="carbon-required">*</span> |
523
|
|
|
<# } #> |
524
|
|
|
</label> |
525
|
|
|
|
526
|
|
|
<div class="field-holder {{{ complex_id + '-' + field.id + '-' + index }}}"></div> |
527
|
|
|
|
528
|
|
|
<# if (field.help_text) { #> |
529
|
|
|
<em class="help-text"> |
530
|
|
|
{{{ field.help_text }}} |
531
|
|
|
</em> |
532
|
|
|
<# } #> |
533
|
|
|
|
534
|
|
|
<em class="carbon-error"></em> |
535
|
|
|
</div> |
536
|
|
|
<# }) #> |
537
|
|
|
</div> |
538
|
|
|
</div> |
539
|
|
|
<?php |
540
|
|
|
} |
541
|
|
|
|
542
|
|
|
/** |
543
|
|
|
* The Underscore template for the group item tab. |
544
|
|
|
*/ |
545
|
|
|
public function template_group_tab_item() { |
546
|
|
|
?> |
547
|
|
|
<li class="group-tab-item" data-group-id="{{ id }}"> |
548
|
|
|
<a href="#"> |
549
|
|
|
<span class="group-handle"></span> |
550
|
|
|
|
551
|
|
|
<# if (label_template || label) { #> |
552
|
|
|
<span class="group-name">{{{ label_template || label }}}</span> |
553
|
|
|
<# } #> |
554
|
|
|
<span class="group-number">{{{ order + 1 }}}</span> |
555
|
|
|
<span class="dashicons dashicons-warning carbon-complex-group-error-badge" ></span> |
556
|
|
|
</a> |
557
|
|
|
</li> |
558
|
|
|
<?php |
559
|
|
|
} |
560
|
|
|
|
561
|
|
|
/** |
562
|
|
|
* Modify the layout of this field. |
563
|
|
|
* |
564
|
|
|
* @param string $layout |
565
|
|
|
* @return Complex_Field |
566
|
|
|
*/ |
567
|
|
|
public function set_layout( $layout ) { |
568
|
|
|
$available_layouts = array( |
569
|
|
|
self::LAYOUT_GRID, |
570
|
|
|
self::LAYOUT_TABBED_HORIZONTAL, |
571
|
|
|
self::LAYOUT_TABBED_VERTICAL, |
572
|
|
|
self::LAYOUT_LIST, |
573
|
|
|
); |
574
|
|
|
|
575
|
|
|
if ( $layout === self::LAYOUT_TABBED ) { |
576
|
|
|
// The library used to provide just one kind of tabs -- horizontal ones. Later vertical tabs were added. |
577
|
|
|
// So the "tabbed" name was renamed to "tabbed-horizontal" and "tabbed-vertical" layout was introduced. |
578
|
|
|
_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 ); |
579
|
|
|
|
580
|
|
|
$layout = self::LAYOUT_TABBED_HORIZONTAL; |
581
|
|
|
} |
582
|
|
|
|
583
|
|
View Code Duplication |
if ( ! in_array( $layout, $available_layouts ) ) { |
|
|
|
|
584
|
|
|
$error_message = 'Incorrect layout ``' . $layout . '" specified. ' . |
585
|
|
|
'Available layouts: ' . implode( ', ', $available_layouts ); |
586
|
|
|
|
587
|
|
|
Incorrect_Syntax_Exception::raise( $error_message ); |
588
|
|
|
} |
589
|
|
|
|
590
|
|
|
if ( $layout === self::LAYOUT_LIST ) { |
591
|
|
|
_doing_it_wrong( __METHOD__, __( 'Complex field <code>' . self::LAYOUT_LIST . '</code> layout is deprecated, please use <code>set_width()</code> instead.', 'carbon_fields' ), null ); |
|
|
|
|
592
|
|
|
} |
593
|
|
|
|
594
|
|
|
$this->layout = $layout; |
595
|
|
|
|
596
|
|
|
return $this; |
597
|
|
|
} |
598
|
|
|
|
599
|
|
|
/** |
600
|
|
|
* Set the complex fields to static. |
601
|
|
|
* If you set the type to static, there will be no options to add or remove any group. |
602
|
|
|
* Min and max values are going to be ignored. |
603
|
|
|
* |
604
|
|
|
* @param string $static |
605
|
|
|
* @return Complex_Field |
606
|
|
|
*/ |
607
|
|
|
public function set_static($static) { |
608
|
|
|
$this->static = $static; |
|
|
|
|
609
|
|
|
return $this; |
610
|
|
|
} |
611
|
|
|
|
612
|
|
|
/** |
613
|
|
|
* Set the minimum number of entries. |
614
|
|
|
* |
615
|
|
|
* @param int $min |
616
|
|
|
* @return Complex_Field |
617
|
|
|
*/ |
618
|
|
|
public function set_min( $min ) { |
619
|
|
|
$this->values_min = intval( $min ); |
620
|
|
|
return $this; |
621
|
|
|
} |
622
|
|
|
|
623
|
|
|
/** |
624
|
|
|
* Get the minimum number of entries. |
625
|
|
|
* |
626
|
|
|
* @return int $min |
627
|
|
|
*/ |
628
|
|
|
public function get_min() { |
629
|
|
|
return $this->values_min; |
630
|
|
|
} |
631
|
|
|
|
632
|
|
|
/** |
633
|
|
|
* Set the maximum number of entries. |
634
|
|
|
* |
635
|
|
|
* @param int $max |
636
|
|
|
* @return Complex_Field |
637
|
|
|
*/ |
638
|
|
|
public function set_max( $max ) { |
639
|
|
|
$this->values_max = intval( $max ); |
640
|
|
|
return $this; |
641
|
|
|
} |
642
|
|
|
|
643
|
|
|
/** |
644
|
|
|
* Get the maximum number of entries. |
645
|
|
|
* |
646
|
|
|
* @return int $max |
647
|
|
|
*/ |
648
|
|
|
public function get_max() { |
649
|
|
|
return $this->values_max; |
650
|
|
|
} |
651
|
|
|
|
652
|
|
|
/** |
653
|
|
|
* Retrieve the groups of this field. |
654
|
|
|
* |
655
|
|
|
* @return array |
656
|
|
|
*/ |
657
|
|
|
public function get_group_names() { |
658
|
|
|
return array_keys( $this->groups ); |
659
|
|
|
} |
660
|
|
|
|
661
|
|
|
/** |
662
|
|
|
* Retrieve a group by its name. |
663
|
|
|
* |
664
|
|
|
* @param string $group_name Group name |
665
|
|
|
* @return Group_Field $group_object Group object |
666
|
|
|
*/ |
667
|
|
|
public function get_group_by_name( $group_name ) { |
668
|
|
|
$group_object = null; |
669
|
|
|
|
670
|
|
|
foreach ( $this->groups as $group ) { |
671
|
|
|
if ( $group->get_name() == $group_name ) { |
672
|
|
|
$group_object = $group; |
673
|
|
|
} |
674
|
|
|
} |
675
|
|
|
|
676
|
|
|
return $group_object; |
677
|
|
|
} |
678
|
|
|
} |
679
|
|
|
|
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.