search ]

How to Register ACF Fields Using PHP in WordPress

Registering ACF fields using PHP reduces the number of database reads and enables the use of Version Control like GIT and similar. The option to define fields via code decreases the chance of losing information that exists in a normal situation in the database.

It’s already stated that if you are looking for a solution for code deployment in several development environments, you can also use Synchronized Local JSON – an option that came in version 5 of ACF and provides a solution with minimal effort.

In terms of performance – Local JSON, as well as registering fields in PHP are definitely preferable over adding fields through the WordPress admin interface. To my understanding, the main advantage of registering fields in PHP over Local JSON is the possibility of translating the fields using textdomain.

Registering ACF Fields with PHP

Adding a group of fields (field groups) and adding the fields themselves is a fairly simple process. ACF can even generate the code for you from the Import / Export menu of ACF in the WordPress dashboard if you prefer to do it that way.

Remember that the identifier (key) for each field group and the identifier for each field must be unique. This identifier provides a reference for ACF to find, save, and load the information. If there are two fields with the same identifier, the second field will overwrite the first.

The functions that you can use, and which will be used in the examples later in the post, are the following functions, and you can find additional functions in the core/local.php file.

Function NameDescription
acf_add_local_field_group( $field_group )Adding a group of fields to the local cache
acf_add_local_field( $field )Adding a field to the local cache
acf_get_local_field( $key )Retrieving a local field
acf_remove_local_field( $key )Removing a local field

Some Examples

Here is a basic example illustrating how you can add a group of fields using PHP:

if( function_exists('acf_add_local_field_group') ):

acf_add_local_field_group(array (
	'key' => 'group_1',
	'title' => 'My Group',
	'fields' => array (
		array (
			'key' => 'field_1',
			'label' => 'Sub Title',
			'name' => 'sub_title',
			'type' => 'text',
			'prefix' => '',
			'instructions' => '',
			'required' => 0,
			'conditional_logic' => 0,
			'wrapper' => array (
				'width' => '',
				'class' => '',
				'id' => '',
			),
			'default_value' => '',
			'placeholder' => '',
			'prepend' => '',
			'append' => '',
			'maxlength' => '',
			'readonly' => 0,
			'disabled' => 0,
		)
	),
	'location' => array (
		array (
			array (
				'param' => 'post_type',
				'operator' => '==',
				'value' => 'post',
			),
		),
	),
	'menu_order' => 0,
	'position' => 'normal',
	'style' => 'default',
	'label_placement' => 'top',
	'instruction_placement' => 'label',
	'hide_on_screen' => '',
));

endif;

This code should be in the functions.php file of your theme (or ideally, a child theme). By the way – it’s likely that there will be no need to add all the settings you saw in the code above.

You can minimize the code and remove a number of settings so that ACF will use the default settings for those removed. The more minimal code looks like this:

if( function_exists('acf_add_local_field_group') ):

acf_add_local_field_group(array(
	'key' => 'group_1',
	'title' => 'My Group',
	'fields' => array (
		array (
			'key' => 'field_1',
			'label' => 'Sub Title',
			'name' => 'sub_title',
			'type' => 'text',
		)
	),
	'location' => array (
		array (
			array (
				'param' => 'post_type',
				'operator' => '==',
				'value' => 'post',
			),
		),
	),
));

endif;

It’s stated that in the above code, we also defined a group of fields and a field for that group of fields (the field is defined in lines 8 to 9). Similarly, you can add a group of fields and a field for that group separately.

In this way, you can define the field as a variable and add it to multiple groups of fields. Note that the variable $field must contain the definition parent which should be identical to the identifier of the field group or another parent field such as repater or flexible content.

if( function_exists('acf_add_local_field_group') ):

acf_add_local_field_group(array(
	'key' => 'group_1',
	'title' => 'My Group',
	'fields' => $field,
	'location' => array (
		array (
			array (
				'param' => 'post_type',
				'operator' => '==',
				'value' => 'post',
			),
		),
	),
));

$field = acf_add_local_field(array(
	'key' => 'field_1',
	'label' => 'Sub Title',
	'name' => 'sub_title',
	'type' => 'text',
	'parent' => 'group_1'
));

endif;

Adding ACF Field Groups via a Function

You can add the functions mentioned above directly to the functions.php file, but it is preferable to add them via the hook acf/init. This hook was added in version 5.2.7 of ACF and is the recommended way to use it.

The advantage of using this action is that the function will not run if the ACF plugin is not active for some reason or another, and therefore will not display an error in such cases.

