Advanced Custom Fields (ACF) is one of the most popular tools for adding custom fields to WordPress. When working on a project where ACF fields need to be stored in a code repository (e.g., Git), there are several ways to manage them. Below, we discuss four main methods: saving JSON files in the theme, saving JSON files in any location, registering fields via PHP code, and using PHP libraries.
JSON files in the active theme directory
ACF allows you to save field configurations in JSON files automatically. This solution lets you store field settings directly in the repository, particularly useful when working in teams or across multiple environments.
To save fields in JSON files within the theme, all you need to do is to create acf-json directory in your theme.
JSON files in any location
If you want to save JSON files in a location other than the theme, such as in a plugin-specific directory or a special folder in the project, you can customize the previous solution:
add_filter('acf/settings/save_json', function ($path) {
// Define your custom path to save JSON files
$path = WP_CONTENT_DIR . '/acf-json';
return $path;
});
add_filter('acf/settings/load_json', function ($paths) {
// Define your custom path to load JSON files
unset($paths[0]);
$paths[] = WP_CONTENT_DIR . '/acf-json';
return $paths;
});
This allows JSON files to be saved and loaded from any defined location, which can be useful when you want them to be independent of the theme.
Starting from ACF version 6.2, there are several modifiers available for the acf/settings/save_json filter, allowing you to set different save paths for various types of files:
acf/settings/save_json/key={$key}: Refers to the field group, post type, taxonomy, or UI options page key.acf/settings/save_json/name={$name}: Refers to the name of the field group, post type, taxonomy, or UI options page.acf/settings/save_json/type={$post_type}: Refers to the type, such asacf-field-group,acf-post-type,acf-taxonomy, oracf-ui-options-page.
These filters enable precise control over where JSON files are saved, depending on their key, name, or type. When multiple paths match the same file, the most specific path takes precedence, meaning that the acf/settings/save_json/key={$key} filter will override the acf/settings/save_json/name={$name} filter, and so on.
For example, you can ensure all ACF custom post types save to a designated folder using this filter:
function my_acf_cpt_save_folder( $path ) {
return get_stylesheet_directory() . '/acf-json/post-types';
}
add_filter( 'acf/settings/save_json/type=acf-post-type', 'my_acf_cpt_save_folder' );
Additionally, ACF 6.2 introduced a new filter, acf/json/save_paths, with two parameters: an array of potential save paths for the file and an array of settings for the field group, post type, taxonomy, or options page. This allows you to use one function to manage multiple items and adjust the save path conditionally, for instance, based on the item’s name:
function custom_acf_json_save_paths( $paths, $post ) {
if ( $post['title'] === 'Theme Settings' ) {
$paths = array( get_stylesheet_directory() . '/options-pages' );
}
if ( $post['title'] === 'Theme Settings Fields' ) {
$paths = array( get_stylesheet_directory() . '/field-groups' );
}
return $paths;
}
add_filter( 'acf/json/save_paths', 'custom_acf_json_save_paths', 10, 2 );
If you define custom save paths and want ACF to load files from those paths, ensure that the paths are also added to the acf/settings/load_json filter.
To customize the filename of saved JSON files, you can use the new acf/json/save_file_name filter. For example, you can modify the filename to reflect the name of the field group, post type, or taxonomy:
function custom_acf_json_filename( $filename, $post, $load_path ) {
$filename = str_replace(
array(' ', '_'),
array('-', '-'),
$post['title']
);
$filename = strtolower( $filename ) . '.json';
return $filename;
}
add_filter( 'acf/json/save_file_name', 'custom_acf_json_filename', 10, 3 );
Pros
- you can use the UI for editing ACF fields
Cons
- devs can modify the JSON directly, which is not the correct way
- devs can synchronize fields on different environments – on the local env should be synchronized
- deleted JSON file can be restored by devs if it was synchronized with the local database
Registering fields via PHP Code
Another solution is to register ACF fields directly through PHP code. ACF provides the option to register fields using PHP functions, giving you full control over field configurations in the code.
ACF documentation offers detailed instructions on how to do this: Register Fields via PHP.
Here’s an example:
if (function_exists('acf_add_local_field_group')) {
acf_add_local_field_group(array(
'key' => 'group_1',
'title' => 'My Custom Fields',
'fields' => array(
array(
'key' => 'field_1',
'label' => 'Custom Field',
'name' => 'custom_field',
'type' => 'text',
),
),
'location' => array(
array(
array(
'param' => 'post_type',
'operator' => '==',
'value' => 'post',
),
),
),
));
}
The advantage of this approach is that all fields are stored directly in the code, making them more readable and easier to version control, though it requires familiarity with ACF field structures.
Using PHP Libraries, e.g., ACF Builder
If you prefer a more structured approach to creating fields, you can use PHP libraries such as ACF Builder. This library allows for more readable field definitions using object-oriented syntax.
Example using ACF Builder:
use StoutLogic\AcfBuilder\FieldsBuilder;
$builder = new FieldsBuilder('custom_fields');
$builder
->addText('custom_field', [
'label' => 'Custom Field',
]);
add_action('acf/init', function() use ($builder) {
acf_add_local_field_group($builder->build());
});
This approach offers greater flexibility and better code organization, especially in large projects where creating many fields can become complex.
Summary
Each of these solutions has its pros and cons, and the right choice depends on the specifics of your project and team preferences. Here’s a brief summary:
- JSON files in the theme – Quick integration, use of UI to create fields, convenient synchronization across environments, but dependent on the theme.
- JSON Files in Any Location – Greater flexibility in managing files, use of ACF UI, independent of the theme.
- Registering Fields via PHP – Full control over fields in the code, harder to manage for non-technical users, and need to learn the ACF syntax.
- PHP Libraries, e.g., ACF Builder – Better organization and flexibility, particularly in larger projects, but need to learn a new tool.
These methods make it easy to store and version ACF fields in a repository, simplifying team collaboration on the project.
If you consider using JSON files, make sure that fields won’t be synchronized on environments different than local. You can disable ACF interface with a simple code:
add_filter('acf/settings/show_admin', function(){
return wp_get_environment_type() === 'development';
});