PluginProbe ʕ •ᴥ•ʔ
Advanced Custom Fields (ACF®) / 6.8.8
Advanced Custom Fields (ACF®) v6.8.8
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 6.0.1 6.0.2 6.0.3 6.0.4 6.0.5 6.0.6 6.0.7 6.1.0 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 6.1.6 6.1.7 6.1.8 6.2.0 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.2.6 6.2.6.1 6.2.7 6.2.8 6.2.9 6.3.0 6.3.1 6.3.10.2 6.3.11 6.3.12 6.3.2 6.3.3 6.3.4 6.3.5 6.3.6 6.3.6.1 6.4.0 6.4.0.1 6.4.1 6.4.2 6.4.3 6.5.0 6.5.1 6.6.0 6.6.1 6.6.2 6.7.0 6.7.1 6.7.2 6.8.0 trunk 1.0.0 1.0.2 1.0.3 1.0.5 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.1.1 2.1.3 2.1.4 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.0.6 3.0.7 3.1.0 3.1.1 3.1.2 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.1.8 3.1.9 3.2.0 3.2.2 3.2.3 3.2.4 3.2.5 3.2.6 3.2.7 3.2.8 3.2.9 3.3.0 3.3.1 3.3.2 3.3.3 3.3.4 3.3.5 3.3.6 3.3.7 3.3.8 3.3.9 3.4.0 3.4.1 3.4.2 3.4.3 3.5.0 3.5.1 3.5.2 3.5.3 3.5.4 3.5.5 3.5.6 3.5.7 3.5.8 4.0.0 4.0.1 4.0.2 4.0.3 4.1.0 4.1.1 4.1.2 4.1.3 4.1.4 4.1.5 4.1.6 4.1.8 4.2.0 4.2.1 4.2.2 4.3.0 4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 4.3.6 4.3.7 4.3.8 4.3.9 4.4.0 4.4.1 4.4.10 4.4.11 4.4.12 4.4.2 4.4.3 4.4.4 4.4.5 4.4.6 4.4.7 4.4.8 4.4.9 5.10 5.10.1 5.10.2 5.11 5.11.1 5.11.2 5.11.3 5.11.4 5.12 5.12.1 5.12.2 5.12.3 5.12.4 5.12.5 5.12.6 5.6.10 5.6.2 5.6.3 5.6.4 5.6.5 5.6.6 5.6.7 5.6.8 5.6.9 5.7.0 5.7.1 5.7.10 5.7.12 5.7.13 5.7.2 5.7.3 5.7.4 5.7.5 5.7.6 5.7.7 5.7.8 5.7.9 5.8.0 5.8.1 5.8.10 5.8.11 5.8.12 5.8.13 5.8.14 5.8.2 5.8.3 5.8.4
advanced-custom-fields / includes / api / api-template.php
advanced-custom-fields / includes / api Last commit date
api-helpers.php 2 weeks ago api-template.php 3 months ago api-term.php 5 months ago index.php 2 years ago
api-template.php
1567 lines
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