01273 264503 info@mootpoint.org

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.