PluginProbe
Advanced Custom Fields (ACF®) / 6.8.1
Advanced Custom Fields (ACF®) v6.8.1
6.8.9 6.8.8 6.8.7 6.8.6 6.8.5 6.8.4 6.8.3 6.8.2 6.8.1 5.8.5 5.8.6 5.8.7 5.8.8 5.8.9 5.9.0 5.9.1 5.9.2 5.9.3 5.9.4 5.9.5 5.9.6 5.9.7 5.9.8 5.9.9 6.0.0 All 230 releases
advanced-custom-fields / includes / api / api-template.php
api-template.php
1,567 lines 41.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package ACF
4 * @author WP Engine
5 *
6 * © 2026 Advanced Custom Fields (ACF®). All rights reserved.
7 * "ACF" is a trademark of WP Engine.
8 * Licensed under the GNU General Public License v2 or later.
9 * https://www.gnu.org/licenses/gpl-2.0.html
10 */
11
12 /**
13 * This function will return a custom field value for a specific field name/key + post_id.
14 * There is a 3rd parameter to turn on/off formating. This means that an image field will not use
15 * its 'return option' to format the value but return only what was saved in the database
16 *
17 * @since 3.6
18 *
19 * @param string $selector The field name or key.
20 * @param mixed $post_id The post_id of which the value is saved against.
21 * @param boolean $format_value Whether or not to format the value as described above.
22 * @param boolean $escape_html If we're formatting the value, make sure it's also HTML safe.
23 *
24 * @return mixed
25 */
26 function get_field( $selector, $post_id = false, $format_value = true, $escape_html = false ) {
27
28 // filter post_id
29 $post_id = acf_get_valid_post_id( $post_id );
30
31 // get field
32 $field = acf_maybe_get_field( $selector, $post_id );
33
34 // create dummy field
35 $dummy_field = false;
36 if ( ! $field ) {
37 $field = acf_get_valid_field(
38 array(
39 'name' => $selector,
40 'key' => '',
41 'type' => '',
42 )
43 );
44
45 // prevent formatting, flag as dummy in case $escape_html is true.
46 $format_value = false;
47 $dummy_field = true;
48 }
49
50 // get value for field
51 $value = acf_get_value( $post_id, $field );
52
53 // escape html is only compatible when formatting the value too
54 if ( ! $dummy_field && ! $format_value && $escape_html ) {
55 _doing_it_wrong( __FUNCTION__, __( 'Returning an escaped HTML value is only possible when format_value is also true. The field value has not been returned for security.', 'acf' ), '6.2.6' ); //phpcs:ignore -- escape not required.
56 return false;
57 }
58
59 // format value
60 if ( $format_value ) {
61 if ( $escape_html ) {
62 // return the escaped HTML version if requested.
63 if ( acf_field_type_supports( $field['type'], 'escaping_html' ) ) {
64 $value = acf_format_value( $value, $post_id, $field, true );
65 } else {
66 $new_value = acf_format_value( $value, $post_id, $field );
67 if ( is_array( $new_value ) ) {
68 $value = map_deep( $new_value, 'acf_esc_html' );
69 } else {
70 $value = acf_esc_html( $new_value );
71 }
72 }
73 } else {
74 // get value for field
75 $value = acf_format_value( $value, $post_id, $field );
76 }
77 }
78
79 // If we've built a dummy text field, we won't format the value, but they may still request it escaped. Use `acf_esc_html`
80 if ( $dummy_field && $escape_html ) {
81 if ( is_array( $value ) ) {
82 $value = map_deep( $value, 'acf_esc_html' );
83 } else {
84 $value = acf_esc_html( $value );
85 }
86 }
87
88 // return
89 return $value;
90 }
91
92 /**
93 * This function is the same as echo get_field(), but will escape the value for safe HTML output regardless of parameters.
94 *
95 * @since 1.0.3
96 *
97 * @param string $selector The field name or key.
98 * @param mixed $post_id The post_id of which the value is saved against.
99 * @param boolean $format_value Enable formatting of value. Default true.
100 *
101 * @return void
102 */
103 function the_field( $selector, $post_id = false, $format_value = true ) {
104 $field = get_field_object( $selector, $post_id, $format_value, true, $format_value );
105 $value = $field ? $field['value'] : get_field( $selector, $post_id, $format_value, $format_value );
106
107 if ( is_array( $value ) ) {
108 $value = implode( ', ', $value );
109 }
110
111 // If we're not a scalar we'd throw an error, so return early for safety.
112 if ( ! is_scalar( $value ) ) {
113 return;
114 }
115
116 // If $format_value is false, we've not been able to apply field level escaping as we're giving the raw DB value. Escape the output with `acf_esc_html`.
117 if ( ! $format_value ) {
118 $value = acf_esc_html( $value );
119 }
120
121 // Get the unescaped value while we're still logging removed_unsafe_html.
122 $unescaped_value = get_field( $selector, $post_id, $format_value, false );
123 if ( is_array( $unescaped_value ) ) {
124 $unescaped_value = implode( ', ', $unescaped_value );
125 }
126
127 if ( ! is_scalar( $unescaped_value ) ) {
128 $unescaped_value = false;
129 }
130
131 $field_type = is_array( $field ) && isset( $field['type'] ) ? $field['type'] : 'text';
132 if ( apply_filters( 'acf/the_field/allow_unsafe_html', false, $selector, $post_id, $field_type, $field ) ) {
133 $value = $unescaped_value;
134 } elseif ( $unescaped_value !== false && (string) $value !== (string) $unescaped_value ) {
135 do_action( 'acf/removed_unsafe_html', __FUNCTION__, $selector, $field, $post_id );
136 }
137
138 echo $value; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escaped by logic above.
139 }
140
141 /**
142 * Logs instances of ACF successfully escaping unsafe HTML.
143 *
144 * @since 6.2.5
145 *
146 * @param string $function The function that resulted in HTML being escaped.
147 * @param string $selector The selector (field key, name, etc.) passed to that function.
148 * @param array $field The field being queried when HTML was escaped.
149 * @param mixed $post_id The post ID the function was called on.
150 * @return void
151 */
152 function _acf_log_escaped_html( $function, $selector, $field, $post_id ) {
153 // If the notice isn't shown, no use in logging the errors.
154 if ( apply_filters( 'acf/admin/prevent_escaped_html_notice', true ) ) {
155 return;
156 }
157
158 // If the notice has been dismissed, don't log further errors.
159 if ( get_option( 'acf_escaped_html_notice_dismissed' ) ) {
160 return;
161 }
162
163 // If the field isn't set, we've output a non-ACF field, so don't log anything.
164 if ( ! is_array( $field ) ) {
165 return;
166 }
167
168 $escaped = _acf_get_escaped_html_log();
169
170 // Only store up to 100 results at a time.
171 if ( count( $escaped ) >= 100 ) {
172 return;
173 }
174
175 // Bail if we already logged an error for this field.
176 if ( isset( $escaped[ $field['key'] ] ) ) {
177 return;
178 }
179
180 $escaped[ $field['key'] ] = array(
181 'selector' => $selector,
182 'function' => $function,
183 'field' => $field['label'],
184 'post_id' => $post_id,
185 );
186
187 _acf_update_escaped_html_log( $escaped );
188 }
189 add_action( 'acf/removed_unsafe_html', '_acf_log_escaped_html', 10, 4 );
190
191 /**
192 * Returns an array of instances where HTML was altered due to escaping in the_field or a shortcode.
193 *
194 * @since 6.2.5
195 *
196 * @return array
197 */
198 function _acf_get_escaped_html_log() {
199 $escaped = get_option( 'acf_escaped_html_log', array() );
200 return is_array( $escaped ) ? $escaped : array();
201 }
202
203 /**
204 * Updates the array of instances where HTML was altered due to escaping in the_field or a shortcode.
205 *
206 * @since 6.2.5
207 *
208 * @param array $escaped The array of instances.
209 * @return boolean True on success, or false on failure.
210 */
211 function _acf_update_escaped_html_log( $escaped = array() ) {
212 return update_option( 'acf_escaped_html_log', (array) $escaped, false );
213 }
214
215 /**
216 * Deletes the array of instances where HTML was altered due to escaping in the_field or a shortcode.
217 * Since 6.2.7, also clears the legacy `acf_will_escape_html_log` option to clean up.
218 *
219 * @since 6.2.5
220 *
221 * @return boolean True on success, or false on failure.
222 */
223 function _acf_delete_escaped_html_log() {
224 delete_option( 'acf_will_escape_html_log' );
225 return delete_option( 'acf_escaped_html_log' );
226 }
227
228 /**
229 * This function will return an array containing all the field data for a given field_name.
230 *
231 * @since 3.6
232 *
233 * @param string $selector The field name or key.
234 * @param mixed $post_id The post_id of which the value is saved against.
235 * @param boolean $format_value Whether to format the field value.
236 * @param boolean $load_value Whether to load the field value.
237 * @param boolean $escape_html Should the field return a HTML safe formatted value if $format_value is true.
238 *
239 * @return array|false $field
240 */
241 function get_field_object( $selector, $post_id = false, $format_value = true, $load_value = true, $escape_html = false ) {
242 // Compatibility with ACF ~4.
243 if ( is_array( $format_value ) && isset( $format_value['format_value'] ) ) {
244 $format_value = $format_value['format_value'];
245 }
246
247 $post_id = acf_get_valid_post_id( $post_id );
248 $field = acf_maybe_get_field( $selector, $post_id );
249
250 if ( ! $field ) {
251 return false;
252 }
253
254 if ( $load_value ) {
255 $field['value'] = acf_get_value( $post_id, $field );
256 }
257
258 // escape html is only compatible when formatting the value too
259 if ( ! $format_value && $escape_html ) {
260 _doing_it_wrong( __FUNCTION__, __( 'Returning an escaped HTML value is only possible when format_value is also true. The field value has not been returned for security.', 'acf' ), '6.2.6' ); //phpcs:ignore -- escape not required.
261 $field['value'] = false;
262 return $field;
263 }
264
265 // format value
266 if ( $load_value && $format_value ) {
267 if ( $escape_html ) {
268 // return the escaped HTML version if requested.
269 if ( acf_field_type_supports( $field['type'], 'escaping_html' ) ) {
270 $field['value'] = acf_format_value( $field['value'], $post_id, $field, true );
271 } else {
272 $new_value = acf_format_value( $field['value'], $post_id, $field );
273 if ( is_array( $new_value ) ) {
274 $field['value'] = map_deep( $new_value, 'acf_esc_html' );
275 } else {
276 $field['value'] = acf_esc_html( $new_value );
277 }
278 }
279 } else {
280 // get value for field
281 $field['value'] = acf_format_value( $field['value'], $post_id, $field );
282 }
283 }
284
285 return $field;
286 }
287
288 /**
289 * This function will return a field for the given selector.
290 * It will also review the field_reference to ensure the correct field is returned which makes it useful for the template API
291 *
292 * @since 5.2.3
293 *
294 * @param $selector (mixed) identifier of field. Can be an ID, key, name or post object
295 * @param $post_id (mixed) the post_id of which the value is saved against
296 * @param $strict (boolean) if true, return a field only when a field key is found.
297 *
298 * @return $field (array)
299 */
300 function acf_maybe_get_field( $selector, $post_id = false, $strict = true ) {
301
302 // init
303 acf_init();
304
305 // Check if field key was given.
306 if ( acf_is_field_key( $selector ) ) {
307 return acf_get_field( $selector );
308 }
309
310 // Lookup field via reference.
311 $post_id = acf_get_valid_post_id( $post_id );
312 $field = acf_get_meta_field( $selector, $post_id );
313 if ( $field ) {
314 return $field;
315 }
316
317 // Lookup field loosely via name.
318 if ( ! $strict ) {
319 return acf_get_field( $selector );
320 }
321
322 // Return no result.
323 return false;
324 }
325
326 /**
327 * This function will attempt to find a sub field
328 *
329 * @since 5.4.0
330 *
331 * @param $post_id (int)
332 * @return $post_id (int)
333 */
334 function acf_maybe_get_sub_field( $selectors, $post_id = false, $strict = true ) {
335
336 // bail early if not enough selectors
337 if ( ! is_array( $selectors ) || count( $selectors ) < 3 ) {
338 return false;
339 }
340
341 // vars
342 $offset = (int) acf_get_setting( 'row_index_offset' );
343 $selector = acf_extract_var( $selectors, 0 );
344 $selectors = array_values( $selectors ); // reset keys
345
346 // attempt get field
347 $field = acf_maybe_get_field( $selector, $post_id, $strict );
348
349 // bail early if no field
350 if ( ! $field ) {
351 return false;
352 }
353
354 // loop
355 for ( $j = 0; $j < count( $selectors ); $j += 2 ) {
356
357 // vars
358 $sub_i = (int) $selectors[ $j ];
359 $sub_s = $selectors[ $j + 1 ];
360 $field_name = $field['name'];
361
362 // find sub field
363 $field = acf_get_sub_field( $sub_s, $field );
364
365 // bail early if no sub field
366 if ( ! $field ) {
367 return false;
368 }
369
370 // add to name
371 $field['name'] = $field_name . '_' . ( $sub_i - $offset ) . '_' . $field['name'];
372 }
373
374 // return
375 return $field;
376 }
377
378 /**
379 * This function will return an array containing all the custom field values for a specific post_id.
380 * The function is not very elegant and wastes a lot of PHP memory / SQL queries if you are not using all the values.
381 *
382 * @since 3.6
383 *
384 * @param mixed $post_id The post_id of which the value is saved against.
385 * @param boolean $format_value Whether or not to format the field value.
386 * @param boolean $escape_html Should the field return a HTML safe formatted value if $format_value is true.
387 *
388 * @return array|false Associative array where field name => field value, or false on failure.
389 */
390 function get_fields( $post_id = false, $format_value = true, $escape_html = false ) {
391
392 // escape html is only compatible when formatting the value too
393 if ( ! $format_value && $escape_html ) {
394 _doing_it_wrong( __FUNCTION__, __( 'Returning escaped HTML values is only possible when format_value is also true. The field values have not been returned for security.', 'acf' ), '6.2.6' ); //phpcs:ignore -- escape not required.
395 return false;
396 }
397
398 // vars
399 $fields = get_field_objects( $post_id, $format_value, true, $escape_html );
400 $meta = array();
401
402 // bail early
403 if ( ! $fields ) {
404 return false;
405 }
406
407 // populate
408 foreach ( $fields as $k => $field ) {
409 $meta[ $k ] = $field['value'];
410 }
411
412 // return
413 return $meta;
414 }
415
416
417 /**
418 * This function will return an array containing all the custom field objects for a specific post_id.
419 * The function is not very elegant and wastes a lot of PHP memory / SQL queries if you are not using all the fields / values.
420 *
421 * @since 3.6
422 *
423 * @param mixed $post_id The post_id of which the value is saved against.
424 * @param boolean $format_value Whether or not to format the field value.
425 * @param boolean $load_value Whether or not to load the field value.
426 * @param boolean $escape_html Should the field return a HTML safe formatted value if $format_value is true.
427 *
428 * @return array|false Associative array where field name => field, or false on failure.
429 */
430 function get_field_objects( $post_id = false, $format_value = true, $load_value = true, $escape_html = false ) {
431
432 // init
433 acf_init();
434
435 // validate post_id
436 $post_id = acf_get_valid_post_id( $post_id );
437
438 // get meta
439 $meta = acf_get_meta( $post_id );
440
441 // bail early if no meta
442 if ( empty( $meta ) ) {
443 return false;
444 }
445
446 // escape html is only compatible when formatting the value too
447 if ( ! $format_value && $escape_html ) {
448 _doing_it_wrong( __FUNCTION__, __( 'Returning escaped HTML values is only possible when format_value is also true. The field values have not been returned for security.', 'acf' ), '6.2.6' ); //phpcs:ignore -- escape not required.
449 }
450
451 // populate vars
452 $fields = array();
453 foreach ( $meta as $key => $value ) {
454
455 // bail if reference key does not exist
456 if ( ! isset( $meta[ "_$key" ] ) || ( ! is_string( $meta[ "_$key" ] ) && ! is_numeric( $meta[ "_$key" ] ) ) ) {
457 continue;
458 }
459
460 // get field
461 $field = acf_get_field( $meta[ "_$key" ] );
462
463 // bail early if no field, or if the field's name is different to $key
464 // - solves problem where sub fields (and clone fields) are incorrectly allowed
465 if ( ! $field || $field['name'] !== $key ) {
466 continue;
467 }
468
469 // load value
470 if ( $load_value ) {
471 $field['value'] = acf_get_value( $post_id, $field );
472 }
473
474 // avoid returning field values when the function is called incorrectly.
475 if ( ! $format_value && $escape_html ) {
476 $field['value'] = false;
477 }
478
479 // format value
480 if ( $load_value && $format_value ) {
481 if ( $escape_html ) {
482 // return the escaped HTML version if requested.
483 if ( acf_field_type_supports( $field['type'], 'escaping_html' ) ) {
484 $field['value'] = acf_format_value( $field['value'], $post_id, $field, true );
485 } else {
486 $new_value = acf_format_value( $field['value'], $post_id, $field );
487 if ( is_array( $new_value ) ) {
488 $field['value'] = map_deep( $new_value, 'acf_esc_html' );
489 } else {
490 $field['value'] = acf_esc_html( $new_value );
491 }
492 }
493 } else {
494 // get value for field
495 $field['value'] = acf_format_value( $field['value'], $post_id, $field );
496 }
497 }
498
499 // append to $value
500 $fields[ $key ] = $field;
501 }
502
503 // no value
504 if ( empty( $fields ) ) {
505 return false;
506 }
507
508 // return
509 return $fields;
510 }
511
512
513 /**
514 * Checks if a field (such as Repeater or Flexible Content) has any rows of data to loop over.
515 * This function is intended to be used in conjunction with the_row() to step through available values.
516 *
517 * @since 4.3.0
518 *
519 * @param string $selector The field name or field key.
520 * @param mixed $post_id The post ID where the value is saved. Defaults to the current post.
521 * @return boolean
522 */
523 function have_rows( $selector, $post_id = false ) {
524
525 // Validate and backup $post_id.
526 $_post_id = $post_id;
527 $post_id = acf_get_valid_post_id( $post_id );
528
529 // Vars.
530 $key = "selector={$selector}/post_id={$post_id}";
531 $active_loop = acf_get_loop( 'active' );
532 $prev_loop = acf_get_loop( 'previous' );
533 $new_loop = false;
534 $sub_field = false;
535
536 // Check if no active loop.
537 if ( ! $active_loop ) {
538 $new_loop = 'parent';
539
540 // Detect "change" compared to the active loop.
541 } elseif ( $key !== $active_loop['key'] ) {
542
543 // Find sub field and check if a sub value exists.
544 $sub_field_exists = false;
545 $sub_field = acf_get_sub_field( $selector, $active_loop['field'] );
546 if ( $sub_field ) {
547 $sub_field_exists = isset( $active_loop['value'][ $active_loop['i'] ][ $sub_field['key'] ] );
548 }
549
550 // Detect change in post_id.
551 if ( $post_id != $active_loop['post_id'] ) {
552
553 // Case: Change in $post_id was due to this being a nested loop and not specifying the $post_id.
554 // Action: Move down one level into a new loop.
555 if ( empty( $_post_id ) && $sub_field_exists ) {
556 $new_loop = 'child';
557
558 // Case: Change in $post_id was due to a nested loop ending.
559 // Action: move up one level through the loops.
560 } elseif ( $prev_loop && $prev_loop['post_id'] == $post_id ) {
561 acf_remove_loop( 'active' );
562 $active_loop = $prev_loop;
563
564 // Case: Chang in $post_id is the most obvious, used in an WP_Query loop with multiple $post objects.
565 // Action: leave this current loop alone and create a new parent loop.
566 } else {
567 $new_loop = 'parent';
568 }
569
570 // Detect change in selector.
571 } elseif ( $selector != $active_loop['selector'] ) {
572
573 // Case: Change in $field_name was due to this being a nested loop.
574 // Action: move down one level into a new loop.
575 if ( $sub_field_exists ) {
576 $new_loop = 'child';
577
578 // Case: Change in $field_name was due to a nested loop ending.
579 // Action: move up one level through the loops.
580 } elseif ( $prev_loop && $prev_loop['selector'] == $selector && $prev_loop['post_id'] == $post_id ) {
581 acf_remove_loop( 'active' );
582 $active_loop = $prev_loop;
583
584 // Case: Change in $field_name is the most obvious, this is a new loop for a different field within the $post.
585 // Action: leave this current loop alone and create a new parent loop.
586 } else {
587 $new_loop = 'parent';
588 }
589 }
590 }
591
592 // Add loop if required.
593 if ( $new_loop ) {
594 $args = array(
595 'key' => $key,
596 'selector' => $selector,
597 'post_id' => $post_id,
598 'name' => null,
599 'value' => null,
600 'field' => null,
601 'i' => -1,
602 );
603
604 // Case: Parent loop.
605 if ( $new_loop === 'parent' ) {
606 $field = get_field_object( $selector, $post_id, false );
607 if ( $field ) {
608 $args['field'] = $field;
609 $args['value'] = $field['value'];
610 $args['name'] = $field['name'];
611 unset( $args['field']['value'] );
612 }
613
614 // Case: Child loop ($sub_field must exist).
615 } else {
616 $args['field'] = $sub_field;
617 $args['value'] = $active_loop['value'][ $active_loop['i'] ][ $sub_field['key'] ];
618 $args['name'] = "{$active_loop['name']}_{$active_loop['i']}_{$sub_field['name']}";
619 $args['post_id'] = $active_loop['post_id'];
620 }
621
622 // Bail early if value is either empty or a non array.
623 if ( ! $args['value'] || ! is_array( $args['value'] ) ) {
624 return false;
625 }
626
627 // Allow for non repeatable data for Group and Clone fields.
628 if ( acf_get_field_type_prop( $args['field']['type'], 'have_rows' ) === 'single' ) {
629 $args['value'] = array( $args['value'] );
630 }
631
632 // Add loop.
633 $active_loop = acf_add_loop( $args );
634 }
635
636 // Return true if next row exists.
637 if ( $active_loop && isset( $active_loop['value'][ (int) $active_loop['i'] + 1 ] ) ) {
638 return true;
639 }
640
641 // Return false if no next row.
642 acf_remove_loop( 'active' );
643 return false;
644 }
645
646
647 /**
648 * This function will progress the global repeater or flexible content value 1 row
649 *
650 * @since 4.3.0
651 *
652 * @param N/A
653 * @return (array) the current row data
654 */
655 function the_row( $format = false ) {
656
657 // vars
658 $i = acf_get_loop( 'active', 'i' );
659
660 // increase
661 ++$i;
662
663 // update
664 acf_update_loop( 'active', 'i', $i );
665
666 // return
667 return get_row( $format );
668 }
669
670 function get_row( $format = false ) {
671
672 // vars
673 $loop = acf_get_loop( 'active' );
674
675 // bail early if no loop
676 if ( ! $loop ) {
677 return false;
678 }
679
680 // get value
681 $value = acf_maybe_get( $loop['value'], $loop['i'] );
682
683 // bail early if no current value
684 // possible if get_row_layout() is called before the_row()
685 if ( ! $value ) {
686 return false;
687 }
688
689 // format
690 if ( $format ) {
691
692 // vars
693 $field = $loop['field'];
694
695 // single row
696 if ( acf_get_field_type_prop( $field['type'], 'have_rows' ) === 'single' ) {
697
698 // format value
699 $value = acf_format_value( $value, $loop['post_id'], $field );
700
701 // multiple rows
702 } else {
703
704 // format entire value
705 // - solves problem where cached value is incomplete
706 // - no performance issues here thanks to cache
707 $value = acf_format_value( $loop['value'], $loop['post_id'], $field );
708 $value = acf_maybe_get( $value, $loop['i'] );
709 }
710 }
711
712 // return
713 return $value;
714 }
715
716 function get_row_index() {
717
718 // vars
719 $i = (int) acf_get_loop( 'active', 'i' );
720 $offset = (int) acf_get_setting( 'row_index_offset' );
721
722 // return
723 return $offset + $i;
724 }
725
726 function the_row_index() {
727 echo intval( get_row_index() );
728 }
729
730
731 /**
732 * This function is used inside a 'has_sub_field' while loop to return a sub field object
733 *
734 * @since 5.3.8
735 *
736 * @param $selector (string)
737 * @return (array)
738 */
739 function get_row_sub_field( $selector ) {
740
741 // vars
742 $row = acf_get_loop( 'active' );
743
744 // bail early if no row
745 if ( ! $row ) {
746 return false;
747 }
748
749 // attempt to find sub field
750 $sub_field = acf_get_sub_field( $selector, $row['field'] );
751
752 // bail early if no field
753 if ( ! $sub_field ) {
754 return false;
755 }
756
757 // update field's name based on row data
758 $sub_field['name'] = "{$row['name']}_{$row['i']}_{$sub_field['name']}";
759
760 // return
761 return $sub_field;
762 }
763
764
765 /**
766 * This function is used inside a 'has_sub_field' while loop to return a sub field value
767 *
768 * @since 5.3.8
769 *
770 * @param $selector (string)
771 * @return (mixed)
772 */
773 function get_row_sub_value( $selector ) {
774
775 // vars
776 $row = acf_get_loop( 'active' );
777
778 // bail early if no row
779 if ( ! $row ) {
780 return null;
781 }
782
783 // return value
784 if ( isset( $row['value'][ $row['i'] ][ $selector ] ) ) {
785 return $row['value'][ $row['i'] ][ $selector ];
786 }
787
788 // return
789 return null;
790 }
791
792
793 /**
794 * This function will find the current loop and unset it from the global array.
795 * To be used when loop finishes or a break is used
796 *
797 * @since 5.0.0
798 *
799 * @param $hard_reset (boolean) completely wipe the global variable, or just unset the active row
800 * @return (boolean)
801 */
802 function reset_rows() {
803
804 // remove last loop
805 acf_remove_loop( 'active' );
806
807 // return
808 return true;
809 }
810
811
812 /**
813 * This function is used inside a while loop to return either true or false (loop again or stop).
814 * When using a repeater or flexible content field, it will loop through the rows until
815 * there are none left or a break is detected
816 *
817 * @since 1.0.3
818 *
819 * @param $field_name (string) the field name
820 * @param $post_id (mixed) the post_id of which the value is saved against
821 * @return (boolean)
822 */
823 function has_sub_field( $field_name, $post_id = false ) {
824
825 // vars
826 $r = have_rows( $field_name, $post_id );
827
828 // if has rows, progress through 1 row for the while loop to work
829 if ( $r ) {
830 the_row();
831 }
832
833 // return
834 return $r;
835 }
836
837 /**
838 * Alias of has_sub_field
839 */
840 function has_sub_fields( $field_name, $post_id = false ) {
841 return has_sub_field( $field_name, $post_id );
842 }
843
844
845 /**
846 * This function is used inside a 'has_sub_field' while loop to return a sub field value
847 *
848 * @since 1.0.3
849 *
850 * @param string $selector The field name or key.
851 * @param boolean $format_value Whether or not to format the value as described above.
852 * @param boolean $escape_html If we're formatting the value, make sure it's also HTML safe.
853 *
854 * @return mixed
855 */
856 function get_sub_field( $selector = '', $format_value = true, $escape_html = false ) {
857
858 // get sub field
859 $sub_field = get_sub_field_object( $selector, $format_value, true, $escape_html );
860
861 // bail early if no sub field
862 if ( ! $sub_field ) {
863 return false;
864 }
865
866 // return
867 return $sub_field['value'];
868 }
869
870
871 /**
872 * This function is the same as echo get_sub_field(), but will escape the value for safe HTML output.
873 *
874 * @since 1.0.3
875 *
876 * @param string $field_name The field name.
877 * @param boolean $format_value Enable formatting of value. When false, the field value will be escaped at this level with `acf_esc_html`. Default true.
878 *
879 * @return void
880 */
881 function the_sub_field( $field_name, $format_value = true ) {
882 $field = get_sub_field_object( $field_name, $format_value, true, $format_value );
883 $value = ( is_array( $field ) && isset( $field['value'] ) ) ? $field['value'] : false;
884
885 if ( is_array( $value ) ) {
886 $value = implode( ', ', $value );
887 }
888
889 // If we're not a scalar we'd throw an error, so return early for safety.
890 if ( ! is_scalar( $value ) ) {
891 return;
892 }
893
894 // If $format_value is false, we've not been able to apply field level escaping as we're giving the raw DB value. Escape the output with `acf_esc_html`.
895 if ( ! $format_value ) {
896 $value = acf_esc_html( $value );
897 }
898
899 $unescaped_field = get_sub_field_object( $field_name, $format_value, true, false );
900 $unescaped_value = ( is_array( $unescaped_field ) && isset( $unescaped_field['value'] ) ) ? $unescaped_field['value'] : false;
901 if ( is_array( $unescaped_value ) ) {
902 $unescaped_value = implode( ', ', $unescaped_value );
903 }
904
905 if ( ! is_scalar( $unescaped_value ) ) {
906 $unescaped_value = false;
907 }
908
909 $field_type = is_array( $field ) && isset( $field['type'] ) ? $field['type'] : 'text';
910 if ( apply_filters( 'acf/the_field/allow_unsafe_html', false, $field_name, 'sub_field', $field_type, $field ) ) {
911 $value = $unescaped_value;
912 } elseif ( $unescaped_value !== false && (string) $value !== (string) $unescaped_value ) {
913 do_action( 'acf/removed_unsafe_html', __FUNCTION__, $field_name, $field, false );
914 }
915
916 echo $value; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escaped inside get_sub_field_object where necessary.
917 }
918
919
920 /**
921 * This function is used inside a 'has_sub_field' while loop to return a sub field object
922 *
923 * @since 3.5.8.1
924 *
925 * @param string $selector The field name or key.
926 * @param boolean $format_value Whether to format the field value.
927 * @param boolean $load_value Whether to load the field value.
928 * @param boolean $escape_html Should the field return a HTML safe formatted value.
929 *
930 * @return mixed
931 */
932 function get_sub_field_object( $selector, $format_value = true, $load_value = true, $escape_html = false ) {
933
934 $row = acf_get_loop( 'active' );
935
936 // bail early if no row
937 if ( ! $row ) {
938 return false;
939 }
940
941 // attempt to find sub field
942 $sub_field = get_row_sub_field( $selector );
943
944 // bail early if no sub field
945 if ( ! $sub_field ) {
946 return false;
947 }
948
949 // load value
950 if ( $load_value ) {
951 $sub_field['value'] = get_row_sub_value( $sub_field['key'] );
952 }
953
954 // escape html is only compatible when formatting the value too
955 if ( ! $format_value && $escape_html ) {
956 _doing_it_wrong( __FUNCTION__, __( 'Returning an escaped HTML value is only possible when format_value is also true. The field value has not been returned for security.', 'acf' ), '6.2.6' ); //phpcs:ignore -- escape not required.
957 $sub_field['value'] = false;
958 }
959
960 // format value
961 if ( $load_value && $format_value ) {
962 if ( $escape_html ) {
963 // return the escaped HTML version if requested.
964 if ( acf_field_type_supports( $sub_field['type'], 'escaping_html' ) ) {
965 $sub_field['value'] = acf_format_value( $sub_field['value'], $row['post_id'], $sub_field, true );
966 } else {
967 $new_value = acf_format_value( $sub_field['value'], $row['post_id'], $sub_field );
968 if ( is_array( $new_value ) ) {
969 $sub_field['value'] = map_deep( $new_value, 'acf_esc_html' );
970 } else {
971 $sub_field['value'] = acf_esc_html( $new_value );
972 }
973 }
974 } else {
975 // get value for field
976 $sub_field['value'] = acf_format_value( $sub_field['value'], $row['post_id'], $sub_field );
977 }
978 }
979
980 // return
981 return $sub_field;
982 }
983
984
985 /**
986 * This function will return a string representation of the current row layout within a 'have_rows' loop
987 *
988 * @since 3.0.6
989 *
990 * @return mixed
991 */
992 function get_row_layout() {
993
994 // vars
995 $row = get_row();
996
997 // return
998 if ( isset( $row['acf_fc_layout'] ) ) {
999 return $row['acf_fc_layout'];
1000 }
1001
1002 // return
1003 return false;
1004 }
1005
1006 /**
1007 * This function is used to add basic shortcode support for the ACF plugin
1008 * eg. [acf field="heading" post_id="123" format_value="1"]
1009 *
1010 * @since 1.1.1
1011 *
1012 * @param array $atts The shortcode attributes.
1013 *
1014 * @return string|void
1015 */
1016 function acf_shortcode( $atts ) {
1017 // Return if the ACF shortcode is disabled.
1018 if ( ! acf_get_setting( 'enable_shortcode' ) ) {
1019 if ( is_preview() ) {
1020 return apply_filters( 'acf/shortcode/disabled_message', esc_html__( '[The ACF shortcode is disabled on this site]', 'acf' ) );
1021 } else {
1022 return;
1023 }
1024 }
1025
1026 if ( function_exists( 'wp_is_block_theme' ) && wp_is_block_theme() ) {
1027 // Prevent the ACF shortcode in FSE block template parts by default.
1028 if ( ! doing_filter( 'the_content' ) && ! apply_filters( 'acf/shortcode/allow_in_block_themes_outside_content', false ) ) {
1029 return;
1030 }
1031 }
1032
1033 // Limit previews of ACF shortcode data for users without publish_posts permissions.
1034 $preview_capability = apply_filters( 'acf/shortcode/preview_capability', 'publish_posts' );
1035 if ( is_preview() && ! current_user_can( $preview_capability ) ) {
1036 return apply_filters( 'acf/shortcode/preview_capability_message', esc_html__( '[ACF shortcode value disabled for preview]', 'acf' ) );
1037 }
1038
1039 // Mitigate issue where some AJAX requests can return ACF field data.
1040 $ajax_capability = apply_filters( 'acf/ajax/shortcode_capability', 'edit_posts' );
1041 if ( wp_doing_ajax() && ( $ajax_capability !== false ) && ! current_user_can( $ajax_capability ) ) {
1042 return;
1043 }
1044
1045 $atts = shortcode_atts(
1046 array(
1047 'field' => '',
1048 'post_id' => false,
1049 'format_value' => true,
1050 ),
1051 $atts,
1052 'acf'
1053 );
1054
1055 // Decode the post ID for filtering.
1056 $post_id = acf_get_valid_post_id( $atts['post_id'] );
1057 $decoded_post_id = acf_decode_post_id( $post_id );
1058
1059 // If we've decoded to a post, ensure the post is publicly visible.
1060 if ( $decoded_post_id['type'] === 'post' ) {
1061 if ( $atts['post_id'] !== false && ( (int) $atts['post_id'] !== (int) acf_get_valid_post_id() ) && ( ! is_post_publicly_viewable( $decoded_post_id['id'] ) ) && apply_filters( 'acf/shortcode/prevent_access_to_fields_on_non_public_posts', true ) ) {
1062 if ( is_preview() ) {
1063 return apply_filters( 'acf/shortcode/post_not_public_message', esc_html__( '[The ACF shortcode cannot display fields from non-public posts]', 'acf' ) );
1064 } else {
1065 return;
1066 }
1067 }
1068 }
1069
1070 $access_already_prevented = apply_filters( 'acf/prevent_access_to_unknown_fields', false );
1071 $filter_applied = false;
1072
1073 if ( ! $access_already_prevented ) {
1074 $filter_applied = true;
1075 add_filter( 'acf/prevent_access_to_unknown_fields', '__return_true' );
1076 }
1077
1078 // Try to get the field value, ensuring any non-safe HTML is stripped from wysiwyg fields via `acf_the_content`
1079 $field = get_field_object( $atts['field'], $post_id, $atts['format_value'], true, true );
1080 $value = $field ? $field['value'] : get_field( $atts['field'], $post_id, $atts['format_value'], true );
1081
1082 $field_type = is_array( $field ) && isset( $field['type'] ) ? $field['type'] : 'text';
1083
1084 if ( ! acf_field_type_supports( $field_type, 'bindings', true ) ) {
1085 if ( is_preview() ) {
1086 return apply_filters( 'acf/shortcode/field_not_supported_message', '[' . esc_html__( 'The requested ACF field type does not support output in bindings or the ACF Shortcode.', 'acf' ) . ']' );
1087 } else {
1088 return;
1089 }
1090 }
1091
1092 if ( isset( $field['allow_in_bindings'] ) && ! $field['allow_in_bindings'] ) {
1093 if ( is_preview() ) {
1094 return apply_filters( 'acf/shortcode/field_not_allowed_message', '[' . esc_html__( 'The requested ACF field is not allowed to be output in bindings or the ACF Shortcode.', 'acf' ) . ']' );
1095 } else {
1096 return;
1097 }
1098 }
1099
1100 if ( apply_filters( 'acf/shortcode/prevent_access', false, $atts, $decoded_post_id['id'], $decoded_post_id['type'], $field_type, $field ) ) {
1101 return;
1102 }
1103
1104 if ( is_array( $value ) ) {
1105 $value = implode( ', ', $value );
1106 }
1107
1108 // Temporarily always get the unescaped version for action comparison.
1109 $unescaped_value = get_field( $atts['field'], $post_id, $atts['format_value'], false );
1110
1111 // Remove the filter preventing access to unknown filters now we've got all the values.
1112 if ( $filter_applied ) {
1113 remove_filter( 'acf/prevent_access_to_unknown_fields', '__return_true' );
1114 }
1115
1116 if ( is_array( $unescaped_value ) ) {
1117 $unescaped_value = implode( ', ', $unescaped_value );
1118 }
1119
1120 if ( ! is_scalar( $unescaped_value ) ) {
1121 $unescaped_value = false;
1122 }
1123
1124 // Handle getting the unescaped version if we're allowed unsafe html.
1125 if ( apply_filters( 'acf/shortcode/allow_unsafe_html', false, $atts, $field_type, $field ) ) {
1126 $value = $unescaped_value;
1127 } elseif ( $unescaped_value !== false && (string) $value !== (string) $unescaped_value ) {
1128 do_action( 'acf/removed_unsafe_html', __FUNCTION__, $atts['field'], $field, $post_id );
1129 }
1130
1131 return $value;
1132 }
1133 add_shortcode( 'acf', 'acf_shortcode' );
1134
1135
1136 /**
1137 * This function will update a value in the database
1138 *
1139 * @since 3.1.9
1140 *
1141 * @param string $selector The field name or key.
1142 * @param mixed $value The value to save in the database.
1143 * @param mixed $post_id The post_id of which the value is saved against.
1144 *
1145 * @return boolean
1146 */
1147 function update_field( $selector, $value, $post_id = false ) {
1148
1149 // filter post_id
1150 $post_id = acf_get_valid_post_id( $post_id );
1151
1152 // get field
1153 $field = acf_maybe_get_field( $selector, $post_id, false );
1154
1155 // create dummy field
1156 if ( ! $field ) {
1157 $field = acf_get_valid_field(
1158 array(
1159 'name' => $selector,
1160 'key' => '',
1161 'type' => '',
1162 )
1163 );
1164 }
1165
1166 // save
1167 return acf_update_value( $value, $post_id, $field );
1168 }
1169
1170
1171 /**
1172 * This function will update a value of a sub field in the database
1173 *
1174 * @since 5.0.0
1175 *
1176 * @param $selector (mixed) the sub field name or key, or an array of ancestors
1177 * @param $value (mixed) the value to save in the database
1178 * @param $post_id (mixed) the post_id of which the value is saved against
1179 *
1180 * @return boolean
1181 */
1182 function update_sub_field( $selector, $value, $post_id = false ) {
1183
1184 // vars
1185 $sub_field = false;
1186
1187 // get sub field
1188 if ( is_array( $selector ) ) {
1189 $post_id = acf_get_valid_post_id( $post_id );
1190 $sub_field = acf_maybe_get_sub_field( $selector, $post_id, false );
1191 } else {
1192 $post_id = acf_get_loop( 'active', 'post_id' );
1193 $sub_field = get_row_sub_field( $selector );
1194 }
1195
1196 // bail early if no sub field
1197 if ( ! $sub_field ) {
1198 return false;
1199 }
1200
1201 // update
1202 return acf_update_value( $value, $post_id, $sub_field );
1203 }
1204
1205
1206 /**
1207 * This function will remove a value from the database
1208 *
1209 * @since 3.1.9
1210 *
1211 * @param $selector (string) the field name or key
1212 * @param $post_id (mixed) the post_id of which the value is saved against
1213 *
1214 * @return boolean
1215 */
1216 function delete_field( $selector, $post_id = false ) {
1217
1218 // filter post_id
1219 $post_id = acf_get_valid_post_id( $post_id );
1220
1221 // get field
1222 $field = acf_maybe_get_field( $selector, $post_id );
1223
1224 // delete
1225 return $field ? acf_delete_value( $post_id, $field ) : false;
1226 }
1227
1228
1229 /**
1230 * This function will delete a value of a sub field in the database
1231 *
1232 * @since 5.0.0
1233 *
1234 * @param $selector (mixed) the sub field name or key, or an array of ancestors
1235 * @param $value (mixed) the value to save in the database
1236 * @param $post_id (mixed) the post_id of which the value is saved against
1237 * @return (boolean)
1238 */
1239 function delete_sub_field( $selector, $post_id = false ) {
1240 return update_sub_field( $selector, null, $post_id );
1241 }
1242
1243
1244 /**
1245 * This function will add a row of data to a field
1246 *
1247 * @since 5.2.3
1248 *
1249 * @param $selector (string)
1250 * @param $row (array)
1251 * @param $post_id (mixed)
1252 * @return (boolean)
1253 */
1254 function add_row( $selector, $row = false, $post_id = false ) {
1255
1256 // filter post_id
1257 $post_id = acf_get_valid_post_id( $post_id );
1258
1259 // get field
1260 $field = acf_maybe_get_field( $selector, $post_id, false );
1261
1262 // bail early if no field
1263 if ( ! $field ) {
1264 return false;
1265 }
1266
1267 // get raw value
1268 $value = acf_get_value( $post_id, $field );
1269
1270 // ensure array
1271 $value = acf_get_array( $value );
1272
1273 // append
1274 $value[] = $row;
1275
1276 // Paginated repeaters should be saved normally.
1277 $field['pagination'] = false;
1278
1279 // update value
1280 acf_update_value( $value, $post_id, $field );
1281
1282 // return
1283 return count( $value );
1284 }
1285
1286
1287 /**
1288 * This function will add a row of data to a field
1289 *
1290 * @since 5.2.3
1291 *
1292 * @param $selector (string)
1293 * @param $row (array)
1294 * @param $post_id (mixed)
1295 * @return (boolean)
1296 */
1297 function add_sub_row( $selector, $row = false, $post_id = false ) {
1298
1299 // vars
1300 $sub_field = false;
1301
1302 // get sub field
1303 if ( is_array( $selector ) ) {
1304 $post_id = acf_get_valid_post_id( $post_id );
1305 $sub_field = acf_maybe_get_sub_field( $selector, $post_id, false );
1306 } else {
1307 $post_id = acf_get_loop( 'active', 'post_id' );
1308 $sub_field = get_row_sub_field( $selector );
1309 }
1310
1311 // bail early if no sub field
1312 if ( ! $sub_field ) {
1313 return false;
1314 }
1315
1316 // get raw value
1317 $value = acf_get_value( $post_id, $sub_field );
1318
1319 // ensure array
1320 $value = acf_get_array( $value );
1321
1322 // append
1323 $value[] = $row;
1324
1325 // update
1326 acf_update_value( $value, $post_id, $sub_field );
1327
1328 // return
1329 return count( $value );
1330 }
1331
1332
1333 /**
1334 * This function will update a row of data to a field
1335 *
1336 * @since 5.2.3
1337 *
1338 * @param $selector (string)
1339 * @param $i (int)
1340 * @param $row (array)
1341 * @param $post_id (mixed)
1342 * @return (boolean)
1343 */
1344 function update_row( $selector, $i = 1, $row = false, $post_id = false ) {
1345
1346 // vars
1347 $offset = (int) acf_get_setting( 'row_index_offset' );
1348 $i = (int) $i - $offset;
1349
1350 // filter post_id
1351 $post_id = acf_get_valid_post_id( $post_id );
1352
1353 // get field
1354 $field = acf_maybe_get_field( $selector, $post_id, false );
1355
1356 // bail early if no field
1357 if ( ! $field ) {
1358 return false;
1359 }
1360
1361 // get raw value
1362 $value = acf_get_value( $post_id, $field );
1363
1364 // ensure array
1365 $value = acf_get_array( $value );
1366
1367 // update
1368 $value[ $i ] = $row;
1369
1370 // update value
1371 acf_update_value( $value, $post_id, $field );
1372
1373 // return
1374 return true;
1375 }
1376
1377
1378 /**
1379 * This function will add a row of data to a field
1380 *
1381 * @since 5.2.3
1382 *
1383 * @param $selector (string)
1384 * @param $row (array)
1385 * @param $post_id (mixed)
1386 * @return (boolean)
1387 */
1388 function update_sub_row( $selector, $i = 1, $row = false, $post_id = false ) {
1389
1390 // vars
1391 $sub_field = false;
1392 $offset = (int) acf_get_setting( 'row_index_offset' );
1393 $i = (int) $i - $offset;
1394
1395 // get sub field
1396 if ( is_array( $selector ) ) {
1397 $post_id = acf_get_valid_post_id( $post_id );
1398 $sub_field = acf_maybe_get_sub_field( $selector, $post_id, false );
1399 } else {
1400 $post_id = acf_get_loop( 'active', 'post_id' );
1401 $sub_field = get_row_sub_field( $selector );
1402 }
1403
1404 // bail early if no sub field
1405 if ( ! $sub_field ) {
1406 return false;
1407 }
1408
1409 // get raw value
1410 $value = acf_get_value( $post_id, $sub_field );
1411
1412 // ensure array
1413 $value = acf_get_array( $value );
1414
1415 // append
1416 $value[ $i ] = $row;
1417
1418 // update
1419 acf_update_value( $value, $post_id, $sub_field );
1420
1421 // return
1422 return true;
1423 }
1424
1425
1426 /**
1427 * This function will delete a row of data from a field
1428 *
1429 * @since 5.2.3
1430 *
1431 * @param $selector (string)
1432 * @param $i (int)
1433 * @param $post_id (mixed)
1434 * @return (boolean)
1435 */
1436 function delete_row( $selector, $i = 1, $post_id = false ) {
1437
1438 // vars
1439 $offset = (int) acf_get_setting( 'row_index_offset' );
1440 $i = (int) $i - $offset;
1441
1442 // filter post_id
1443 $post_id = acf_get_valid_post_id( $post_id );
1444
1445 // get field
1446 $field = acf_maybe_get_field( $selector, $post_id );
1447
1448 // bail early if no field
1449 if ( ! $field ) {
1450 return false;
1451 }
1452
1453 // get value
1454 $value = acf_get_value( $post_id, $field );
1455
1456 // ensure array
1457 $value = acf_get_array( $value );
1458
1459 // bail early if index doesn't exist
1460 if ( ! isset( $value[ $i ] ) ) {
1461 return false;
1462 }
1463
1464 // unset
1465 unset( $value[ $i ] );
1466
1467 // update
1468 acf_update_value( $value, $post_id, $field );
1469
1470 // return
1471 return true;
1472 }
1473
1474
1475 /**
1476 * This function will add a row of data to a field
1477 *
1478 * @since 5.2.3
1479 *
1480 * @param $selector (string)
1481 * @param $row (array)
1482 * @param $post_id (mixed)
1483 * @return (boolean)
1484 */
1485 function delete_sub_row( $selector, $i = 1, $post_id = false ) {
1486
1487 // vars
1488 $sub_field = false;
1489 $offset = (int) acf_get_setting( 'row_index_offset' );
1490 $i = (int) $i - $offset;
1491
1492 // get sub field
1493 if ( is_array( $selector ) ) {
1494 $post_id = acf_get_valid_post_id( $post_id );
1495 $sub_field = acf_maybe_get_sub_field( $selector, $post_id, false );
1496 } else {
1497 $post_id = acf_get_loop( 'active', 'post_id' );
1498 $sub_field = get_row_sub_field( $selector );
1499 }
1500
1501 // bail early if no sub field
1502 if ( ! $sub_field ) {
1503 return false;
1504 }
1505
1506 // get raw value
1507 $value = acf_get_value( $post_id, $sub_field );
1508
1509 // ensure array
1510 $value = acf_get_array( $value );
1511
1512 // bail early if index doesn't exist
1513 if ( ! isset( $value[ $i ] ) ) {
1514 return false;
1515 }
1516
1517 // append
1518 unset( $value[ $i ] );
1519
1520 // update
1521 acf_update_value( $value, $post_id, $sub_field );
1522
1523 // return
1524 return true;
1525 }
1526
1527
1528 /**
1529 * Depreceated Functions
1530 *
1531 * These functions are outdated
1532 *
1533 * @since 1.0.0
1534 *
1535 * @param n/a
1536 * @return n/a
1537 */
1538 function create_field( $field ) {
1539
1540 acf_render_field( $field );
1541 }
1542
1543 function render_field( $field ) {
1544
1545 acf_render_field( $field );
1546 }
1547
1548 function reset_the_repeater_field() {
1549
1550 return reset_rows();
1551 }
1552
1553 function the_repeater_field( $field_name, $post_id = false ) {
1554
1555 return has_sub_field( $field_name, $post_id );
1556 }
1557
1558 function the_flexible_field( $field_name, $post_id = false ) {
1559
1560 return has_sub_field( $field_name, $post_id );
1561 }
1562
1563 function acf_filter_post_id( $post_id ) {
1564
1565 return acf_get_valid_post_id( $post_id );
1566 }
1567