function my_acf_add_local_field_groups() {
	
	acf_add_local_field_group(array(
		'key' => 'group_1',
		'title' => 'My Group',
		'fields' => array (
			array (
				'key' => 'field_1',
				'label' => 'Sub Title',
				'name' => 'sub_title',
				'type' => 'text',
			)
		),
		'location' => array (
			array (
				array (
					'param' => 'post_type',
					'operator' => '==',
					'value' => 'post',
				),
			),
		),
	));
	
}

add_action('acf/init', 'my_acf_add_local_field_groups');

Possible Settings for a Field Group

Here is a complete list of possible settings when creating a field group. If you are familiar with ACF, you will certainly notice that all the settings mentioned in the code below can also be changed in the editing of the ACF field group in the WordPress admin interface.

$group = array(
	
	/* (string) Unique identifier for field group. Must begin with 'group_' */
	'key' => 'group_1',
	
	/* (string) Visible in metabox handle */
	'title' => 'My Group',
	
	/* (array) An array of fields */
	'fields' => array(),
	
	/* (array) An array containing 'rule groups' where each 'rule group' is an array containing 'rules'. 
	Each group is considered an 'or', and each rule is considered an 'and'. */
	'location' => array(
		array(
			array(
				'param' => 'post_type',
				'operator' => '==',
				'value' => 'post',
			),
		),
	),
	
	/* (int) Field groups are shown in order from lowest to highest. Defaults to 0 */
	'menu_order' => 0,
	
	/* (string) Determines the position on the edit screen. Defaults to normal. Choices of 'acf_after_title', 'normal' or 'side' */
	'position' => 'normal',
	
	/* (string) Determines the metabox style. Defaults to 'default'. Choices of 'default' or 'seamless' */
	'style' => 'default',
	
	/* (string) Determines where field labels are places in relation to fields. Defaults to 'top'. 
	Choices of 'top' (Above fields) or 'left' (Beside fields) */
	'label_placement' => 'top',
	
	/* (string) Determines where field instructions are places in relation to fields. Defaults to 'label'. 
	Choices of 'label' (Below labels) or 'field' (Below fields) */
	'instruction_placement' => 'label',
	
	/* (array) An array of elements to hide on the screen */
	'hide_on_screen' => '',
);

Generic Settings for an Individual Field

In addition, here is a list of possible generic settings for an individual field. In addition to these settings, you will find later in the post the specific settings for each type of field in ACF in a convenient way…

$field = array (
	
	/* (string) Unique identifier for the field. Must begin with 'field_' */
	'key' => 'field_1',
	
	/* (string) Visible when editing the field value */
	'label' => 'Sub Title',
	
	/* (string) Used to save and load data. Single word, no spaces. Underscores and dashes allowed */
	'name' => 'sub_title',
	
	/* (string) Type of field (text, textarea, image, etc) */
	'type' => 'text',
	
	/* (string) Instructions for authors. Shown when submitting data */
	'instructions' => '',
	
	/* (int) Whether or not the field value is required. Defaults to 0 */
	'required' => 0,
	
	/* (mixed) Conditionally hide or show this field based on other field's values. 
	Best to use the ACF UI and export to understand the array structure. Defaults to 0 */
	'conditional_logic' => 0,
	
	/* (array) An array of attributes given to the field element */
	'wrapper' => array (
		'width' => '',
		'class' => '',
		'id' => '',
	),
	
	/* (mixed) A default value used by ACF if no value has yet been saved */
	'default_value' => '',
);

Settings According to Specific Field Type

And here is a complete list of additional settings for each type of field in ACF…

Basic

Text field settings

$text_field = array(
	
	/* ... Insert generic settings here ... */
	
	/* (string) Appears within the input. Defaults to '' */
	'placeholder' => '',
	
	/* (string) Appears before the input. Defaults to '' */
	'prepend' => '',
	
	/* (string) Appears after the input. Defaults to '' */
	'append' => '',
	
	/* (string) Restricts the character limit. Defaults to '' */
	'maxlength' => '',
	
	/* (bool) Makes the input readonly. Defaults to 0 */
	'readonly' => 0,
	
	/* (bool) Makes the input disabled. Defaults to 0 */
	'disabled' => 0,
	
);

Textarea field settings

$textarea_field = array(
	
	/* ... Insert generic settings here ... */
	
	/* (string) Appears within the input. Defaults to '' */
	'placeholder' => '',
	
	/* (string) Restricts the character limit. Defaults to '' */
	'maxlength' => '',
	
	/* (int) Restricts the number of rows and height. Defaults to '' */
	'rows' => '',
	
	/* (new_lines) Decides how to render new lines. Detauls to 'wpautop'.
	Choices of 'wpautop' (Automatically add paragraphs), 'br' (Automatically add <br>) or '' (No Formatting) */
	'new_lines' => '',
	
	/* (bool) Makes the input readonly. Defaults to 0 */
	'readonly' => 0,
	
	/* (bool) Makes the input disabled. Defaults to 0 */
	'disabled' => 0,
	
);

