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