PluginProbe
Advanced Forms for ACF / trunk
Advanced Forms for ACF vtrunk
1.9.0 1.9.1 1.9.2.1 1.9.3 1.9.3.1 1.9.3.2 1.9.3.3 1.9.3.4 1.9.3.5 1.9.3.6 1.9.3.7 1.9.3.8 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.0.3.1 1.0.3.2 1.0.3.3 1.0.4 1.1.0 1.1.1 1.2.0 1.3.0 All 51 releases
advanced-forms / api / api-forms.php

api-forms.php in Advanced Forms for ACF trunk, at api/api-forms.php

463 lines 11.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * The main function used to output a form
5 *
6 * @since 1.0.0
7 */
8 function advanced_form( $form_id, $args = array() ) {
9 // Render form and catch output
10 ob_start();
11 do_action( 'af/form/render', $form_id, $args );
12 $output = ob_get_clean();
13
14 if ( ! isset( $args['echo'] ) || $args['echo'] ) {
15 echo $output;
16 }
17
18 return $output;
19 }
20
21 /**
22 * Helper function to extract a specific field value from submitted fields
23 *
24 * @since 1.0.0
25 */
26 function af_get_field( $field_key_or_name, $fields = false ) {
27 // Get fields from the global submission object if fields weren't passed
28 if ( ! $fields && af_has_submission() ) {
29 $fields = AF()->submission['fields'];
30 }
31
32 foreach ( $fields as $field ) {
33 if ( $field['key'] == $field_key_or_name || $field['name'] == $field_key_or_name ) {
34 return $field['value'];
35 }
36
37 // Also search sub fields
38 if ( isset( $field['sub_fields'] ) && is_array( $field['value'] ) ) {
39 foreach ( $field['value'] as $sub_field_name => $sub_field_value ) {
40 if ( $sub_field_name == $field_key_or_name ) {
41 return $sub_field_value;
42 }
43 }
44 }
45 }
46
47 return false;
48 }
49
50 /**
51 * Save submitted field directly to post
52 *
53 * @since 1.1.1
54 * @deprecated 1.3.0 Use af_save_field()
55 * @see af_save_field()
56 */
57 function af_save_field_to_post( $field_key_or_name, $post_id ) {
58 _deprecated_function( __FUNCTION__, '1.3.0', 'af_save_field()' );
59 af_save_field( $field_key_or_name, $post_id );
60 }
61
62 /**
63 * Save submitted field directly to an object (post, user, term) with ACF naming
64 *
65 * @since 1.3.0
66 */
67 function af_save_field( $field_key_or_name, $object_id ) {
68 // Make sure we have a submission to work with
69 if ( ! af_has_submission() ) {
70 return false;
71 }
72
73 $field = af_get_field_object( $field_key_or_name );
74
75 /**
76 * We save the field directly to the post using acf_update_value.
77 * This ensures that clone fields, repeaters etc. work as intended.
78 * $field['_input'] should match the raw $_POST value.
79 */
80 if ( $field ) {
81 $value = $field['_input'];
82 acf_update_value( $value, $object_id, $field );
83 return true;
84 }
85
86 return false;
87 }
88
89 /**
90 * Save all submitted fields directly to an object (post, user, term) with ACF naming
91 *
92 * @since 1.3.0
93 */
94 function af_save_all_fields( $object_id, $excluded_fields = array() ) {
95 // Make sure we have a submission to work with
96 if ( ! af_has_submission() ) {
97 return false;
98 }
99
100 $fields = AF()->submission['fields'];
101
102 /**
103 * We save the fields directly to the post using acf_update_value.
104 * This ensures that clone fields, repeaters etc. work as intended.
105 * $field['_input'] should match the raw $_POST value.
106 */
107 foreach ( $fields as $field ) {
108 if ( in_array( $field['key'], $excluded_fields ) ) {
109 continue;
110 }
111
112 $value = $field['_input'];
113 acf_update_value( $value, $object_id, $field );
114 }
115
116 return true;
117 }
118
119 /**
120 * Helper function to extract a full field object from submitted fields
121 *
122 * @since 1.2.0
123 */
124 function af_get_field_object( $field_key_or_name, $fields = false ) {
125 // Get fields from the global submission object if fields weren't passed
126 if ( ! $fields && af_has_submission() ) {
127 $fields = AF()->submission['fields'];
128 }
129
130 foreach ( $fields as $field ) {
131 // Save submitted value to post using ACFs acf_update_value
132 if ( $field['key'] == $field_key_or_name || $field['name'] == $field_key_or_name ) {
133 return $field;
134 }
135 }
136
137 return false;
138 }
139
140 /**
141 * Used to register a form programmatically
142 *
143 * @since 1.0.0
144 */
145 function af_register_form( $form ) {
146 global $af_registered_forms;
147
148 if ( ! $af_registered_forms || ! is_array( $af_registered_forms ) ) {
149 $af_registered_forms = array();
150 }
151
152 $form = af_get_valid_form( $form );
153
154 if ( $form ) {
155 $af_registered_forms[ $form['key'] ] = $form;
156 }
157
158 return $form;
159 }
160
161 /**
162 * Checks if the passed key is a valid form key (begins with form_)
163 *
164 * @since 1.0.1
165 */
166 function af_is_valid_form_key( $key ) {
167 if ( ! is_string( $key ) ) {
168 return false;
169 }
170
171 if ( 'form_' == substr( $key, 0, 5 ) ) {
172 return true;
173 }
174
175 return false;
176 }
177
178 /**
179 * Validates and fills a form array with default values
180 *
181 * @since 1.0.0
182 */
183 function af_get_valid_form( $form ) {
184 // A form key is always required
185 if ( ! isset( $form['key'] ) ) {
186 return false;
187 }
188
189 $args = array(
190 'key' => '',
191 'post_id' => false,
192 'title' => '',
193 'display' => array(
194 'description' => '',
195 'success_message' => '',
196 ),
197 'create_entries' => false,
198 );
199
200 $args = apply_filters( 'af/form/valid_form', $args );
201
202 return wp_parse_args( $form, $args );
203 }
204
205 /**
206 * Generates a form array from a form post object
207 *
208 * @since 1.0.0
209 */
210 function af_form_from_post( $form_post ) {
211 // Get post object if ID has been passed
212 if ( is_numeric( $form_post ) ) {
213 $form_post = get_post( $form_post );
214 }
215
216 // Make sure we have a post and that it's a form
217 if ( ! $form_post || 'af_form' != $form_post->post_type ) {
218 return false;
219 }
220
221 $form = af_get_valid_form( array(
222 'post_id' => $form_post->ID,
223 'title' => $form_post->post_title,
224 'key' => get_post_meta( $form_post->ID, 'form_key', true ),
225 'display' => array(
226 'description' => get_field( 'form_description', $form_post->ID ),
227 'success_message' => get_field( 'form_success_message', $form_post->ID ),
228 ),
229 'create_entries' => get_field( 'form_create_entries', $form_post->ID ),
230 ) );
231
232 $form = apply_filters( 'af/form/from_post', $form, $form_post );
233 $form = apply_filters( 'af/form/from_post/id=' . $form['post_id'], $form, $form_post );
234 $form = apply_filters( 'af/form/from_post/key=' . $form['key'], $form, $form_post );
235
236 return $form;
237 }
238
239 /**
240 * Save a form array to a form post.
241 *
242 * @since 1.7.0
243 */
244 function af_form_to_post( $form, $post ) {
245 // Get post object if ID has been passed
246 if ( is_numeric( $post ) ) {
247 $post = get_post( $post );
248 }
249
250 wp_update_post( array(
251 'ID' => $post->ID,
252 'post_title' => $form['title'],
253 ) );
254
255 $form = af_get_valid_form( $form );
256
257 update_post_meta( $post->ID, 'form_key', $form['key'] );
258
259 update_field( 'field_form_description', $form['display']['description'], $post->ID );
260 update_field( 'field_form_success_message', $form['display']['success_message'], $post->ID );
261
262 update_field( 'field_form_create_entries', $form['create_entries'], $post->ID );
263
264 do_action( 'af/form/to_post', $form, $post );
265 do_action( 'af/form/to_post/id=' . $post->ID, $form, $post );
266 do_action( 'af/form/to_post/key=' . $form['key'], $form, $post );
267
268 return $post;
269 }
270
271 /**
272 * Retrieves a form either
273 *
274 * @since 1.0.0
275 */
276 function af_form_from_key( $key ) {
277 global $af_registered_forms;
278
279 if ( $af_registered_forms && isset( $af_registered_forms[ $key ] ) ) {
280 return af_get_valid_form( $af_registered_forms[ $key ] );
281 }
282
283 // Form not a registered one, search posts by key meta
284 $post = af_form_post_from_key( $key );
285 if ( $post ) {
286 return af_form_from_post( $post );
287 }
288
289 return false;
290 }
291
292 /**
293 * Retrieves a form post by key if one exists.
294 *
295 * @since 1.7.0
296 */
297 function af_form_post_from_key( $key ) {
298 $args = array(
299 'post_type' => 'af_form',
300 'posts_per_page' => '1',
301 'meta_query' => array(
302 array(
303 'key' => 'form_key',
304 'value' => $key,
305 ),
306 ),
307 );
308
309 $form_query = new WP_Query( $args );
310
311 if ( $form_query->have_posts() ) {
312 return $form_query->posts[0];
313 }
314
315 return false;
316 }
317
318 /**
319 * Retrieves a form by form key or form ID
320 *
321 * @since 1.0.0
322 */
323 function af_get_form( $form_id_or_key ) {
324 $form = false;
325
326 if ( af_is_valid_form_key( $form_id_or_key ) ) {
327 $form = af_form_from_key( $form_id_or_key );
328
329 } elseif ( is_numeric( $form_id_or_key ) ) {
330 $form = af_form_from_post( $form_id_or_key );
331
332 }
333
334 return $form;
335 }
336
337 /**
338 * Returns all forms, both those saved as posts and those registered
339 *
340 * @since 1.0.0
341 */
342 function af_get_forms() {
343 $forms = array();
344
345 // Get all forms saved as posts
346 $form_query = new WP_Query( [
347 'post_type' => 'af_form',
348 'posts_per_page' => - 1,
349 ] );
350
351 if ( $form_query->have_posts() ) {
352 foreach ( $form_query->posts as $form_post ) {
353 $form = af_form_from_post( $form_post );
354 $forms[] = $form;
355 }
356 }
357
358 // Get all programmatically registered forms
359 global $af_registered_forms;
360
361 if ( $af_registered_forms && is_array( $af_registered_forms ) ) {
362 foreach ( $af_registered_forms as $registered_form ) {
363 $forms[] = af_get_valid_form( $registered_form );
364 }
365 }
366
367 return $forms;
368 }
369
370 /**
371 * Returns all fields groups used by specified form
372 *
373 * @since 1.0.0
374 */
375 function af_get_form_field_groups( $form_key ) {
376 // If a full form array is passed
377 if ( ! empty( $form_key['key'] ) ) {
378 $form_key = $form_key['key'];
379 }
380
381 $field_groups = acf_get_field_groups( [ 'af_form' => $form_key, ] );
382
383 $field_groups = apply_filters( 'af/form/field_groups', $field_groups, $form_key );
384 $field_groups = apply_filters( "af/form/field_groups/key={$form_key}", $field_groups, $form_key );
385
386 return $field_groups;
387 }
388
389 /**
390 * Returns all fields assigned to a form
391 *
392 * @since 1.0.1
393 */
394 function af_get_form_fields( $form_key, $type = 'all' ) {
395 $exclude_types = array();
396
397 // Only pick fields which can be properly stringified (not repeaters, flexible fields etc.)
398 if ( 'regular' == $type ) {
399 $exclude_types = array( 'repeater', 'clone', 'flexible_content' );
400 }
401
402 $form_fields = array();
403
404 $field_groups = af_get_form_field_groups( $form_key );
405
406 if ( $field_groups ) {
407 foreach ( $field_groups as $field_group ) {
408 $fields = acf_get_fields( $field_group );
409 if ( ! empty ( $fields ) ) {
410 foreach ( $fields as $field ) {
411 if ( in_array( $field['type'], $exclude_types ) ) {
412 continue;
413 }
414 $form_fields[] = $field;
415 }
416 }
417 }
418 }
419
420 return $form_fields;
421 }
422
423 /**
424 * Renders the success message for a form. Requires that the submission has already been loaded.
425 *
426 * @since 1.7.2
427 */
428 function af_form_success_message( $form, $args ) {
429 $success_message = $form['display']['success_message'];
430 $success_message = apply_filters( 'af/form/success_message', $success_message, $form, $args );
431 $success_message = apply_filters( 'af/form/success_message/id=' . $form['post_id'], $success_message, $form, $args );
432 $success_message = apply_filters( 'af/form/success_message/key=' . $form['key'], $success_message, $form, $args );
433
434 $success_message = af_resolve_merge_tags( $success_message );
435
436 return sprintf( '<div class="af-success" aria-live="assertive" role="alert">%s</div>', $success_message );
437 }
438
439 /**
440 * Enqueues the necessary scripts and styles for a form.
441 *
442 * @since 1.8.0
443 */
444 function af_enqueue() {
445 // Enqueue the hotfix that prevents validation from firing across all forms on the same page when one is submitted.
446 if ( apply_filters( 'af/settings/enqueue_validation_hotfix', true ) ) {
447 wp_enqueue_script( 'af-multi-form-validation-hotfix', AF()->url . 'assets/dist/js/multi-form-validation-hotfix.js', [ 'acf-input' ] );
448 }
449
450 // Enqueue ACF scripts and styles
451 acf_enqueue_scripts();
452
453 // ACF fails to include all translations when running "acf_enqueue_scripts", hence we need to do it manually.
454 $acf_l10n = acf_get_instance( 'ACF_Assets' )->text;
455 wp_localize_script( 'acf-input', 'acfL10n', $acf_l10n );
456
457 wp_enqueue_script( 'af-forms-script', AF()->url . 'assets/dist/js/forms.js', array(
458 'jquery',
459 'acf-input'
460 ), AF()->version, true );
461
462 wp_enqueue_style( 'af-form-style', AF()->url . 'assets/dist/css/form.css' );
463 }