Number field settings

$number_field = array(
	
	/* ... Insert generic settings here ... */
	
	/* (string) Appears within the input. Defaults to '' */
	'placeholder' => '',
	
	/* (string) Appears before the input. Defaults to '' */
	'prepend' => '',
	
	/* (string) Appears after the input. Defaults to '' */
	'append' => '',
	
	/* (int) Minimum number value. Defaults to '' */
	'min' => '',
	
	/* (int) Maximum number value. Defaults to '' */
	'max' => '',
	
	/* (int) Step size increments. Defaults to '' */
	'step' => '',
	
);

Email field settings

$email_field = array(
	
	/* ... Insert generic settings here ... */
	
	/* (string) Appears within the input. Defaults to '' */
	'placeholder' => '',
	
	/* (string) Appears before the input. Defaults to '' */
	'prepend' => '',
	
	/* (string) Appears after the input. Defaults to '' */
	'append' => '',
	
);

Url field settings

$url_field = array(
	
	/* ... Insert generic settings here ... */
	
	/* (string) Appears within the input. Defaults to '' */
	'placeholder' => '',
	
);

Password field settings

$password_field = array(
	
	/* ... Insert generic settings here ... */
	
	/* (string) Appears within the input. Defaults to '' */
	'placeholder' => '',
	
	/* (string) Appears before the input. Defaults to '' */
	'prepend' => '',
	
	/* (string) Appears after the input. Defaults to '' */
	'append' => '',
	
);

Content

WYSIWYG field settings

$wysiwyg_field = array(
	
	/* ... Insert generic settings here ... */
	
	/* (string) Specify which tabs are available. Defaults to 'all'.
	Choices of 'all' (Visual & Text), 'visual' (Visual Only) or text (Text Only) */
	'tabs' => 'all',
	
	/* (string) Specify the editor's toolbar. Defaults to 'full'.
	Choices of 'full' (Full), 'basic' (Basic) or a custom toolbar (https://www.advancedcustomfields.com/resources/customize-the-wysiwyg-toolbars/) */
	'toolbar' => 'full',
	
	/* (bool) Show the media upload button. Defaults to 1 */
	'media_upload' => 1,
	
);

oEmbed field settings

$oembed_field = array(
	
	/* ... Insert generic settings here ... */
	
	/* (int) Specify the width of the oEmbed element. Can be overridden by CSS */
	'width' => '',
	
	/* (int) Specify the height of the oEmbed element. Can be overridden by CSS */
	'height' => '',
	
);

Image field settings

$image_field = array(
	
	/* ... Insert generic settings here ... */
	
	/* (string) Specify the type of value returned by get_field(). Defaults to 'array'.
	Choices of 'array' (Image Array), 'url' (Image URL) or 'id' (Image ID) */
	'return_format' => 'array',
	
	/* (string) Specify the image size shown when editing. Defaults to 'thumbnail'. */
	'preview_size' => 'thumbnail',
	
	/* (string) Restrict the image library. Defaults to 'all'.
	Choices of 'all' (All Images) or 'uploadedTo' (Uploaded to post) */
	'library' => 'all',
	
	/* (int) Specify the minimum width in px required when uploading. Defaults to 0 */
	'min_width' => 0,
	
	/* (int) Specify the minimum height in px required when uploading. Defaults to 0 */
	'min_height' => 0,
	
	/* (int) Specify the minimum filesize in MB required when uploading. Defaults to 0 
	The unit may also be included. eg. '256KB' */
	'min_size' => 0,
	
	/* (int) Specify the maximum width in px allowed when uploading. Defaults to 0 */
	'max_width' => 0,
	
	/* (int) Specify the maximum height in px allowed when uploading. Defaults to 0 */
	'max_height' => 0,
	
	/* (int) Specify the maximum filesize in MB in px allowed when uploading. Defaults to 0
	The unit may also be included. eg. '256KB' */
	'max_size' => 0,
	
	/* (string) Comma separated list of file type extensions allowed when uploading. Defaults to '' */
	'mime_types' => '',
	
);

File field settings

