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 / rest-api / acf-rest-api-functions.php
advanced-custom-fields / includes / rest-api Last commit date
acf-rest-api-functions.php 4 weeks ago class-acf-rest-api.php 5 months ago class-acf-rest-embed-links.php 6 months ago class-acf-rest-request.php 6 months ago index.php 2 years ago
acf-rest-api-functions.php
283 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 * Get the REST API schema for a given field.
14 *
15 * @param array $field
16 * @return array
17 */
18 function acf_get_field_rest_schema( array $field ) {
19 $type = acf_get_field_type( $field['type'] );
20 $schema = array();
21
22 if ( ! is_object( $type ) || ! method_exists( $type, 'get_rest_schema' ) ) {
23 return $schema;
24 }
25
26 $schema = $type->get_rest_schema( $field );
27
28 /**
29 * Filter the REST API schema for a given field.
30 *
31 * @param array $schema The field schema array.
32 * @param array $field The field array.
33 */
34 return (array) apply_filters( 'acf/rest/get_field_schema', $schema, $field );
35 }
36
37 acf_add_filter_variations( 'acf/rest/get_field_schema', array( 'type', 'name', 'key' ), 1 );
38
39 /**
40 * Get the REST API field links for a given field. The links are appended to the REST response under the _links property
41 * and provide API resource links to related objects. If a link is marked as 'embeddable', WordPress can load the resource
42 * in the main request under the _embedded property when the request contains the _embed URL parameter.
43 *
44 * @see \acf_field::get_rest_links()
45 * @see https://developer.wordpress.org/rest-api/using-the-rest-api/linking-and-embedding/
46 *
47 * @param string|integer $post_id
48 * @param array $field
49 * @return array
50 */
51 function acf_get_field_rest_links( $post_id, array $field ) {
52 $value = acf_get_value( $post_id, $field );
53 $type = acf_get_field_type( $field['type'] );
54 $links = $type->get_rest_links( $value, $post_id, $field );
55
56 /**
57 * Filter the REST API links for a given field.
58 *
59 * @param array $links
60 * @param string|int $post_id
61 * @param array $field
62 * @param mixed $value
63 */
64 return (array) apply_filters( 'acf/rest/get_field_links', $links, $post_id, $field, $value );
65 }
66
67 acf_add_filter_variations( 'acf/rest/get_field_links', array( 'type', 'name', 'key' ), 2 );
68
69 /**
70 * Replaces User subfield data with REST-safe values.
71 *
72 * Walks the subfields of a container field (Group, Clone, Repeater layout row,
73 * or Flexible Content layout row), delegating each subfield's value to
74 * {@see acf_rest_sanitize_user_data()} so that any nested User field data is
75 * reduced to IDs.
76 *
77 * @since ACF 6.8.7
78 *
79 * @param mixed $formatted_value The formatted parent value.
80 * @param mixed $raw_value The raw parent value.
81 * @param array $sub_fields The parent field's subfields.
82 * @param string $output_property The subfield property used as the output key.
83 * @return mixed
84 */
85 function acf_rest_sanitize_user_sub_fields( $formatted_value, $raw_value, $sub_fields, $output_property ) {
86 if ( ! is_array( $formatted_value ) || ! is_array( $sub_fields ) ) {
87 return $formatted_value;
88 }
89
90 $raw_value = is_array( $raw_value ) ? $raw_value : array();
91
92 foreach ( $sub_fields as $sub_field ) {
93 if ( ! is_array( $sub_field ) ) {
94 continue;
95 }
96
97 $output_key = array_key_exists( $output_property, $sub_field )
98 ? $sub_field[ $output_property ]
99 : $sub_field['name'] ?? '';
100 if ( '' === $output_key || ! array_key_exists( $output_key, $formatted_value ) ) {
101 continue;
102 }
103
104 $raw_key = $sub_field['key'] ?? '';
105 $raw_sub_value = '' !== $raw_key && array_key_exists( $raw_key, $raw_value )
106 ? $raw_value[ $raw_key ]
107 : null;
108
109 $formatted_value[ $output_key ] = acf_rest_sanitize_user_data(
110 $formatted_value[ $output_key ],
111 $raw_sub_value,
112 $sub_field
113 );
114 }
115
116 return $formatted_value;
117 }
118
119 /**
120 * Replaces formatted User field data with REST-safe values based on the field definition.
121 *
122 * Recurses into Group, Clone, Repeater, and Flexible Content containers so
123 * nested User fields are handled the same way as top-level User fields.
124 *
125 * @since ACF 6.8.7
126 *
127 * @param mixed $formatted_value The formatted field value.
128 * @param mixed $raw_value The raw field value.
129 * @param array $field The field array.
130 * @return mixed
131 */
132 function acf_rest_sanitize_user_data( $formatted_value, $raw_value, $field ) {
133 if ( empty( $field['type'] ) ) {
134 return $formatted_value;
135 }
136
137 if ( 'user' === $field['type'] ) {
138 if ( ! $formatted_value ) {
139 return $formatted_value;
140 }
141
142 if ( ! empty( $field['multiple'] ) && is_array( $formatted_value ) ) {
143 $user_ids = array();
144 foreach ( $formatted_value as $user ) {
145 $user_ids[] = acf_idval( $user );
146 }
147
148 return $user_ids;
149 }
150
151 return acf_idval( $formatted_value );
152 }
153
154 if ( ! is_array( $formatted_value ) ) {
155 return $formatted_value;
156 }
157
158 $is_clone = 'clone' === $field['type'];
159 $is_group = 'group' === $field['type'];
160
161 if ( $is_group || $is_clone ) {
162 $output_property = $is_clone ? '__name' : '_name';
163
164 return acf_rest_sanitize_user_sub_fields(
165 $formatted_value,
166 $raw_value,
167 $field['sub_fields'] ?? array(),
168 $output_property
169 );
170 }
171
172 if ( 'repeater' === $field['type'] ) {
173 $raw_value = is_array( $raw_value ) ? $raw_value : array();
174
175 foreach ( $formatted_value as $row_index => $formatted_row ) {
176 $raw_row = array_key_exists( $row_index, $raw_value ) ? $raw_value[ $row_index ] : array();
177
178 $formatted_value[ $row_index ] = acf_rest_sanitize_user_sub_fields(
179 $formatted_row,
180 $raw_row,
181 $field['sub_fields'] ?? array(),
182 '_name'
183 );
184 }
185
186 return $formatted_value;
187 }
188
189 if ( 'flexible_content' === $field['type'] ) {
190 $raw_value = is_array( $raw_value ) ? $raw_value : array();
191
192 foreach ( $formatted_value as $row_index => $formatted_row ) {
193 if ( ! is_array( $formatted_row ) ) {
194 continue;
195 }
196
197 $raw_row = array_key_exists( $row_index, $raw_value ) && is_array( $raw_value[ $row_index ] )
198 ? $raw_value[ $row_index ]
199 : array();
200 $layout_name = $formatted_row['acf_fc_layout'] ?? $raw_row['acf_fc_layout'] ?? '';
201
202 foreach ( $field['layouts'] ?? array() as $layout ) {
203 if ( ! isset( $layout['name'] ) || $layout_name !== $layout['name'] ) {
204 continue;
205 }
206
207 $formatted_value[ $row_index ] = acf_rest_sanitize_user_sub_fields(
208 $formatted_row,
209 $raw_row,
210 $layout['sub_fields'] ?? array(),
211 '_name'
212 );
213 break;
214 }
215 }
216 }
217
218 return $formatted_value;
219 }
220
221 /**
222 * Format a given field's value for output in the REST API.
223 *
224 * @param $value
225 * @param $post_id
226 * @param $field
227 * @param string $format 'light' for normal REST API formatting or 'standard' to apply ACF's normal field formatting.
228 * @return mixed
229 */
230 function acf_format_value_for_rest( $value, $post_id, $field, $format = 'light' ) {
231 if ( $format === 'standard' ) {
232 $value_formatted = acf_format_value( $value, $post_id, $field );
233 } else {
234 $type = acf_get_field_type( $field['type'] );
235 $value_formatted = $type->format_value_for_rest( $value, $post_id, $field );
236 }
237
238 /**
239 * Filter the formatted value for a given field.
240 *
241 * @param mixed $value_formatted The formatted value.
242 * @param string|int $post_id The post ID of the current object.
243 * @param array $field The field array.
244 * @param mixed $value The raw/unformatted value.
245 * @param string $format The format applied to the field value.
246 */
247 return apply_filters( 'acf/rest/format_value_for_rest', $value_formatted, $post_id, $field, $value, $format );
248 }
249
250 acf_add_filter_variations( 'acf/rest/format_value_for_rest', array( 'type', 'name', 'key' ), 2 );
251
252 /**
253 * Reduces User field REST responses to IDs for requesters without the
254 * `list_users` capability. Hooked into acf/rest/format_value_for_rest so
255 * the sanitizer only runs for field types that can carry user data.
256 *
257 * @since ACF 6.8.7
258 *
259 * @param mixed $value_formatted The formatted field value.
260 * @param string|integer $post_id The post ID of the current object.
261 * @param array $field The field array.
262 * @param mixed $value The raw/unformatted value.
263 * @param string $format The format applied to the field value.
264 * @return mixed
265 */
266 function acf_rest_apply_user_data_sanitizer( $value_formatted, $post_id, $field, $value, $format ) {
267 if ( 'standard' !== $format || empty( $field['type'] ) ) {
268 return $value_formatted;
269 }
270
271 if ( ! in_array( $field['type'], array( 'user', 'group', 'clone', 'repeater', 'flexible_content' ), true ) ) {
272 return $value_formatted;
273 }
274
275 // Preserve existing behavior for requesters authorized to list users.
276 if ( current_user_can( 'list_users' ) ) {
277 return $value_formatted;
278 }
279
280 return acf_rest_sanitize_user_data( $value_formatted, $value, $field );
281 }
282 add_filter( 'acf/rest/format_value_for_rest', 'acf_rest_apply_user_data_sanitizer', 10, 5 );
283