Creating Custom ACF Fields
Creating custom field types in Advanced Custom Fields (ACF) allows you to build tailored, reusable components for editors in the WordPress admin interface. These fields enhance the flexibility of your theme by making UI decisions more visual and standardized.
Rather than relying on default ACF fields, custom ones like Section Spacing, Message, or Background Color Selector let developers define complex logic, interactions, and styles directly in the editing interface.
⚠️ Warning: Creating or modifying custom ACF fields requires understanding of both PHP and the ACF API, as well as coordination with frontend styling and JavaScript. If you’re not sure where to start, talk to Eli or Nerea — they are the original authors of these fields and can guide you properly.
📐 Example 1: Section Spacing Field
Section titled “📐 Example 1: Section Spacing Field”Purpose: This field allows content editors to visually control spacing around sections (e.g., top padding, bottom margin) directly from the backend.
It consists of:
- A
init.php
that registers the field. - A
class-PREFIX-acf-field-spacing.php
that handles rendering, logic, and asset loading. - A set of supporting JS/CSS and images for the spacing UI.
👉 In the UI, the field presents visual buttons and previews to let editors pick between spacing configurations such as “Top & Bottom - Large”, “Bottom only”, etc.
💬 Example 2: Message Field
Section titled “💬 Example 2: Message Field”Purpose: This field provides a custom message or placeholder for users in the backend. It’s useful for internal notes or visual delimiters between field groups.
It includes:
- A
init.php
for registration. - A corresponding PHP class with optional JS/CSS (even if not used here, the structure is maintained).
- Label, version, and localization metadata.
Although simple, this type provides a flexible way to guide content editors with inline messages.
🎨 Example 3: Light Background Selector
Section titled “🎨 Example 3: Light Background Selector”Purpose: Allows editors to choose between predefined light background color classes for visual modules.
Includes:
- A dropdown with swatches (e.g., white, grey).
- Custom CSS for color previews.
- Custom JS to bind selection values to the field.
It enhances UX by replacing plain select fields with visual options and ensures design consistency across modules.
📦 File Structure (Common to All)
Section titled “📦 File Structure (Common to All)”Each custom field typically includes:
init.php
— registers the field during WordPressinit
.class-PREFIX-acf-field-NAME.php
— handles logic, admin rendering, field settings.assets/js/fields-v1.js
— for interactivity in the ACF interface.assets/css/field.css
— for admin styling.- Optional images or icons (for visual UI, e.g., spacing diagrams).
🧠 Pro Tips Before You Build or Modify
Section titled “🧠 Pro Tips Before You Build or Modify”- Review existing projects — most of these fields already exist in active themes.
- Understand the field behavior — spacing, background, and message fields often require tight integration between backend PHP, frontend JS, and CSS.
- Always reuse when possible — these components are modular for a reason.
- Consult with Eli or Nerea before building or changing anything — they are the original creators and have deep knowledge of how these fields work.
🔎 In-depth Example: Background Color Selector
Section titled “🔎 In-depth Example: Background Color Selector”To create a custom ACF block, we’ll break down the code into several components. Here’s the basic process for creating a new field like background color:
Step 1: Defining the Field Type
Section titled “Step 1: Defining the Field Type”We start by defining the custom ACF field type class. This is the core logic for how the field behaves in the ACF interface.
class PREFIX_acf_field_backgroundcolor extends \acf_field{ public $show_in_rest = true; // Allows the field to be visible in the REST API.
private $env; // Store environment variables like plugin or theme context.
public function __construct() { $this->name = 'backgroundcolor'; // The field name used in PHP and JS code. $this->label = __('Background Color', 'TEXTDOMAIN'); // The label shown in the ACF field settings. $this->category = 'basic'; // The category where the field appears in the ACF field type picker. $this->defaults = array('font_size' => 14); // Default settings for the field. $this->l10n = array('error' => __('Error! Please enter a higher value', 'TEXTDOMAIN')); // Localization strings.
$this->env = array( 'url' => site_url(str_replace(ABSPATH, '', __DIR__)), // URL to the field’s directory. 'version' => '1.0', // Version number of the theme or plugin. );
parent::__construct(); }}
In this part:
- The name is the identifier of the field (used in the PHP/JS code).
- The label is what will be displayed in the admin interface.
- The category groups the field within the ACF field types.
Step 2: Rendering Field Settings
Section titled “Step 2: Rendering Field Settings”Next, we define what settings will appear when the user configures the field in the ACF admin interface.
public function render_field_settings($field){ // Here you can add additional field settings. // For example, you could add font size or custom options for this field type.}
In this function, you can render additional settings that the user will interact with when configuring the field. For example, you could allow users to choose which colors are available in the dropdown.
Step 3: Rendering the Field on the Edit Screen
Section titled “Step 3: Rendering the Field on the Edit Screen”Now, we define how the field will appear on the edit screen when users are creating or editing a post.
public function render_field($field){ ?> <div class="dropdown-color js--background-color"> <div class="selected"> <a href="#"><span>Please select</span></a> </div> <div class="options js--select-background-color"> <ul> <li value="primary"><a href="#" class="c--color-bg-a" data-value="f--background-a"> <div></div>White </a></li> <li><a href="#" data-value="f--background-b" class="c--color-bg-a c--color-bg--grey"> <div></div>Grey </a></li> </ul> </div> </div>
<input type="hidden" class="setting-font-size js--background-color" name="<?php echo esc_attr($field['name']) ?>" value="<?php echo esc_attr($field['value']) ?>" /> <?php}
In this part, we create a dropdown color selector for the user to pick a background color. The selected color will be stored as the field’s value.
Step 4: Enqueueing Scripts and Styles
Section titled “Step 4: Enqueueing Scripts and Styles”To make the field interactive (with dropdowns, color selection, etc.), we need to enqueue custom JavaScript and CSS.
public function input_admin_enqueue_scripts(){ $url = trailingslashit($this->env['url']); $version = date("F j, Y, g:i a");
wp_register_script( 'PREFIX-backgroundcolor', "{$url}assets/js/background-color.js", array('acf-input'), $version ); wp_register_style( 'PREFIX-backgroundcolor', "{$url}assets/css/background-color.css", array('acf-input'), $version );
wp_enqueue_script('PREFIX-backgroundcolor'); wp_enqueue_style('PREFIX-backgroundcolor');}
Here, we link to the custom JS and CSS files that make the dropdown color selector functional and styled. The script will handle the interactivity of the field (e.g., showing/hiding the dropdown when clicked).
Step 5: Registering the Field
Section titled “Step 5: Registering the Field”Finally, we register the new field type with ACF so that it can be used in the WordPress admin.
add_action('init', 'PREFIX_include_acf_field_backgroundcolor');
function PREFIX_include_acf_field_backgroundcolor(){ if (!function_exists('acf_register_field_type')) { return; } require_once __DIR__ . '/class-PREFIX-acf-field-backgroundcolor.php'; acf_register_field_type('PREFIX_acf_field_backgroundcolor');}
This function tells WordPress to include our custom field and register it with ACF, making it available for use in the admin interface.
🎮 Custom JavaScript for the Color Selector
Section titled “🎮 Custom JavaScript for the Color Selector”Here’s the accompanying JavaScript that controls the dropdown behavior and the color selection:
(function ($) { function getColorName(className) { switch (className) { case "f--background-a": return "White"; case "f--background-b": return "Grey"; default: return "Select a background color"; } }
function initialize_field($field) { $.each($($field.find(".js--background-color")), function () { var selector = $(this).find(".options ul"); var selectorSpan = $(this).find(".selected a span");
$(this).find(".selected a").click(function () { selector.toggle(); });
$(this).find("ul li a").click(function () { $field.find("input").val($(this).attr("data-value")); selectorSpan.html(`<div class="${$(this).attr("data-value")}">` + getColorName($field.find("input").val()) + "</div>"); selector.hide(); });
if ($field.find("input").val()) { selectorSpan.html(`<div class="${$field.find("input").val()}">` + getColorName($field.find("input").val()) + "</div>"); } }); }
if (typeof acf.add_action !== "undefined") { acf.add_action("ready_field/type=backgroundcolor", initialize_field); acf.add_action("append_field/type=backgroundcolor", initialize_field); }})(jQuery);
This script manages the interactivity of the color selector, showing and hiding the color options, and setting the selected color as the field’s value.
🎨 Custom CSS
Section titled “🎨 Custom CSS”Custom CSS defines the visual styles for the background color selector, including the colors for the options. This CSS ensures the field is displayed correctly in the ACF editor. Here’s an example of the custom CSS:
/* Custom styles for the background color field */.js--background-color .selected a { display: flex; align-items: center;}
.c--color-bg-a div, .c--color-bg-b div { width: 20px; height: 20px; margin-right: 10px;}
.c--color-bg-a { background-color: white;}
.c--color-bg-b { background-color: grey;}
.options ul { display: none; list-style-type: none; padding: 0;}
.options ul li { padding: 10px; cursor: pointer;}
This CSS handles the color selection interface, ensuring it looks clean and functional in the ACF editor.
🧠 Custom ACF fields are powerful tools that, when used properly, bring great value to both developers and editors. Take advantage of what’s been built — but handle with care.