$file_field = array(
	
	/* ... Insert generic settings here ... */
	
	/* (string) Specify the type of value returned by get_field(). Defaults to 'array'.
	Choices of 'array' (File Array), 'url' (File URL) or 'id' (File ID) */
	'return_format' => 'array',
	
	/* (string) Specify the file size shown when editing. Defaults to 'thumbnail'. */
	'preview_size' => 'thumbnail',
	
	/* (string) Restrict the file library. Defaults to 'all'.
	Choices of 'all' (All Files) or 'uploadedTo' (Uploaded to post) */
	'library' => 'all',
		
	/* (int) Specify the minimum filesize in MB required when uploading. Defaults to 0 
	The unit may also be included. eg. '256KB' */
	'min_size' => 0,
		
	/* (int) Specify the maximum filesize in MB in px allowed when uploading. Defaults to 0
	The unit may also be included. eg. '256KB' */
	'max_size' => 0,
	
	/* (string) Comma separated list of file type extensions allowed when uploading. Defaults to '' */
	'mime_types' => '',
	
);

Gallery field settings

$gallery_field = array(
	
	/* ... Insert generic settings here ... */
	
	/* (int) Specify the minimum attachments required to be selected. Defaults to 0 */
	'min' => 0,
	
	/* (int) Specify the maximum attachments allowed to be selected. Defaults to 0 */
	'max' => 0,
	
	/* (string) Specify the image size shown when editing. Defaults to 'thumbnail'. */
	'preview_size' => 'thumbnail',
	
	/* (string) Restrict the image library. Defaults to 'all'.
	Choices of 'all' (All Images) or 'uploadedTo' (Uploaded to post) */
	'library' => 'all',
	
	/* (int) Specify the minimum width in px required when uploading. Defaults to 0 */
	'min_width' => 0,
	
	/* (int) Specify the minimum height in px required when uploading. Defaults to 0 */
	'min_height' => 0,
	
	/* (int) Specify the minimum filesize in MB required when uploading. Defaults to 0 
	The unit may also be included. eg. '256KB' */
	'min_size' => 0,
	
	/* (int) Specify the maximum width in px allowed when uploading. Defaults to 0 */
	'max_width' => 0,
	
	/* (int) Specify the maximum height in px allowed when uploading. Defaults to 0 */
	'max_height' => 0,
	
	/* (int) Specify the maximum filesize in MB in px allowed when uploading. Defaults to 0
	The unit may also be included. eg. '256KB' */
	'max_size' => 0,
	
	/* (string) Comma separated list of file type extensions allowed when uploading. Defaults to '' */
	'mime_types' => '',
	
);

Choice

Select field settings

$select_field = array(
	
	/* ... Insert generic settings here ... */
	
	/* (array) Array of choices where the key ('red') is used as value and the value ('Red') is used as label */
	'choices' => array(
		'red'	=> 'Red'
	),
	
	/* (bool) Allow a null (blank) value to be selected. Defaults to 0 */
	'allow_null' => 0,
	
	/* (bool) Allow mulitple choices to be selected. Defaults to 0 */
	'multiple' => 0,
	
	/* (bool) Use the select2 interfacte. Defaults to 0 */
	'ui' => 0,
	
	/* (bool) Load choices via AJAX. The ui setting must also be true for this to work. Defaults to 0 */
	'ajax' => 0,
	
	/* (string) Appears within the select2 input. Defaults to '' */
	'placeholder' => '',
	
);

Checkbox field settings

$checkbox_field = array(
	
	/* ... Insert generic settings here ... */
	
	/* (array) Array of choices where the key ('red') is used as value and the value ('Red') is used as label */
	'choices' => array(
		'red'	=> 'Red'
	),
	
	/* (string) Specify the layout of the checkbox inputs. Defaults to 'vertical'.
	Choices of 'vertical' or 'horizontal' */
	'layout' => 0,
	
);

Radio field settings

$radio_field = array(
	
	/* ... Insert generic settings here ... */
	
	/* (array) Array of choices where the key ('red') is used as value and the value ('Red') is used as label */
	'choices' => array(
		'red'	=> 'Red'
	),
	
	/* (bool) Allow a custom choice to be entered via a text input */
	'other_choice' => 0,
	
	/* (bool) Allow the custom value to be added to this field's choices. Defaults to 0.
	Will not work with PHP registered fields, only DB fields */
	'save_other_choice' => 0,
	
	/* (string) Specify the layout of the checkbox inputs. Defaults to 'vertical'.
	Choices of 'vertical' or 'horizontal' */
	'layout' => 0,
	
);

True / False field settings

$true_false_field = array(
	
	/* ... Insert generic settings here ... */
	
	/* (string) Text shown along side the checkbox */
	'message' => 0,
	
);

Relational Fields

Post Object field settings

