Click to initialize TinyMCE
You can register a form in the “ACF > Forms” menu or using acfe_register_form()
as below. See Settings Cheatsheet for the list of all available arguments.
Usage example:
add_action('acfe/init', 'my_form_register');
function my_form_register(){
acfe_register_form(array(
'name' => 'my-form',
'title' => 'My Form',
'field_groups' => array(
'group_5ffd27b7d0c62',
),
'attributes' => array(
'submit' => array(
'value' => 'Submit Form',
),
),
'success' => array(
'message' => 'The page "{action:post:post_title}" has been created.',
),
'actions' => array(
array(
'action' => 'post',
'type' => 'insert_post',
'save' => array(
'post_type' => 'page',
'post_status' => 'publish',
'post_title' => '{field:field_5ff7ee7cdd8f3}',
'acf_fields' => array(
'field_6102a25520748',
'field_63efcca4ea9b8',
),
),
),
),
));
}
Render with form name
Once registered, the form can be rendered anywhere on the front-end using the acfe_form()
function, with the form name
as argument:
<?php get_header(); ?>
<?php acfe_form('my-form'); ?>
<?php get_footer(); ?>
Render with form id
Alternatively, you can use the form ID, in case the form was registered with the Form UI:
<?php get_header(); ?>
<?php acfe_form(120); ?>
<?php get_footer(); ?>
Render and override settings
You can also render a form and override settings on the fly. To do so, pass an array with a name
or ID
to choose which form to display, and override existing settings. Usage example:
<?php get_header(); ?>
<?php
acfe_form(array(
'name' => 'my-form', // render 'my-form'
'success' => array(
'message' => 'Success!', // change the success message
),
));
?>
<?php get_footer(); ?>
Alternatively, it is possible to register and render an inline form, directly within the front-end template. The following form doesn’t require acfe_register_form()
, as it is created and displayed on the fly:
<?php get_header(); ?>
<?php
// create & render an inline form
acfe_form(array(
'name' => 'inline-form',
'title' => 'Inline Form',
'field_groups' => array(
'group_5ffd27b7d0c62',
),
'attributes' => array(
'submit' => array(
'value' => 'Submit',
),
),
'success' => array(
'message' => 'The page "{action:post:post_title}" has been created.',
),
'actions' => array(
array(
'action' => 'post',
'type' => 'insert_post',
'save' => array(
'post_type' => 'page',
'post_status' => 'publish',
'post_title' => '{field:field_5ff7ee7cdd8f3}',
'acf_fields' => array(
'field_6102a25520748',
'field_63efcca4ea9b8',
),
),
),
),
));
?>
<?php get_footer(); ?>
The most basic way to display field groups is to fill the field_groups
argument. The form will automatically display the related fields.
acfe_form(array(
'name' => 'my-form',
'field_groups' => array(
'group_5ffd27b7d0c62',
'group_5ffd66b8aa7ca',
),
));
If you need to control where the fields are displayed you can use it in combination with the render
argument, and the {render:fields}
template tag.
The following example will render both field groups within arbitrary HTML:
acfe_form(array(
'name' => 'my-form',
'field_groups' => array(
'group_5ffd27b7d0c62',
'group_5ffd66b8aa7ca',
),
'render' => '
<h3>My Form</h3>
<div class="wrapper">
{render:fields}
</div>
',
));
As an alternative, it is possible to omit the field_groups
argument, and directly use {render:group_5f5e3b3b1b1d1}
. The following example will split the displayed field groups:
acfe_form(array(
'name' => 'my-form',
'render' => '
<h3>Field Group 1</h3>
<div class="wrapper">
{render:group_5ffd27b7d0c62}
</div>
<h3>Field Group 2</h3>
<div class="wrapper">
{render:group_5ffd66b8aa7ca}
</div>
',
));
It is also possible to render each fields individually, using the field name or key. Please note that you can only render top-level fields.
For example, you cannot render Repeater sub fields individually, you have to render the whole repeater. If you need to hide a sub field, please see the Hide Field section.
acfe_form(array(
'name' => 'my-form',
'render' => '
<div class="row">
<div class="col-6">
{render:my_field}
</div>
<div class="col-6">
{render:field_5ffa85c208d1e}
</div>
<div class="col-12">
{render:field_5ff29c5ba9df9}
</div>
</div>
',
));
The submission button is rendered after all the fields by default, but it can be also placed manually with the {render:submit}
tag. Note the submit attribute must still be enabled and filled.
acfe_form(array(
'name' => 'my-form',
'render' => '
<h3>My Form</h3>
<div class="wrapper">
{render:submit}
{render:field_5ff7ee7cdd8f3}
{render:field_5ffa85c208d1e}
</div>
',
));
Fields can be prefilled with values using the map
argument. Assigned values must be unformatted and compatible with their field type. For example, a Date Picker field value should use the YYYYMMDD
format.
acfe_form(array(
'name' => 'my-form',
'render' => '
{render:field_5ff7ee7cdd8f3}
{render:field_5ffa85c208d1e}
',
'map' => array(
'field_5ff7ee7cdd8f3' => array(
'value' => 'my value',
),
'field_5ffa85c208d1e' => array(
'value' => 'my other value',
),
),
));
Here is an example with a more complex field, like a Repeater:
acfe_form(array(
'name' => 'my-form',
'render' => '
{render:field_5ff7ee7cdd8f3}
',
'map' => array(
// repeater field
'field_5ff7ee7cdd8f3' => array(
'value' => array(
array(
'field_621a65cc5521e' => 'Row 1',
),
array(
'field_621a65cc5521e' => 'Row 2',
),
)
),
),
));
If you need to inject values from existing fields in the database, make sure to get unformatted values. To do so, add false
as the last argument in your get_field()
. See documentation.
// get value from existing post (unformatted)
$my_field = get_field('my_field', 145, false);
acfe_form(array(
'name' => 'my-form',
'render' => '
{render:field_5ff7ee7cdd8f3}
',
'map' => array(
'field_5ff7ee7cdd8f3' => array(
'value' => $my_field, // use value
),
),
));
The map
argument allows to hide specific fields by assigning false
, just like in the acf/prepare_field
hook.
acfe_form(array(
'name' => 'my-form',
'render' => '
{render:group_5ffd27b7d0c62}
',
'map' => array(
'field_5ff7ee7cdd8f3' => false, // hide this field
),
));
Following this logic, we can also change the label, instructions and other field settings:
acfe_form(array(
'name' => 'my-form',
'render' => '
{render:field_5ff7ee7cdd8f3}
',
'map' => array(
'field_5ff7ee7cdd8f3' => array(
'label' => 'New Label',
'instructions' => 'New Instructions',
// ...
),
),
));
The easiest way to validate the whole form is to use the acfe/form/validate_form
hook. You can retrieve any field input value using get_field()
and omit the $post_id
argument.
To throw an error, simply use the acfe_add_validation_error()
helper.
add_action('acfe/form/validate_form/form=my-form', 'my_form_validation');
function my_form_validation($form){
// get field input value
$my_field = get_field('my_field');
// get field input value (unformatted)
// $my_field = get_field('my_field', false, false);
// check field value
if($my_field === 'my value'){
// add validation error
acfe_add_validation_error('my_field', 'my value is not allowed');
}
}
Indeed, the native ACF hook acf/validate_value
will also work for front-end forms. However, you have to make sure the request comes from the front-end, and not the WP Admin, using acfe_is_front()
.
add_filter('acf/validate_value/name=my_field', 'my_acf_validate_value', 10, 4);
function my_acf_validate_value($valid, $value, $field, $input_name){
// bail early if not on the front-end
if(!acfe_is_front()){
return $valid;
}
// ...
return $valid;
}
Following the same logic as the validation, you can retrieve field input values with get_field()
inside the acfe/form/submit_form
hook. See documentation.
In this example, we’ll create a new page using fields values, and update ACF fields in the new page with update_field()
.
<?php get_header(); ?>
<?php
acfe_form(array(
'name' => 'my-form',
'title' => 'My Form',
'field_groups' => array(
'group_5ffd27b7d0c62',
),
));
?>
<?php get_footer(); ?>
add_action('acfe/form/submit_form/form=my-form', 'my_form_submission');
function my_form_submission($form){
// get title input value
$title = get_field('title');
// get description input value
$description = get_field('description');
// create page
$post_id = wp_insert_post(array(
'post_title' => $title, // use title field
'post_content' => $description, // use description field
'post_type' => 'page',
'post_status' => 'publish',
));
// make sure the page was created
if($post_id && !is_wp_error($post_id)){
// get fields input value
// we must get unformatted values in order to update fields later
$date = get_field('date', false, false);
$checkbox = get_field('checkbox', false, false);
// update acf fields on the new page
update_field('date', $date, $post_id);
update_field('checkbox', $checkbox, $post_id);
}
}
The exact same result can be achieved using the built-in Post Action, with less code. Usage example:
<?php get_header(); ?>
<?php
acfe_form(array(
'name' => 'my-form',
'title' => 'My Form',
'field_groups' => array(
'group_5ffd27b7d0c62', // display field group
),
'actions' => array(
array(
'action' => 'post',
'type' => 'insert_post',
'save' => array(
'post_type' => 'page',
'post_status' => 'publish',
'post_title' => '{field:field_5ff7ee7cdd8f3}', // title field
'post_content' => '{field:field_621a65cc5521e}', // description field
'acf_fields' => array(
'field_6102a25520748', // date field
'field_63efcca4ea9b8', // checkbox field
),
),
),
),
));
?>
<?php get_footer(); ?>
The easiest way to control whenever a form should be rendered is to use the classic if()
conditional logic.
// only display the form to logged user
if(is_user_logged_in()){
acfe_form('my-form');
}
Alternatively, you can use the acfe/form/load_form
hook, check your condition and return false
to hide the form. This example will achieve the same result, but without the if()
condition on the front-end template.
add_filter('acfe/form/load_form/form=my-form', 'my_form_load');
function my_form_load($form){
// check if user is logged in
if(!is_user_logged_in()){
return false; // hide form
}
// display form
return $form;
}
<?php get_header(); ?>
<?php acfe_form('my-form'); ?>
<?php get_footer(); ?>
You can pass custom data to the form during the form render, and retrieve it later in the Form UI or in PHP hooks. Usage example:
acfe_form(array(
'name' => 'my-form',
'profile_id' => get_current_user_id(), // add custom data
'actions' => array(
array(
'action' => 'redirect',
'url' => '/profile?id={form:profile_id}', // retrieve custom data
),
),
));
Custom data can also be passed with the acfe/form/load_form
filter. See documentation. Usage example:
add_filter('acfe/form/load_form/form=my-form', 'my_form_settings');
function my_form_settings($form){
// add custom data
$form['profile_id'] = get_current_user_id();
// return
return $form;
}
These custom data can then be retrieved in any front-end forms hooks within the $form
argument. Usage example:
// form submission
add_action('acfe/form/submit_form/form=my-form', 'my_form_submit');
function my_form_submit($form){
// retrieve custom data
$user_id = $form['profile_id'];
// ...
}
Or directly within the Form UI using the {form:profile_id}
template tag. Usage example: