PluginProbe
Advanced Custom Fields (ACF®) / 6.2.8
Advanced Custom Fields (ACF®) v6.2.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 All 230 releases
advanced-custom-fields / includes / forms / form-front.php
form-front.php
590 lines 14.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 if ( ! defined( 'ABSPATH' ) ) {
4 exit; // Exit if accessed directly
5 }
6
7 if ( ! class_exists( 'acf_form_front' ) ) :
8 #[AllowDynamicProperties]
9 class acf_form_front {
10
11 /** @var array An array of registered form settings */
12 private $forms = array();
13
14 /** @var array An array of default fields */
15 public $fields = array();
16
17
18 /**
19 * This function will setup the class functionality
20 *
21 * @type function
22 * @date 5/03/2014
23 * @since 5.0.0
24 *
25 * @param n/a
26 * @return n/a
27 */
28
29 function __construct() {
30
31 // vars
32 $this->fields = array(
33
34 '_post_title' => array(
35 'prefix' => 'acf',
36 'name' => '_post_title',
37 'key' => '_post_title',
38 'label' => __( 'Title', 'acf' ),
39 'type' => 'text',
40 'required' => true,
41 ),
42
43 '_post_content' => array(
44 'prefix' => 'acf',
45 'name' => '_post_content',
46 'key' => '_post_content',
47 'label' => __( 'Content', 'acf' ),
48 'type' => 'wysiwyg',
49 ),
50
51 '_validate_email' => array(
52 'prefix' => 'acf',
53 'name' => '_validate_email',
54 'key' => '_validate_email',
55 'label' => __( 'Validate Email', 'acf' ),
56 'type' => 'text',
57 'value' => '',
58 'wrapper' => array( 'style' => 'display:none !important;' ),
59 ),
60
61 );
62
63 // actions
64 add_action( 'acf/validate_save_post', array( $this, 'validate_save_post' ), 1 );
65
66 // filters
67 add_filter( 'acf/pre_save_post', array( $this, 'pre_save_post' ), 5, 2 );
68 }
69
70
71 /**
72 * description
73 *
74 * @type function
75 * @date 28/2/17
76 * @since 5.5.8
77 *
78 * @param $post_id (int)
79 * @return $post_id (int)
80 */
81
82 function validate_form( $args ) {
83
84 // defaults
85 // Todo: Allow message and button text to be generated by CPT settings.
86 $args = wp_parse_args(
87 $args,
88 array(
89 'id' => 'acf-form',
90 'post_id' => false,
91 'new_post' => false,
92 'field_groups' => false,
93 'fields' => false,
94 'post_title' => false,
95 'post_content' => false,
96 'form' => true,
97 'form_attributes' => array(),
98 'return' => add_query_arg( 'updated', 'true', acf_get_current_url() ),
99 'html_before_fields' => '',
100 'html_after_fields' => '',
101 'submit_value' => __( 'Update', 'acf' ),
102 'updated_message' => __( 'Post updated', 'acf' ),
103 'label_placement' => 'top',
104 'instruction_placement' => 'label',
105 'field_el' => 'div',
106 'uploader' => 'wp',
107 'honeypot' => true,
108 'html_updated_message' => '<div id="message" class="updated"><p>%s</p></div>', // 5.5.10
109 'html_submit_button' => '<input type="submit" class="acf-button button button-primary button-large" value="%s" />', // 5.5.10
110 'html_submit_spinner' => '<span class="acf-spinner"></span>', // 5.5.10
111 'kses' => true, // 5.6.5
112 )
113 );
114
115 $args['form_attributes'] = wp_parse_args(
116 $args['form_attributes'],
117 array(
118 'id' => $args['id'],
119 'class' => 'acf-form',
120 'action' => '',
121 'method' => 'post',
122 )
123 );
124
125 // filter post_id
126 $args['post_id'] = acf_get_valid_post_id( $args['post_id'] );
127
128 // new post?
129 if ( $args['post_id'] === 'new_post' ) {
130 $args['new_post'] = wp_parse_args(
131 $args['new_post'],
132 array(
133 'post_type' => 'post',
134 'post_status' => 'draft',
135 )
136 );
137 }
138
139 // filter
140 $args = apply_filters( 'acf/validate_form', $args );
141
142 // return
143 return $args;
144 }
145
146
147 /**
148 * description
149 *
150 * @type function
151 * @date 28/2/17
152 * @since 5.5.8
153 *
154 * @param $post_id (int)
155 * @return $post_id (int)
156 */
157
158 function add_form( $args = array() ) {
159
160 // validate
161 $args = $this->validate_form( $args );
162
163 // append
164 $this->forms[ $args['id'] ] = $args;
165 }
166
167
168 /**
169 * description
170 *
171 * @type function
172 * @date 28/2/17
173 * @since 5.5.8
174 *
175 * @param $post_id (int)
176 * @return $post_id (int)
177 */
178
179 function get_form( $id = '' ) {
180
181 // bail early if not set
182 if ( ! isset( $this->forms[ $id ] ) ) {
183 return false;
184 }
185
186 // return
187 return $this->forms[ $id ];
188 }
189
190
191 /**
192 * This function will validate fields from the above array
193 *
194 * @type function
195 * @date 7/09/2016
196 * @since 5.4.0
197 *
198 * @param $post_id (int)
199 * @return $post_id (int)
200 */
201
202 function validate_save_post() {
203
204 // register field if isset in $_POST
205 foreach ( $this->fields as $k => $field ) {
206
207 // bail early if no in $_POST
208 if ( ! isset( $_POST['acf'][ $k ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Verified elsewhere.
209 continue;
210 }
211
212 // register
213 acf_add_local_field( $field );
214 }
215
216 // honeypot
217 if ( ! empty( $_POST['acf']['_validate_email'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Data not used; presence indicates spam.
218
219 acf_add_validation_error( '', __( 'Spam Detected', 'acf' ) );
220 }
221 }
222
223
224 /**
225 * description
226 *
227 * @type function
228 * @date 7/09/2016
229 * @since 5.4.0
230 *
231 * @param $post_id (int)
232 * @return $post_id (int)
233 */
234
235 function pre_save_post( $post_id, $form ) {
236
237 // vars
238 $save = array(
239 'ID' => 0,
240 );
241
242 // determine save data
243 if ( is_numeric( $post_id ) ) {
244
245 // update post
246 $save['ID'] = $post_id;
247 } elseif ( $post_id == 'new_post' ) {
248
249 // merge in new post data
250 $save = array_merge( $save, $form['new_post'] );
251 } else {
252
253 // not post
254 return $post_id;
255 }
256
257 // phpcs:disable WordPress.Security.NonceVerification.Missing -- Verified in check_submit_form().
258 // save post_title
259 if ( isset( $_POST['acf']['_post_title'] ) ) {
260 $save['post_title'] = acf_extract_var( $_POST['acf'], '_post_title' ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized by WP when saved.
261 }
262
263 // save post_content
264 if ( isset( $_POST['acf']['_post_content'] ) ) {
265 $save['post_content'] = acf_extract_var( $_POST['acf'], '_post_content' ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized by WP when saved.
266 }
267 // phpcs:enable WordPress.Security.NonceVerification.Missing
268
269 // honeypot
270 if ( ! empty( $_POST['acf']['_validate_email'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Data not used; presence indicates spam.
271 return false;
272 }
273
274 // validate
275 if ( count( $save ) == 1 ) {
276 return $post_id;
277 }
278
279 // save
280 if ( $save['ID'] ) {
281 wp_update_post( $save );
282 } else {
283 $post_id = wp_insert_post( $save );
284 }
285
286 // return
287 return $post_id;
288 }
289
290
291 /**
292 * This function will enqueue a form
293 *
294 * @type function
295 * @date 7/09/2016
296 * @since 5.4.0
297 *
298 * @param $post_id (int)
299 * @return $post_id (int)
300 */
301
302 function enqueue_form() {
303
304 // check
305 $this->check_submit_form();
306
307 // load acf scripts
308 acf_enqueue_scripts();
309 }
310
311
312 /**
313 * This function will maybe submit form data
314 *
315 * @type function
316 * @date 3/3/17
317 * @since 5.5.10
318 *
319 * @param n/a
320 * @return n/a
321 */
322
323 function check_submit_form() {
324
325 // Verify nonce.
326 if ( ! acf_verify_nonce( 'acf_form' ) ) {
327 return false;
328 }
329
330 // Confirm form was submit.
331 if ( ! isset( $_POST['_acf_form'] ) ) {
332 return false;
333 }
334
335 // Load registered form using id.
336 $form = $this->get_form( acf_sanitize_request_args( $_POST['_acf_form'] ) );
337
338 // Fallback to encrypted JSON.
339 if ( ! $form ) {
340 $form = json_decode( acf_decrypt( sanitize_text_field( $_POST['_acf_form'] ) ), true );
341 if ( ! $form ) {
342 return false;
343 }
344 }
345
346 // Run kses on all $_POST data.
347 if ( $form['kses'] && isset( $_POST['acf'] ) ) {
348 $_POST['acf'] = wp_kses_post_deep( $_POST['acf'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- False positive.
349 }
350
351 // Validate data and show errors.
352 // Todo: Return WP_Error and show above form, keeping input values.
353 acf_validate_save_post( true );
354
355 // Submit form.
356 $this->submit_form( $form );
357 }
358
359
360 /**
361 * This function will submit form data
362 *
363 * @type function
364 * @date 3/3/17
365 * @since 5.5.10
366 *
367 * @param n/a
368 * @return n/a
369 */
370
371 function submit_form( $form ) {
372
373 // filter
374 $form = apply_filters( 'acf/pre_submit_form', $form );
375
376 // vars
377 $post_id = acf_maybe_get( $form, 'post_id', 0 );
378
379 // add global for backwards compatibility
380 $GLOBALS['acf_form'] = $form;
381
382 // allow for custom save
383 $post_id = apply_filters( 'acf/pre_save_post', $post_id, $form );
384
385 // save
386 acf_save_post( $post_id );
387
388 // restore form (potentially modified)
389 $form = $GLOBALS['acf_form'];
390
391 // action
392 do_action( 'acf/submit_form', $form, $post_id );
393
394 // vars
395 $return = acf_maybe_get( $form, 'return', '' );
396
397 // redirect
398 if ( $return ) {
399
400 // update %placeholders%
401 $return = str_replace( '%post_id%', $post_id, $return );
402 $return = str_replace( '%post_url%', get_permalink( $post_id ), $return );
403
404 // redirect
405 wp_redirect( $return ); //phpcs:ignore WordPress.Security.SafeRedirect.wp_redirect_wp_redirect -- unsafe redirects allowed.
406 exit;
407 }
408 }
409
410
411 /**
412 * description
413 *
414 * @type function
415 * @date 7/09/2016
416 * @since 5.4.0
417 *
418 * @param $post_id (int)
419 * @return $post_id (int)
420 */
421
422 function render_form( $args = array() ) {
423
424 // Vars.
425 $is_registered = false;
426 $field_groups = array();
427 $fields = array();
428
429 // Allow form settings to be directly provided.
430 if ( is_array( $args ) ) {
431 $args = $this->validate_form( $args );
432
433 // Otherwise, lookup registered form.
434 } else {
435 $is_registered = true;
436 $args = $this->get_form( $args );
437 if ( ! $args ) {
438 return false;
439 }
440 }
441
442 // Extract vars.
443 $post_id = $args['post_id'];
444
445 // Prevent ACF from loading values for "new_post".
446 if ( $post_id === 'new_post' ) {
447 $post_id = false;
448 }
449
450 // Set uploader type.
451 acf_update_setting( 'uploader', $args['uploader'] );
452
453 // Register local fields.
454 foreach ( $this->fields as $k => $field ) {
455 acf_add_local_field( $field );
456 }
457
458 // Append post_title field.
459 if ( $args['post_title'] ) {
460 $_post_title = acf_get_field( '_post_title' );
461 $_post_title['value'] = $post_id ? get_post_field( 'post_title', $post_id ) : '';
462 $fields[] = $_post_title;
463 }
464
465 // Append post_content field.
466 if ( $args['post_content'] ) {
467 $_post_content = acf_get_field( '_post_content' );
468 $_post_content['value'] = $post_id ? get_post_field( 'post_content', $post_id ) : '';
469 $fields[] = $_post_content;
470 }
471
472 // Load specific fields.
473 if ( $args['fields'] ) {
474
475 // Lookup fields using $strict = false for better compatibility with field names.
476 foreach ( $args['fields'] as $selector ) {
477 $fields[] = acf_maybe_get_field( $selector, $post_id, false );
478 }
479
480 // Load specific field groups.
481 } elseif ( $args['field_groups'] ) {
482 foreach ( $args['field_groups'] as $selector ) {
483 $field_groups[] = acf_get_field_group( $selector );
484 }
485
486 // Load fields for the given "new_post" args.
487 } elseif ( $args['post_id'] == 'new_post' ) {
488 $field_groups = acf_get_field_groups( $args['new_post'] );
489
490 // Load fields for the given "post_id" arg.
491 } else {
492 $field_groups = acf_get_field_groups(
493 array(
494 'post_id' => $args['post_id'],
495 )
496 );
497 }
498
499 // load fields from the found field groups.
500 if ( $field_groups ) {
501 foreach ( $field_groups as $field_group ) {
502 $_fields = acf_get_fields( $field_group );
503 if ( $_fields ) {
504 foreach ( $_fields as $_field ) {
505 $fields[] = $_field;
506 }
507 }
508 }
509 }
510
511 // Add honeypot field.
512 if ( $args['honeypot'] ) {
513 $fields[] = acf_get_field( '_validate_email' );
514 }
515
516 // Display updated_message
517 if ( ! empty( $_GET['updated'] ) && $args['updated_message'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Used as a flag; data not used.
518 printf( $args['html_updated_message'], $args['updated_message'] ); //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- designed to contain potentially unsafe HTML, set by developers.
519 }
520
521 // display form
522 if ( $args['form'] ) : ?>
523 <form <?php echo acf_esc_attrs( $args['form_attributes'] ); ?>>
524 <?php
525 endif;
526
527 // Render hidde form data.
528 acf_form_data(
529 array(
530 'screen' => 'acf_form',
531 'post_id' => $args['post_id'],
532 'form' => $is_registered ? $args['id'] : acf_encrypt( json_encode( $args ) ),
533 )
534 );
535
536 ?>
537 <div class="acf-fields acf-form-fields -<?php echo esc_attr( $args['label_placement'] ); ?>">
538 <?php echo $args['html_before_fields']; ?><?php //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- designed to contain potentially unsafe HTML, set by developers. ?>
539 <?php acf_render_fields( $fields, $post_id, $args['field_el'], $args['instruction_placement'] ); ?>
540 <?php echo $args['html_after_fields']; ?><?php //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- designed to contain potentially unsafe HTML, set by developers. ?>
541 </div>
542 <?php if ( $args['form'] ) : ?>
543 <div class="acf-form-submit">
544 <?php printf( $args['html_submit_button'], $args['submit_value'] ); ?><?php //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- designed to contain potentially unsafe HTML, set by developers. ?>
545 <?php echo $args['html_submit_spinner']; ?><?php //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- designed to contain potentially unsafe HTML, set by developers. ?>
546 </div>
547 </form>
548 <?php endif;
549 }
550 }
551
552 // initialize
553 acf()->form_front = new acf_form_front();
554 endif; // class_exists check
555
556
557 /**
558 * Functions
559 *
560 * alias of acf()->form->functions
561 *
562 * @type function
563 * @date 11/06/2014
564 * @since 5.0.0
565 *
566 * @param n/a
567 * @return n/a
568 */
569 function acf_form_head() {
570
571 acf()->form_front->enqueue_form();
572 }
573
574 function acf_form( $args = array() ) {
575
576 acf()->form_front->render_form( $args );
577 }
578
579 function acf_get_form( $id = '' ) {
580
581 return acf()->form_front->get_form( $id );
582 }
583
584 function acf_register_form( $args ) {
585
586 acf()->form_front->add_form( $args );
587 }
588
589 ?>
590