$post_object_field = array(
	
	/* ... Insert generic settings here ... */
	
	/* (mixed) Specify an array of post types to filter the available choices. Defaults to '' */
	'post_type' => '',
	
	/* (mixed) Specify an array of taxonomies to filter the available choices. Defaults to '' */
	'taxonomy' => '',
	
	/* (bool) Allow a null (blank) value to be selected. Defaults to 0 */
	'allow_null' => 0,
	
	/* (bool) Allow mulitple choices to be selected. Defaults to 0 */
	'multiple' => 0,
	
	/* (string) Specify the type of value returned by get_field(). Defaults to 'object'.
	Choices of 'object' (Post object) or 'id' (Post ID) */
	'return_format' => 'object',
	
);

Page Link field settings

$page_link_field = array(
	
	/* ... Insert generic settings here ... */
	
	/* (mixed) Specify an array of post types to filter the available choices. Defaults to '' */
	'post_type' => '',
	
	/* (mixed) Specify an array of taxonomies to filter the available choices. Defaults to '' */
	'taxonomy' => '',
	
	/* (bool) Allow a null (blank) value to be selected. Defaults to 0 */
	'allow_null' => 0,
	
	/* (bool) Allow mulitple choices to be selected. Defaults to 0 */
	'multiple' => 0,
	
);

Relationship field settings

$relationship_field = array(
	
	/* ... Insert generic settings here ... */
	
	/* (mixed) Specify an array of post types to filter the available choices. Defaults to '' */
	'post_type' => '',
	
	/* (mixed) Specify an array of taxonomies to filter the available choices. Defaults to '' */
	'taxonomy' => '',
	
	/* (array) Specify the available filters used to search for posts.
	Choices of 'search' (Search input), 'post_type' (Post type select) and 'taxonomy' (Taxonomy select) */
	'filters' => array('search', 'post_type', 'taxonomy'),
	
	/* (array) Specify the visual elements for each post.
	Choices of 'featured_image' (Featured image icon) */
	'elements' => array(),
	
	/* (int) Specify the minimum posts required to be selected. Defaults to 0 */
	'min' => 0,
	
	/* (int) Specify the maximum posts allowed to be selected. Defaults to 0 */
	'max' => 0,
	
	/* (string) Specify the type of value returned by get_field(). Defaults to 'object'.
	Choices of 'object' (Post object) or 'id' (Post ID) */
	'return_format' => 'object',
	
);

Taxonomy field settings

$taxonomy_field = array(
	
	/* ... Insert generic settings here ... */
	
	/* (string) Specify the taxonomy to select terms from. Defaults to 'category' */
	'taxonomy' => '',
	
	/* (array) Specify the appearance of the taxonomy field. Defaults to 'checkbox'
	Choices of 'checkbox' (Checkbox inputs), 'multi_select' (Select field - multiple), 'radio' (Radio inputs) or 'select' (Select field) */
	'field_type' => 'checkbox',
	
	/* (bool) Allow a null (blank) value to be selected. Defaults to 0 */
	'allow_null' => 0,
	
	/* (bool) Allow selected terms to be saved as relatinoships to the post */
	'load_save_terms' 	=> 0,
	
	/* (string) Specify the type of value returned by get_field(). Defaults to 'id'.
	Choices of 'object' (Term object) or 'id' (Term ID) */
	'return_format'		=> 'id',
	
	/* (bool) Allow new terms to be added via a popup window */
	'add_term'			=> 1
	
);

User field settings

$user_field = array(
	
	/* ... Insert generic settings here ... */
	
	/* (array) Array of roles to limit the users available for selection */
	'role' => array(),
	
	/* (bool) Allow a null (blank) value to be selected. Defaults to 0 */
	'allow_null' => 0,
	
	/* (bool) Allow mulitple choices to be selected. Defaults to 0 */
	'multiple' => 0,
	
);

In Summary

If you are working with several development environments, there is no doubt that you should register fields in Advanced Custom Fields using PHP or through the functionality of Local JSON, this is definitely the most convenient way in these situations.

Moreover, in terms of optimization and speed of WordPress sites, these two options are preferable over adding the fields through the ACF admin interface and will save quite a few database reads that affect site performance – even if minimally.

If you have insights about the differences between Local JSON and registration via PHP or any comments about the subject of the post, feel free to share with us in the comments below…. 🙂

Roee Yossef
Roee Yossef

I develop pixel-perfect custom WordPress themes, delivering high-performance, SEO-optimized websites. Have a project in mind? need assistance? Feel free to contact me!

0 Comments...

Leave a Comment

To add code, use the buttons below. For instance, click the PHP button to insert PHP code within the shortcode. If you notice any typos, please let us know!