PluginProbe ʕ •ᴥ•ʔ
Secure Custom Fields / 6.4.1-beta7
Secure Custom Fields v6.4.1-beta7
6.9.5 6.9.4 6.9.3 6.9.2 6.9.1 6.9.0 6.8.9 6.8.7 6.8.8 6.8.6 6.8.4 6.8.5 trunk 6.4.0-beta1 6.4.0-beta2 6.4.1 6.4.1-beta3 6.4.1-beta4 6.4.1-beta5 6.4.1-beta6 6.4.1-beta7 6.4.2 6.5.0 6.5.1 6.5.2 6.5.3 6.5.4 6.5.5 6.5.6 6.5.7 6.6.0 6.7.0 6.7.1 6.8.0 6.8.1 6.8.2 6.8.3
secure-custom-fields / includes / fields / class-acf-field-group.php
secure-custom-fields / includes / fields Last commit date
class-acf-field-accordion.php 1 year ago class-acf-field-button-group.php 1 year ago class-acf-field-checkbox.php 1 year ago class-acf-field-clone.php 1 year ago class-acf-field-color_picker.php 1 year ago class-acf-field-date_picker.php 1 year ago class-acf-field-date_time_picker.php 1 year ago class-acf-field-email.php 1 year ago class-acf-field-file.php 1 year ago class-acf-field-flexible-content.php 1 year ago class-acf-field-gallery.php 1 year ago class-acf-field-google-map.php 1 year ago class-acf-field-group.php 1 year ago class-acf-field-icon_picker.php 1 year ago class-acf-field-image.php 1 year ago class-acf-field-link.php 1 year ago class-acf-field-message.php 1 year ago class-acf-field-number.php 1 year ago class-acf-field-oembed.php 1 year ago class-acf-field-output.php 1 year ago class-acf-field-page_link.php 1 year ago class-acf-field-password.php 1 year ago class-acf-field-post_object.php 1 year ago class-acf-field-radio.php 1 year ago class-acf-field-range.php 1 year ago class-acf-field-relationship.php 1 year ago class-acf-field-repeater.php 1 year ago class-acf-field-select.php 1 year ago class-acf-field-separator.php 1 year ago class-acf-field-tab.php 1 year ago class-acf-field-taxonomy.php 1 year ago class-acf-field-text.php 1 year ago class-acf-field-textarea.php 1 year ago class-acf-field-time_picker.php 1 year ago class-acf-field-true_false.php 1 year ago class-acf-field-url.php 1 year ago class-acf-field-user.php 1 year ago class-acf-field-wysiwyg.php 1 year ago class-acf-field.php 1 year ago class-acf-repeater-table.php 1 year ago index.php 1 year ago
class-acf-field-group.php
651 lines
1 <?php
2
3 if ( ! class_exists( 'acf_field__group' ) ) :
4 #[AllowDynamicProperties]
5 class acf_field__group extends acf_field {
6
7
8 /**
9 * This function will setup the field type data
10 *
11 * @type function
12 * @date 5/03/2014
13 * @since ACF 5.0.0
14 *
15 * @param n/a
16 * @return n/a
17 */
18 function initialize() {
19
20 // vars
21 $this->name = 'group';
22 $this->label = __( 'Group', 'secure-custom-fields' );
23 $this->category = 'layout';
24 $this->description = __( 'Provides a way to structure fields into groups to better organize the data and the edit screen.', 'secure-custom-fields' );
25 $this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-group.png';
26 $this->doc_url = 'https://developer.wordpress.org/secure-custom-fields/features/fields/group/';
27 $this->tutorial_url = 'https://developer.wordpress.org/secure-custom-fields/features/fields/group/group-tutorial/';
28 $this->supports = array(
29 'bindings' => false,
30 );
31 $this->defaults = array(
32 'sub_fields' => array(),
33 'layout' => 'block',
34 );
35 $this->have_rows = 'single';
36
37 // field filters
38 $this->add_field_filter( 'acf/prepare_field_for_export', array( $this, 'prepare_field_for_export' ) );
39 $this->add_field_filter( 'acf/prepare_field_for_import', array( $this, 'prepare_field_for_import' ) );
40 }
41
42
43 /**
44 * This filter is appied to the $field after it is loaded from the database
45 *
46 * @type filter
47 * @since ACF 3.6
48 * @date 23/01/13
49 *
50 * @param $field - the field array holding all the field options
51 *
52 * @return $field - the field array holding all the field options
53 */
54 function load_field( $field ) {
55
56 // vars
57 $sub_fields = acf_get_fields( $field );
58
59 // append
60 if ( $sub_fields ) {
61 $field['sub_fields'] = $sub_fields;
62 }
63
64 // return
65 return $field;
66 }
67
68
69 /**
70 * This filter is applied to the $value after it is loaded from the db
71 *
72 * @type filter
73 * @since ACF 3.6
74 * @date 23/01/13
75 *
76 * @param $value (mixed) the value found in the database
77 * @param $post_id (mixed) the post_id from which the value was loaded
78 * @param $field (array) the field array holding all the field options
79 * @return $value
80 */
81 function load_value( $value, $post_id, $field ) {
82
83 // bail early if no sub fields
84 if ( empty( $field['sub_fields'] ) ) {
85 return $value;
86 }
87
88 // modify names
89 $field = $this->prepare_field_for_db( $field );
90
91 // load sub fields
92 $value = array();
93
94 // loop
95 foreach ( $field['sub_fields'] as $sub_field ) {
96
97 // load
98 $value[ $sub_field['key'] ] = acf_get_value( $post_id, $sub_field );
99 }
100
101 // return
102 return $value;
103 }
104
105
106 /**
107 * This filter is appied to the $value after it is loaded from the db and before it is returned to the template
108 *
109 * @type filter
110 * @since ACF 3.6
111 *
112 * @param mixed $value The value which was loaded from the database.
113 * @param mixed $post_id The $post_id from which the value was loaded.
114 * @param array $field The field array holding all the field options.
115 * @param boolean $escape_html Should the field return a HTML safe formatted value.
116 * @return mixed the modified value
117 */
118 public function format_value( $value, $post_id, $field, $escape_html = false ) {
119 // bail early if no value
120 if ( empty( $value ) ) {
121 return false;
122 }
123
124 // modify names
125 $field = $this->prepare_field_for_db( $field );
126
127 // loop
128 foreach ( $field['sub_fields'] as $sub_field ) {
129
130 // extract value
131 $sub_value = acf_extract_var( $value, $sub_field['key'] );
132
133 // format value
134 $sub_value = acf_format_value( $sub_value, $post_id, $sub_field, $escape_html );
135
136 // append to $row
137 $value[ $sub_field['_name'] ] = $sub_value;
138 }
139
140 // return
141 return $value;
142 }
143
144
145 /**
146 * This filter is appied to the $value before it is updated in the db
147 *
148 * @type filter
149 * @since ACF 3.6
150 * @date 23/01/13
151 *
152 * @param $value - the value which will be saved in the database
153 * @param $field - the field array holding all the field options
154 * @param $post_id - the post_id of which the value will be saved
155 *
156 * @return $value - the modified value
157 */
158 function update_value( $value, $post_id, $field ) {
159
160 // bail early if no value
161 if ( ! acf_is_array( $value ) ) {
162 return null;
163 }
164
165 // bail early if no sub fields
166 if ( empty( $field['sub_fields'] ) ) {
167 return null;
168 }
169
170 // modify names
171 $field = $this->prepare_field_for_db( $field );
172
173 // loop
174 foreach ( $field['sub_fields'] as $sub_field ) {
175
176 // vars
177 $v = false;
178
179 // key (backend)
180 if ( isset( $value[ $sub_field['key'] ] ) ) {
181 $v = $value[ $sub_field['key'] ];
182
183 // name (frontend)
184 } elseif ( isset( $value[ $sub_field['_name'] ] ) ) {
185 $v = $value[ $sub_field['_name'] ];
186
187 // empty
188 } else {
189
190 // input is not set (hidden by conditioanl logic)
191 continue;
192 }
193
194 // update value
195 acf_update_value( $v, $post_id, $sub_field );
196 }
197
198 // return
199 return '';
200 }
201
202
203 /**
204 * This function will modify sub fields ready for update / load
205 *
206 * @type function
207 * @date 4/11/16
208 * @since ACF 5.5.0
209 *
210 * @param $field (array)
211 * @return $field
212 */
213 function prepare_field_for_db( $field ) {
214
215 // bail early if no sub fields
216 if ( empty( $field['sub_fields'] ) ) {
217 return $field;
218 }
219
220 // loop
221 foreach ( $field['sub_fields'] as &$sub_field ) {
222
223 // prefix name
224 $sub_field['name'] = $field['name'] . '_' . $sub_field['_name'];
225 }
226
227 // return
228 return $field;
229 }
230
231
232 /**
233 * Create the HTML interface for your field
234 *
235 * @param $field - an array holding all the field's data
236 *
237 * @type action
238 * @since ACF 3.6
239 * @date 23/01/13
240 */
241 function render_field( $field ) {
242
243 // bail early if no sub fields
244 if ( empty( $field['sub_fields'] ) ) {
245 return;
246 }
247
248 // load values
249 foreach ( $field['sub_fields'] as &$sub_field ) {
250
251 // add value
252 if ( isset( $field['value'][ $sub_field['key'] ] ) ) {
253
254 // this is a normal value
255 $sub_field['value'] = $field['value'][ $sub_field['key'] ];
256 } elseif ( isset( $sub_field['default_value'] ) ) {
257
258 // no value, but this sub field has a default value
259 $sub_field['value'] = $sub_field['default_value'];
260 }
261
262 // update prefix to allow for nested values
263 $sub_field['prefix'] = $field['name'];
264
265 // restore required
266 if ( $field['required'] ) {
267 $sub_field['required'] = 0;
268 }
269 }
270
271 // render
272 if ( $field['layout'] == 'table' ) {
273 $this->render_field_table( $field );
274 } else {
275 $this->render_field_block( $field );
276 }
277 }
278
279
280 /**
281 * description
282 *
283 * @type function
284 * @date 12/07/2016
285 * @since ACF 5.4.0
286 *
287 * @param $post_id (int)
288 * @return $post_id (int)
289 */
290 function render_field_block( $field ) {
291
292 // vars
293 $label_placement = ( $field['layout'] == 'block' ) ? 'top' : 'left';
294
295 // html
296 echo '<div class="acf-fields -' . esc_attr( $label_placement ) . ' -border">';
297
298 foreach ( $field['sub_fields'] as $sub_field ) {
299 acf_render_field_wrap( $sub_field );
300 }
301
302 echo '</div>';
303 }
304
305
306 /**
307 * description
308 *
309 * @type function
310 * @date 12/07/2016
311 * @since ACF 5.4.0
312 *
313 * @param $post_id (int)
314 * @return $post_id (int)
315 */
316 function render_field_table( $field ) {
317
318 ?>
319 <table class="acf-table">
320 <thead>
321 <tr>
322 <?php
323 foreach ( $field['sub_fields'] as $sub_field ) :
324
325 // prepare field (allow sub fields to be removed)
326 $sub_field = acf_prepare_field( $sub_field );
327
328 // bail early if no field
329 if ( ! $sub_field ) {
330 continue;
331 }
332
333 // vars
334 $atts = array();
335 $atts['class'] = 'acf-th';
336 $atts['data-name'] = $sub_field['_name'];
337 $atts['data-type'] = $sub_field['type'];
338 $atts['data-key'] = $sub_field['key'];
339
340 // Add custom width
341 if ( $sub_field['wrapper']['width'] ) {
342 $atts['data-width'] = $sub_field['wrapper']['width'];
343 $atts['style'] = 'width: ' . $sub_field['wrapper']['width'] . '%;';
344 }
345
346 ?>
347 <th <?php echo acf_esc_attrs( $atts ); ?>>
348 <?php acf_render_field_label( $sub_field ); ?>
349 <?php acf_render_field_instructions( $sub_field ); ?>
350 </th>
351 <?php endforeach; ?>
352 </tr>
353 </thead>
354 <tbody>
355 <tr class="acf-row">
356 <?php
357
358 foreach ( $field['sub_fields'] as $sub_field ) {
359 acf_render_field_wrap( $sub_field, 'td' );
360 }
361
362 ?>
363 </tr>
364 </tbody>
365 </table>
366 <?php
367 }
368
369
370 /**
371 * Create extra options for your field. This is rendered when editing a field.
372 * The value of $field['name'] can be used (like bellow) to save extra data to the $field
373 *
374 * @type action
375 * @since ACF 3.6
376 * @date 23/01/13
377 *
378 * @param $field - an array holding all the field's data
379 */
380 function render_field_settings( $field ) {
381
382 // vars
383 $args = array(
384 'fields' => $field['sub_fields'],
385 'parent' => $field['ID'],
386 'is_subfield' => true,
387 );
388
389 ?>
390 <div class="acf-field acf-field-setting-sub_fields" data-setting="group" data-name="sub_fields">
391 <div class="acf-label">
392 <label><?php esc_html_e( 'Sub Fields', 'secure-custom-fields' ); ?></label>
393 </div>
394 <div class="acf-input acf-input-sub">
395 <?php
396
397 acf_get_view( 'acf-field-group/fields', $args );
398
399 ?>
400 </div>
401 </div>
402 <?php
403
404 // layout
405 acf_render_field_setting(
406 $field,
407 array(
408 'label' => __( 'Layout', 'secure-custom-fields' ),
409 'instructions' => __( 'Specify the style used to render the selected fields', 'secure-custom-fields' ),
410 'type' => 'radio',
411 'name' => 'layout',
412 'layout' => 'horizontal',
413 'choices' => array(
414 'block' => __( 'Block', 'secure-custom-fields' ),
415 'table' => __( 'Table', 'secure-custom-fields' ),
416 'row' => __( 'Row', 'secure-custom-fields' ),
417 ),
418 )
419 );
420 }
421
422
423 /**
424 * description
425 *
426 * @type function
427 * @date 11/02/2014
428 * @since ACF 5.0.0
429 *
430 * @param $post_id (int)
431 * @return $post_id (int)
432 */
433 function validate_value( $valid, $value, $field, $input ) {
434
435 // bail early if no $value
436 if ( empty( $value ) ) {
437 return $valid;
438 }
439
440 // bail early if no sub fields
441 if ( empty( $field['sub_fields'] ) ) {
442 return $valid;
443 }
444
445 // loop
446 foreach ( $field['sub_fields'] as $sub_field ) {
447
448 // get sub field
449 $k = $sub_field['key'];
450
451 // bail early if value not set (conditional logic?)
452 if ( ! isset( $value[ $k ] ) ) {
453 continue;
454 }
455
456 // required
457 if ( $field['required'] ) {
458 $sub_field['required'] = 1;
459 }
460
461 // validate
462 acf_validate_value( $value[ $k ], $sub_field, "{$input}[{$k}]" );
463 }
464
465 // return
466 return $valid;
467 }
468
469
470 /**
471 * This filter is appied to the $field before it is duplicated and saved to the database
472 *
473 * @type filter
474 * @since ACF 3.6
475 * @date 23/01/13
476 *
477 * @param $field - the field array holding all the field options
478 *
479 * @return $field - the modified field
480 */
481 function duplicate_field( $field ) {
482
483 // get sub fields
484 $sub_fields = acf_extract_var( $field, 'sub_fields' );
485
486 // save field to get ID
487 $field = acf_update_field( $field );
488
489 // duplicate sub fields
490 acf_duplicate_fields( $sub_fields, $field['ID'] );
491
492 // return
493 return $field;
494 }
495
496 /**
497 * prepare_field_for_export
498 *
499 * Prepares the field for export.
500 *
501 * @date 11/03/2014
502 * @since ACF 5.0.0
503 *
504 * @param array $field The field settings.
505 * @return array
506 */
507 function prepare_field_for_export( $field ) {
508
509 // Check for sub fields.
510 if ( ! empty( $field['sub_fields'] ) ) {
511 $field['sub_fields'] = acf_prepare_fields_for_export( $field['sub_fields'] );
512 }
513 return $field;
514 }
515
516 /**
517 * prepare_field_for_import
518 *
519 * Returns a flat array of fields containing all sub fields ready for import.
520 *
521 * @date 11/03/2014
522 * @since ACF 5.0.0
523 *
524 * @param array $field The field settings.
525 * @return array
526 */
527 function prepare_field_for_import( $field ) {
528
529 // Check for sub fields.
530 if ( ! empty( $field['sub_fields'] ) ) {
531 $sub_fields = acf_extract_var( $field, 'sub_fields' );
532
533 // Modify sub fields.
534 foreach ( $sub_fields as $i => $sub_field ) {
535 $sub_fields[ $i ]['parent'] = $field['key'];
536 $sub_fields[ $i ]['menu_order'] = $i;
537 }
538
539 // Return array of [field, sub_1, sub_2, ...].
540 return array_merge( array( $field ), $sub_fields );
541 }
542 return $field;
543 }
544
545
546 /**
547 * Called when deleting this field's value.
548 *
549 * @date 1/07/2015
550 * @since ACF 5.2.3
551 *
552 * @param mixed $post_id The post ID being saved
553 * @param string $meta_key The field name as seen by the DB
554 * @param array $field The field settings
555 * @return void
556 */
557 function delete_value( $post_id, $meta_key, $field ) {
558
559 // bail early if no sub fields
560 if ( empty( $field['sub_fields'] ) ) {
561 return null;
562 }
563
564 // modify names
565 $field = $this->prepare_field_for_db( $field );
566
567 // loop
568 foreach ( $field['sub_fields'] as $sub_field ) {
569 acf_delete_value( $post_id, $sub_field );
570 }
571 }
572
573 /**
574 * delete_field
575 *
576 * Called when deleting a field of this type.
577 *
578 * @date 8/11/18
579 * @since ACF 5.8.0
580 *
581 * @param arra $field The field settings.
582 * @return void
583 */
584 function delete_field( $field ) {
585
586 // loop over sub fields and delete them
587 if ( $field['sub_fields'] ) {
588 foreach ( $field['sub_fields'] as $sub_field ) {
589 acf_delete_field( $sub_field['ID'] );
590 }
591 }
592 }
593
594 /**
595 * Return the schema array for the REST API.
596 *
597 * @param array $field
598 * @return array
599 */
600 public function get_rest_schema( array $field ) {
601 $schema = array(
602 'type' => array( 'object', 'null' ),
603 'properties' => array(),
604 'required' => ! empty( $field['required'] ),
605 );
606
607 foreach ( $field['sub_fields'] as $sub_field ) {
608 if ( $sub_field_schema = acf_get_field_rest_schema( $sub_field ) ) {
609 $schema['properties'][ $sub_field['name'] ] = $sub_field_schema;
610 }
611 }
612
613 return $schema;
614 }
615
616 /**
617 * Apply basic formatting to prepare the value for default REST output.
618 *
619 * @param mixed $value
620 * @param integer|string $post_id
621 * @param array $field
622 * @return array|mixed
623 */
624 public function format_value_for_rest( $value, $post_id, array $field ) {
625 if ( empty( $value ) || ! is_array( $value ) || empty( $field['sub_fields'] ) ) {
626 return $value;
627 }
628
629 // Loop through each row and within that, each sub field to process sub fields individually.
630 foreach ( $field['sub_fields'] as $sub_field ) {
631
632 // Extract the sub field 'field_key'=>'value' pair from the $value and format it.
633 $sub_value = acf_extract_var( $value, $sub_field['key'] );
634 $sub_value = acf_format_value_for_rest( $sub_value, $post_id, $sub_field );
635
636 // Add the sub field value back to the $value but mapped to the field name instead
637 // of the key reference.
638 $value[ $sub_field['name'] ] = $sub_value;
639 }
640
641 return $value;
642 }
643 }
644
645
646 // initialize
647 acf_register_field_type( 'acf_field__group' );
648 endif; // class_exists check
649
650 ?>
651