Advanced Custom Fields provides very powerful tools to extend a WordPress site using custom fields. The ACF UI integrates tightly with the standard WordPress admin making for a robust and seamless experience.
ACF has documentation on how to create custom fields programmatically using PHP. A typical use case would be when deploying a build which uses many custom field groups and fields, since these can be defined the theme functions.php.
However, there are a couple of problems with the documented approach:
- Fields are created as “local fields” at run time, which means they cannot be edited in the ACF admin UI.
- Fields are created using the acf/init hook which runs early in the page generation process.
But what if you want to create a field conditionally, based on user input in another field? Say you add a new size in a repeater field on a custom post type, and want to auto-create a counter field that tracks the number of sales in that size.
After digging into the ACF source code, I found the acf_update_field function in includes/api-field.php, which writes a field to the database:
/* * acf_update_field * * This function will update a field into the DB. * The returned field will always contain an ID * * @type function * @date 1/10/13 * @since 5.0.0 * * @param $field (array) * @return $field (array) */ function acf_update_field( $field = false, $specific = false )
It turns out you can use almost the same parameters as for the documented acf_update_local_field function. The only difference is that you have to set the parent as a post_id in the $field object, not a field group key. We can solve that by looking up the ID of the field group in the database.
Here is some code which illustrates creating a my_new_field_name field programmatically when the my_triggering_field is updated:
function get_acf_group_id($group_name){ global $wpdb; return $wpdb->get_var(" SELECT ID FROM $wpdb->posts WHERE post_type='acf-field-group' AND post_excerpt='$group_name'; "); } function my_field_registration( $value, $post_id, $field ) { if ( $field['name'] == 'my_triggering_field' ) { if ( $some_condition ) { $args = array( 'key' => 'field_' . uniqid();, 'label' => 'Field label', 'name' => 'my_new_field_name', 'type' => 'number', 'parent' => get_acf_group_id('my-field-group-name') // hyphenated! ); acf_update_field($args); } } return $value; } add_filter('acf/update_value', 'my_field_registration', 10, 3);
This field is created permanently in the database for all future users to use.
Hey Robin, great post. Do you know where I can find a list of the arguments for the $args array? I’m looking to programmatically create a group field which seems straightforward enough using your code example above. However I would then like to programmatically create sub fields within that group and I am unsure of how I specify that in the $args array.
Update: for anyone who sees this I figured it out and it’s super simple. The ‘parent’ arg needs to be set to the post ID of the parent field rather than the post ID of the group. I used the acf_get_field_post() function to retrieve the post ID.
Or, put all your fields inside a field group array and pass it to acf_import_field_group(). This method is defined in acf-field-group-functions.php.
Nice! Thanks Corey.