Advanced Custom Fields 文档
Advanced Custom Fields 官方资源文档,介绍字段、区块与常用 API。
Abilities API Integration
Enables AI tools and automation platforms to interact with ACF data through the WordPress Abilities API.
Description
ACF 6.8 introduces support for the WordPress Abilities API (introduced in WordPress 6.9). This integration exposes ACF’s schema and data through a machine-readable interface, allowing compatible external tools to discover and manipulate ACF field groups, custom post types, taxonomies, and their associated content.
See the ACF 6.8 release post for an overview.
Requirements
WordPress 6.9 or later
ACF 6.8 or later
MCP Adapter plugin or another MCP server implementation
MCP-compatible client (Claude Desktop, Cursor, etc.)
Setup
Enable the Abilities API
Add this filter to your theme’s
functions.php or a custom plugin:
add_filter( 'acf/settings/enable_acf_ai', '__return_true' );
Configure AI Access
Once enabled, a new “ACF AI” settings tab appears in the WordPress admin. From here you can:
Enable/disable AI access globally
Configure which item types allow AI access
Set AI descriptions to help AI understand your content structure
Per-Item AI Access
For existing items (field groups, post types, taxonomies), AI access is disabled by default and requires manual opt-in. New items created after enabling the feature have AI access enabled automatically.
To enable AI access for an existing item:
Edit the field group, post type, or taxonomy
Navigate to the “Settings” tab
Enable “Allow AI Access”
Optionally add an “AI Description” to provide context
Available Abilities
Field Group Abilities
Ability
Description
acf/field-groups
List all field groups that allow AI access
acf/create-field-group
Create a new field group with fields and location rules
Custom Post Type Abilities
Ability
Description
acf/custom-post-types
List all ACF-registered custom post types
acf/create-custom-post-type
Create a new custom post type
acf/{post-type}s
Query posts of a specific type
acf/create-{post-type}
Create a new post
acf/view-{post-type}
Retrieve a single post
acf/update-{post-type}
Update an existing post
acf/delete-{post-type}
Delete a post
Custom Taxonomy Abilities
Ability
Description
acf/custom-taxonomies
List all ACF-registered taxonomies
acf/create-custom-taxonomy
Create a new taxonomy
acf/{taxonomy}s
Query terms
acf/create-{taxonomy}
Create a new term
acf/view-{taxonomy}
Retrieve a single term
acf/update-{taxonomy}
Update an existing term
acf/delete-{taxonomy}
Delete a term
Ability Categories
ACF registers two ability categories:
acf-field-management: Abilities for managing field groups, post types, and taxonomies
wordpress-content-discovery: Abilities for discovering content types and structure
Permissions
All abilities respect WordPress user permissions. The executing user must have the ACF capability (default:
manage_options) to access abilities.
Example Use Cases
AI-Assisted Content Modeling
AI tools can inspect existing field structures and suggest or create new field groups based on content requirements.
"Create a field group for a Recipe post type with fields for ingredients, cooking time, difficulty level, and instructions."
Programmatic Content Import
Import structured data (CSV, JSON) as WordPress content with proper field validation.
"Import this CSV of products into the Products post type, mapping columns to ACF fields."
Bulk Operations
Update ACF field values across multiple posts while respecting validation rules.
"Update all Events with a past date to set their status field to 'archived'."
Rapid Prototyping
Automatically generate demo sites with realistic content structures.
"Set up a real estate site with property listings, agents, and neighborhood taxonomies."
Notes
AI access is opt-in per item to ensure sensitive data is not exposed unintentionally
All operations are logged and respect WordPress audit trails
The API uses JSON Schema for input/output validation
Destructive operations (delete) require explicit confirmation annotations
Ability: acf/create-custom-post-type
Creates a new custom post type in ACF.
Description
Creates a new custom post type using ACF’s post type registration system. The post type is registered with WordPress and optionally enabled for AI access.
Input
{
"post_type": "product",
"label": "Product",
"plural_label": "Products"
}
Required Properties
post_type
(string) The post type key/slug. Must be lowercase alphanumeric with underscores or hyphens. Maximum 20 characters.
label
(string) The singular label for the post type.
plural_label
(string) The plural label for the post type.
Optional Properties
description
(string) Description of the post type.
public
(boolean) Whether the post type is publicly accessible. Default:
true
hierarchical
(boolean) Whether the post type supports parent/child relationships (like Pages). Default:
false
supports
(array) Features the post type supports. Can be an array of strings or an object with boolean values.
Available supports:
–
title: Post title
–
editor: Content editor
–
author: Author selection
–
thumbnail: Featured image
–
excerpt: Post excerpt
–
comments: Comments
–
trackbacks: Trackbacks
–
revisions: Revision history
–
page-attributes: Page attributes (menu order, parent)
–
custom-fields: Custom fields metabox
–
post-formats: Post formats
show_in_rest
(boolean) Whether to expose in the REST API. Required for block editor and AI abilities. Default:
true
rest_base
(string) Custom REST API base path. Defaults to post type key.
has_archive
(boolean) Whether the post type has an archive page. Default:
false
has_archive_slug
(string) Custom slug for the archive page.
menu_icon
(string|object) Admin menu icon. Can be a dashicon class (e.g.,
dashicons-cart), image URL, or object with
type and
value.
menu_position
(integer) Position in the admin menu. Values 5-100.
taxonomies
(array) Array of taxonomy slugs to associate with this post type.
allow_ai_access
(boolean) Whether to allow AI access to this post type. Default:
true
ai_description
(string) Description to help AI understand the purpose of this post type.
Output
{
"success": true,
"post_type": {
"post_type": "product",
"label": "Product",
"plural_label": "Products",
"public": true,
"show_in_rest": true,
"allow_ai_access": true
},
"message": "Custom post type 'product' created successfully."
}
Annotations
Annotation
Value
readonly
false
destructive
false
idempotent
false
Permissions
Requires the ACF capability (default:
manage_options).
Example
Create a Team Member post type:
{
"post_type": "team_member",
"label": "Team Member",
"plural_label": "Team Members",
"description": "Staff and team member profiles",
"public": true,
"supports": ["title", "editor", "thumbnail"],
"has_archive": true,
"menu_icon": "dashicons-groups",
"menu_position": 25,
"allow_ai_access": true,
"ai_description": "Team member profiles with bio, role, and contact information"
}
Response:
{
"success": true,
"post_type": {
"post_type": "team_member",
"label": "Team Member",
"plural_label": "Team Members",
"description": "Staff and team member profiles",
"public": true,
"hierarchical": false,
"supports": ["title", "editor", "thumbnail"],
"show_in_rest": true,
"has_archive": true,
"menu_icon": "dashicons-groups",
"menu_position": 25,
"allow_ai_access": true,
"ai_description": "Team member profiles with bio, role, and contact information"
},
"message": "Custom post type 'team_member' created successfully."
}
Errors
Error
Cause
Invalid post type key
Key contains invalid characters or exceeds 20 characters
Post type already exists
A post type with this key is already registered
Missing required field
post_type,
label, or
plural_label not provided
Notes
Post type keys must be unique across WordPress
Reserved post type keys (
post,
page,
attachment, etc.) cannot be used
The post type is immediately registered and available in the admin
Dynamic abilities (query, create, view, update, delete) are registered for post types with
show_in_rest and
allow_ai_access enabled
Ability: acf/create-custom-taxonomy
Creates a new custom taxonomy in ACF.
Description
Creates a new taxonomy using ACF’s taxonomy registration system. The taxonomy is registered with WordPress and optionally enabled for AI access.
Input
{
"taxonomy": "product_category",
"label": "Product Category",
"plural_label": "Product Categories",
"post_types": ["product"]
}
Required Properties
taxonomy
(string) The taxonomy key/slug. Must be lowercase alphanumeric with underscores or hyphens. Maximum 32 characters.
label
(string) The singular label for the taxonomy.
plural_label
(string) The plural label for the taxonomy.
post_types
(array) Array of post type slugs to associate with this taxonomy.
Optional Properties
description
(string) Description of the taxonomy.
public
(boolean) Whether the taxonomy is publicly accessible. Default:
true
hierarchical
(boolean) Whether the taxonomy supports parent/child relationships (like categories). Default:
false (flat like tags)
show_in_rest
(boolean) Whether to expose in the REST API. Required for block editor and AI abilities. Default:
true
rest_base
(string) Custom REST API base path. Defaults to taxonomy key.
show_admin_column
(boolean) Whether to show a column in the post list table. Default:
false
allow_ai_access
(boolean) Whether to allow AI access to this taxonomy. Default:
true
ai_description
(string) Description to help AI understand the purpose of this taxonomy.
Output
{
"success": true,
"taxonomy": {
"taxonomy": "product_category",
"label": "Product Category",
"plural_label": "Product Categories",
"hierarchical": false,
"public": true,
"post_types": ["product"],
"show_in_rest": true,
"allow_ai_access": true
},
"message": "Custom taxonomy 'product_category' created successfully."
}
Annotations
Annotation
Value
readonly
false
destructive
false
idempotent
false
Permissions
Requires the ACF capability (default:
manage_options).
Example
Create a hierarchical Event Category taxonomy:
{
"taxonomy": "event_category",
"label": "Event Category",
"plural_label": "Event Categories",
"description": "Categories for organizing events",
"post_types": ["event"],
"hierarchical": true,
"show_admin_column": true,
"allow_ai_access": true,
"ai_description": "Hierarchical categories for event types (conferences, workshops, meetups)"
}
Response:
{
"success": true,
"taxonomy": {
"taxonomy": "event_category",
"label": "Event Category",
"plural_label": "Event Categories",
"description": "Categories for organizing events",
"hierarchical": true,
"public": true,
"post_types": ["event"],
"show_in_rest": true,
"show_admin_column": true,
"allow_ai_access": true,
"ai_description": "Hierarchical categories for event types (conferences, workshops, meetups)"
},
"message": "Custom taxonomy 'event_category' created successfully."
}
Errors
Error
Cause
Invalid taxonomy key
Key contains invalid characters or exceeds 32 characters
Taxonomy already exists
A taxonomy with this key is already registered
Missing required field
taxonomy,
label,
plural_label, or
post_types not provided
Invalid post type
One or more specified post types do not exist
Notes
Taxonomy keys must be unique across WordPress
Reserved taxonomy keys (
category,
post_tag, etc.) cannot be used
The taxonomy is immediately registered and available in the admin
Dynamic abilities (query, create, view, update, delete) are registered for taxonomies with
show_in_rest and
allow_ai_access enabled
Set
hierarchical: true for category-like taxonomies with parent/child support
Set
hierarchical: false for tag-like flat taxonomies
Ability: acf/create-field-group
Creates a new ACF field group with fields and location rules.
Description
Creates a new field group in ACF with the specified title, fields, and location rules. The field group is automatically enabled for AI access.
Input
{
"title": "Product Fields",
"fields": [
{
"label": "Price",
"name": "price",
"type": "number"
}
],
"location": [
[
{
"param": "post_type",
"operator": "==",
"value": "product"
}
]
]
}
Required Properties
title
(string) The title of the field group.
fields
(array) Array of field configurations. See Field Schema below.
location
(array) Location rules determining where the field group appears. See Location Schema below.
Optional Properties
description
(string) A description for this field group.
position
(string) Where to show the field group. Default:
normal
–
normal: Below the content editor
–
side: In the sidebar
–
acf_after_title: After the post title
style
(string) Field group style. Default:
default
–
default: Standard metabox
–
seamless: No metabox styling
label_placement
(string) Where to place field labels. Default:
top
–
top: Above the field
–
left: Beside the field
instruction_placement
(string) Where to show field instructions. Default:
label
–
label: Below the label
–
field: Below the field
hide_on_screen
(array) Items to hide from the edit screen. Options:
permalink,
the_content,
excerpt,
custom_fields,
discussion,
comments,
revisions,
slug,
author,
format,
page_attributes,
featured_image,
categories,
tags,
send-trackbacks
active
(boolean) Whether the field group is active. Default:
true
show_in_rest
(boolean) Whether to expose in REST API. Default:
true
allow_ai_access
(boolean) Whether to allow AI access. Default:
true
ai_description
(string) Description to help AI understand the purpose of this field group.
Field Schema
Each field in the
fields array supports these properties:
Property
Type
Required
Description
label
string
Yes
Human-readable field label
name
string
Yes
Field name (used in code)
type
string
Yes
Field type (see below)
instructions
string
No
Help text for editors
required
boolean
No
Whether field is required
default_value
mixed
No
Default value
placeholder
string
No
Placeholder text
conditional_logic
array
No
Conditional display rules
Supported Field Types
Basic:
text,
textarea,
number,
range,
email,
url,
password
Content:
image,
file,
wysiwyg,
oembed,
gallery
Choice:
select,
checkbox,
radio,
button_group,
true_false
Relational:
link,
post_object,
page_link,
relationship,
taxonomy,
user
Layout:
group,
repeater,
flexible_content,
clone
jQuery:
google_map,
date_picker,
date_time_picker,
time_picker,
color_picker
Location Schema
Location rules are nested arrays representing AND/OR logic:
[
[
{ "param": "post_type", "operator": "==", "value": "product" }
]
]
Outer array = OR groups, inner array = AND conditions within a group.
Location Parameters
Parameter
Description
post_type
Post type slug
post_template
Page template file
post_status
Post status
post_format
Post format
post_category
Category ID
post_taxonomy
Taxonomy term
page
Specific page ID
page_parent
Parent page ID
page_type
Page type (front, posts, top, parent, child)
user_form
User form (add, edit)
user_role
User role
taxonomy
Taxonomy screen
options_page
Options page slug
Operators
==: Is equal to
!=: Is not equal to
Output
{
"success": true,
"field_group": {
"ID": 123,
"key": "group_abc123def456",
"title": "Product Fields",
"fields": [...],
"location": [...],
"active": true,
"allow_ai_access": true
},
"field_group_id": 123,
"message": "Field group 'Product Fields' created successfully."
}
Annotations
Annotation
Value
readonly
false
destructive
false
idempotent
false
Permissions
Requires the ACF capability (default:
manage_options).
Example
Create a field group for an Event post type:
{
"title": "Event Details",
"fields": [
{
"label": "Event Date",
"name": "event_date",
"type": "date_picker",
"required": true
},
{
"label": "Event Time",
"name": "event_time",
"type": "time_picker"
},
{
"label": "Location",
"name": "location",
"type": "text",
"instructions": "Enter the venue name and address"
},
{
"label": "Ticket Price",
"name": "ticket_price",
"type": "number",
"default_value": 0
}
],
"location": [
[
{
"param": "post_type",
"operator": "==",
"value": "event"
}
]
],
"ai_description": "Fields for event scheduling and ticketing information"
}
Notes
Field keys are auto-generated if not provided
The field group key is auto-generated based on a unique identifier
Nested fields (repeater, group, flexible content) support the same field schema recursively
Invalid field types or configurations return a WP_Error
Ability: acf/custom-post-types
Lists all ACF-registered custom post types.
Description
Returns an array of custom post types that were created using ACF’s post type registration feature. Includes post types that have AI access enabled.
Input
This ability accepts no input parameters.
null
Output
{
"custom_post_types": [
{
"post_type": "product",
"label": "Product",
"plural_label": "Products",
"description": "Products available for purchase",
"public": true,
"hierarchical": false,
"show_in_rest": true,
"rest_base": "products",
"allow_ai_access": true,
"ai_description": "E-commerce products with pricing and inventory"
}
],
"count": 1,
"message": "Found 1 ACF custom post type(s)."
}
Output Properties
custom_post_types
(array) Array of post type configuration objects.
count
(integer) Total number of post types returned.
message
(string) Human-readable status message.
Post Type Properties
Property
Type
Description
post_type
string
Post type key/slug (max 20 characters)
label
string
Singular label
plural_label
string
Plural label
description
string
Post type description
public
boolean
Whether publicly accessible
hierarchical
boolean
Whether supports parent/child relationships
show_in_rest
boolean
Whether exposed in REST API
rest_base
string
REST API base path
supports
array
Features the post type supports
taxonomies
array
Associated taxonomy slugs
has_archive
boolean
Whether has archive page
menu_icon
string
Dashicon or URL for admin menu
menu_position
integer
Position in admin menu
allow_ai_access
boolean
Whether AI access is enabled
ai_description
string
Description to help AI understand the purpose
Annotations
Annotation
Value
readonly
true
destructive
false
idempotent
true
Permissions
Requires the ACF capability (default:
manage_options).
Example
List all custom post types registered through ACF.
Response:
{
"custom_post_types": [
{
"post_type": "event",
"label": "Event",
"plural_label": "Events",
"description": "Upcoming events and workshops",
"public": true,
"hierarchical": false,
"supports": ["title", "editor", "thumbnail", "excerpt"],
"taxonomies": ["event_category", "event_tag"],
"show_in_rest": true,
"rest_base": "events",
"has_archive": true,
"menu_icon": "dashicons-calendar-alt",
"allow_ai_access": true,
"ai_description": "Events with dates, locations, and ticket information"
},
{
"post_type": "team_member",
"label": "Team Member",
"plural_label": "Team Members",
"public": true,
"hierarchical": false,
"supports": ["title", "editor", "thumbnail"],
"show_in_rest": true,
"allow_ai_access": true
}
],
"count": 2,
"message": "Found 2 ACF custom post type(s)."
}
Notes
Only post types registered through ACF are returned (not core or plugin post types)
Post types must have
show_in_rest enabled to be fully accessible via abilities
Per-post-type abilities (query, create, view, update, delete) are registered dynamically for each post type with AI access
Ability: acf/custom-taxonomies
Lists all ACF-registered custom taxonomies.
Description
Returns an array of taxonomies that were created using ACF’s taxonomy registration feature. Includes taxonomies that have AI access enabled.
Input
This ability accepts no input parameters.
null
Output
{
"custom_taxonomies": [
{
"taxonomy": "product_category",
"label": "Product Category",
"plural_label": "Product Categories",
"description": "Categories for organizing products",
"public": true,
"hierarchical": true,
"show_in_rest": true,
"rest_base": "product-categories",
"post_types": ["product"],
"allow_ai_access": true,
"ai_description": "Hierarchical categories for product organization"
}
],
"count": 1,
"message": "Found 1 ACF custom taxonomy(s)."
}
Output Properties
custom_taxonomies
(array) Array of taxonomy configuration objects.
count
(integer) Total number of taxonomies returned.
message
(string) Human-readable status message.
Taxonomy Properties
Property
Type
Description
taxonomy
string
Taxonomy key/slug (max 32 characters)
label
string
Singular label
plural_label
string
Plural label
description
string
Taxonomy description
public
boolean
Whether publicly accessible
hierarchical
boolean
Whether supports parent/child (like categories)
show_in_rest
boolean
Whether exposed in REST API
rest_base
string
REST API base path
post_types
array
Associated post type slugs
allow_ai_access
boolean
Whether AI access is enabled
ai_description
string
Description to help AI understand the purpose
Annotations
Annotation
Value
readonly
true
destructive
false
idempotent
true
Permissions
Requires the ACF capability (default:
manage_options).
Example
List all custom taxonomies registered through ACF.
Response:
{
"custom_taxonomies": [
{
"taxonomy": "event_category",
"label": "Event Category",
"plural_label": "Event Categories",
"hierarchical": true,
"public": true,
"post_types": ["event"],
"show_in_rest": true,
"allow_ai_access": true,
"ai_description": "Categories for classifying events by type"
},
{
"taxonomy": "event_tag",
"label": "Event Tag",
"plural_label": "Event Tags",
"hierarchical": false,
"public": true,
"post_types": ["event"],
"show_in_rest": true,
"allow_ai_access": true
}
],
"count": 2,
"message": "Found 2 ACF custom taxonomy(s)."
}
Notes
Only taxonomies registered through ACF are returned (not core or plugin taxonomies)
Taxonomies must have
show_in_rest enabled to be fully accessible via abilities
Per-taxonomy abilities (query, create, view, update, delete) are registered dynamically for each taxonomy with AI access
Hierarchical taxonomies support parent/child term relationships (like categories)
Non-hierarchical taxonomies are flat (like tags)
Ability: acf/field-groups
Lists all ACF field groups that allow AI access.
Description
Returns an array of field groups that have AI access enabled. Each field group includes its full configuration, fields, and location rules.
Input
This ability accepts no input parameters.
null
Output
{
"field_groups": [
{
"ID": 123,
"key": "group_abc123",
"title": "Product Fields",
"fields": [...],
"location": [...],
"position": "normal",
"style": "default",
"active": true,
"show_in_rest": true,
"allow_ai_access": true,
"ai_description": "Fields for product information including price, SKU, and inventory."
}
],
"count": 1,
"message": "Found 1 field group(s) with AI access enabled."
}
Output Properties
field_groups
(array) Array of field group objects.
count
(integer) Total number of field groups returned.
message
(string) Human-readable status message.
Field Group Properties
Property
Type
Description
ID
integer
WordPress post ID
key
string
Unique field group key (e.g.,
group_abc123)
title
string
Field group title
fields
array
Array of field configurations
location
array
Location rules determining where the field group appears
position
string
Metabox position (
normal,
side,
acf_after_title)
style
string
Metabox style (
default,
seamless)
active
boolean
Whether the field group is active
show_in_rest
boolean
Whether exposed in REST API
allow_ai_access
boolean
Whether AI access is enabled
ai_description
string
Description to help AI understand the purpose
Annotations
Annotation
Value
readonly
true
destructive
false
idempotent
true
Permissions
Requires the ACF capability (default:
manage_options).
Example
List all field groups available for AI access.
Response:
{
"field_groups": [
{
"ID": 45,
"key": "group_product_details",
"title": "Product Details",
"fields": [
{
"key": "field_price",
"label": "Price",
"name": "price",
"type": "number"
},
{
"key": "field_sku",
"label": "SKU",
"name": "sku",
"type": "text"
}
],
"location": [
[
{
"param": "post_type",
"operator": "==",
"value": "product"
}
]
],
"active": true,
"allow_ai_access": true,
"ai_description": "Core product information fields"
}
],
"count": 1,
"message": "Found 1 field group(s) with AI access enabled."
}
Notes
Only field groups with
allow_ai_access set to
true are returned
Field configurations include all field settings and conditional logic
Location rules use the same format as ACF’s PHP registration
Accordion
Description
The Accordion field is used to organize fields into collapsible panels.
Each Accordion displays a clickable title generated by the field’s label and instructions, and a collapsible content panel where neighboring fields will be moved within.
When editing a field group, be aware that all fields following an Accordion field (or until another Accordion field is defined) will be added to the Accordion’s content panel.
Screenshots
The Accordion field interface
The Accordion field settings
Changelog
Added in version 5.6.6.
Settings
Open
Shows the Accordion content panel as open on initial page load. Defaults to false.
Multi-expand
Prevents default behavior of closing sibling Accordions when one is open. Defaults to false.
Endpoint
Defines an endpoint for the previous Accordion field. All fields that follow will not be appended to the Accordion’s content panel.
acf/admin/license_key_constant_message
Description
Used to modify the admin screen message when a license key is defined in code.
Changelog
Added in version 5.11.1
Example
This example demonstrates how to modify the displayed message when a license key is defined in code.
functions.php
add_filter('acf/admin/license_key_constant_message', function($message) {
return 'ACF is activated by a defined license key.';
});
acf/ajax/shortcode_capability
Description
Used to modify the capability required to parse the ACF shortcode over AJAX requests, commonly used by third party site builder plugins. By default, this is set to
edit_posts.
If you return false from this filter, no capability check will be carried out by ACF. In this case, you must validate access in your filter code before returning false to ensure logged out or subscribers users are unable to access ACF data.
Changelog
Added in version 5.11.2
ACF Blocks Configuration via block.json
Description
Since ACF 6.0, ACF has recommended using
block.json to handle your block registration.
A mirror of the WordPress JSON Schema for
block.json, with ACF’s additions, is available at https://github.com/AdvancedCustomFields/schemas/blob/main/json/block.json.
The WordPress documentation for
block.json, describing all the core properties, is available here.
If your
block.json contains an ACF key, it will be loaded by ACF as an ACF Block.
Block.json ACF Key
The ACF key supports the following properties:
renderTemplate
(String) The path to a template file used to render the block HTML. This can either be a relative path from the
block.json file or a full path to any file.
// Specifying a relative path to the block.json file
"acf": {
"renderTemplate": "testimonial.php"
}
renderCallback
(Callable) (Optional) Instead of providing a render template, a callback function name may be specified to output the block’s HTML.
// Specifying a function
"acf": {
"renderCallback": "my_acf_block_render_callback"
}
mode
(String) (Optional) The display mode for your block. Available settings are “auto”, “preview” and “edit”. Defaults to “preview”.
auto: Preview is shown by default, but changes to edit form when block is selected.
preview: Preview is always shown. Edit form appears in sidebar when block is selected.
edit: Edit form is always shown.Note: When in “preview” or “edit” modes, an icon will appear in the block toolbar to toggle between modes.
"acf": {
"mode": "auto"
}
Note (v3 blocks):** Setting
"mode": "edit" combined with
"supports": { "mode": false } is the legacy v2 way to disable the editor preview. When ACF detects both settings on a v3 block, it automatically treats them as
renderPreview: false. The recommended approach for new v3 blocks is to use
acf.renderPreview: false directly.
blockVersion
(Integer) The version of ACF Blocks to use. Version 1 of ACF Blocks is deprecated and not recommended for use with
block.json. Default is
2.
postTypes
(Array) (Optional) An array of post types to which this block type is restricted.
"acf": {
"postTypes": ["post", "page"]
}
validate
(Boolean) (Since 6.3.0) Should the fields in the block be validated as per the field group configuration. Default is
true.
"acf": {
"validate": false
}
usePostMeta
(Boolean) (Since 6.3.0) Should this block store its field values directly in post meta, rather than the block comment. When enabled, this block will be limited to once per page, and only as a top level block. These blocks will also not be supported as widgets or in the site editor/templates. Default is
false.
"acf": {
"usePostMeta": true
}
hideFieldsInSidebar
(Boolean) (Since 6.6.2) Whether to hide ACF fields from the block editor sidebar and only show them in the Expanded Editing Panel (v3 blocks only). Default is
false.
"acf": {
"hideFieldsInSidebar": true
}
autoInlineEditing
(Boolean) (Since 6.7) Enables automatic inline editing for fields within an ACF Block. When set to true, ACF will automatically apply inline editing functionality to any HTML elements where an ACF field’s value is the only content within that element (v3 blocks only). Default is
false.
"acf": {
"autoInlineEditing": true
}
renderPreview
(Boolean) (Since 6.x) Whether to render a live preview of the block in the editor. When set to
false, a placeholder showing the block icon, title, and an Edit Block button is shown instead. The block’s render template continues to run normally on the front-end. Default is
true (v3 blocks only).
"acf": {
"renderPreview": false
}
Block.json Example
{
"name": "acf/testimonial",
"title": "Testimonial",
"description": "A custom testimonial block that uses ACF fields.",
"style": [ "file:./testimonial.css" ],
"category": "formatting",
"icon": "admin-comments",
"keywords": ["testimonial", "quote"],
"acf": {
"mode": "preview",
"renderTemplate": "testimonial.php",
"validate": "false"
},
"supports": {
"anchor": true
}
}
acf/blocks/default_block_version
Description
Used to opt all of your ACF Blocks into a specific version.
Changelog
Added in version 6.6
Example
functions.php
function my_custom_function_to_bump_the_block_version( $version, $block ) {
return 3; // Use v3
}
add_filter( 'acf/blocks/default_block_version', 'my_custom_function_to_bump_the_block_version', 10, 2 );
Notes
If you have defined the ‘blockVersion’ specifically in your
block.json file, the filter will not override that.
acf/blocks/default_expanded_editor_button_text
Customize the default “Open in Expanded Editor” button text for all V3 blocks.
Description
This filter allows you to change the default button text that appears on the “Open in Expanded Editor” button for all ACF Blocks V3. Individual blocks can override this default using the
acf.expandedEditorButtonText property in
block.json.
Parameters
apply_filters( 'acf/blocks/default_expanded_editor_button_text', $text );
$text
(string) The button text. Default:
'Open in Expanded Editor'
Example
Change the default button text for all blocks
add_filter( 'acf/blocks/default_expanded_editor_button_text', function( $text ) {
return 'Edit Fields';
});
Use a translatable string
add_filter( 'acf/blocks/default_expanded_editor_button_text', function( $text ) {
return __( 'Open Editor', 'my-theme' );
});
Changelog
Added in version 6.8
Notes
This filter only applies to ACF Blocks V3
Individual blocks can override this default via the
acf.expandedEditorButtonText property in
block.json
The button is hidden entirely if the block has no fields assigned
ACF Blocks FAQ
Frequently Asked Questions
Have a question about ACF Blocks that isn’t covered here? Then make sure to register for the next session of ACF Chat Fridays, or reach out on Twitter.
Are blocks a replacement for metaboxes?
No. Traditional field group meta boxes are still an important part of the content editing and theme development process. ACF will continue to utilize them as a tool for saving content.
Can I make changes to the field group?
Yes. You can make changes to your field group and fields at any time. Making changes like this will not cause damage to existing blocks unless you remove fields and update blocks.
Can I make changes to the template?
Yes. You can make changes to your block template or callback function at any time. ACF Blocks are dynamic and are rendered by the server each time they are loaded. This allows changes to block templates to be applied to all existing block content.
Can I register a block without fields?
Yes. There are many scenarios where a block does not require any fields, such as a “latest post” block where you want to render PHP as a block.
Is ACF Blocks included in the free version?
ACF Blocks is a feature of ACF PRO, which also includes more fields and features to build better WordPress sites, such as the Repeater, Flexible Content, Clone, and Gallery fields, and options pages.
Do I need to write any JavaScript?
No. The ACF Blocks framework is 100% PHP, but you can add JavaScript if your block requires it for added functionality (a carousel slider, for example).
Where is block data saved?
WordPress saves block data as HTML comments in the post_content. ACF Blocks follow suit, saving their data as a JSON object within that HTML comment.
Can I load values from other blocks?
Yes, but we recommend against it for performance reasons. Unlike loading a value from a post or user, block values are saved in the block HTML comment found within the post_content. This prevents the $post_id parameter from working as expected in our template functions. If you really need to, you can load the post_content of a given post, and then parse the blocks using the parse_blocks() function. As mentioned above, we do not recommend doing this as it will degrade site performance due to the large number of queries required.
Do ACF blocks support native components?
Not yet, but we do plan to add support for ACF Blocks rendering your React components in an upcoming release..
What is Gutenberg and what are blocks?
Introduced in WordPress 5.0, the block-based editor “Gutenberg” has transformed the way content is created. Content is now created in the unit of blocks instead of freeform text. Blocks take various forms including Paragraphs, Headings, Media, and Embeds.
acf/blocks/fields_needing_wide_popover
Description
This filter allows developers to modify the list of ACF field types that will receive a wider popover when used within an ACF Block with toolbar inline editing. This is particularly useful for fields with more complex user interfaces that require additional horizontal space.
By default, the
gallery,
relationship,
wysiwyg, and
google_map fields are configured to use a wide popover.
Changelog
Added in version 6.7
Parameters
$field_types (array) An array of field type names.
Return
(array) The filtered array of field type names.
Example
This example demonstrates how to add the
'taxonomy' field type to the list of fields that should receive a wide popover.
Template locking options include the following:
contentOnly — Prevents all operations. Additionally, the block types that don’t have content are hidden from the list view and can’t gain focus within the block list. Unlike the other lock types, children can’t override this.
all — Prevents all operations. It is not possible to insert new blocks, move existing blocks, or delete blocks.
insert — Prevents inserting or removing blocks, but allows moving blocks.
Below are screenshots of what each of these would look like when applied to our Author Info block.
Author Info block with
templateLock="contentOnly" set on
InnerBlocks.
All nested blocks that do not contain content are hidden from the list view. Only content is editable.
Author Info block with
templateLock="all" set on
InnerBlocks.
All nested blocks are locked to prevent moving, deleting, or inserting new blocks.
Author Info block with
templateLock="insert" set on
InnerBlocks.
All nested blocks are locked from being removed or having new blocks inserted. Existing blocks can be moved.
Unlocking One Nested Block
For our Author Info block, we want to offer editors the option to remove the author’s biography paragraph, but everything else should remain locked from being removed. We’ll start by locking all the blocks down with
templateLock="all" attribute on our InnerBlocks component, and then we’ll use individual locking properties to unlock the one nested block we want to allow them to remove. We’ll make all of our changes to the Author’s Info
template.php file, in the
author-info directory of the custom plugin we created in our tutorial on
InnerBlocks.
For now, we’ll update our
InnerBlocks code as follows:
Next, we’ll have to update our individual nested block to allow removal. So, if editors choose to remove the author’s biography paragraph then they have the ability.
How to Use Individual Block Locking
Individual block locking takes priority and overrides template locking, unless
templateLock="contentOnly" is used. This hides all blocks that do not have content from the list view, and allows editors to update only the nested content block.
However, we previously decided to apply
templateLock="all". To update the individual Paragraph block nested within our passed template, we just need to target it with an additional
lock parameter. Here is our abbreviated nested code before applying the parameter:
array(
'core/paragraph',
array(
'style' => array(...),
'fontSize' => 'small',
'content' => 'Ea qui voluptate irure nulla aliquip nulla anim laborum exercitation eu incididunt.',
),
array(),
),
And here it is after, with our
lock applied:
array(
'core/paragraph',
array(
'style' => array(...),
'fontSize' => 'small',
'content' => 'Ea qui voluptate irure nulla aliquip nulla anim laborum exercitation eu incididunt.',
'lock' => array(
'remove' => false,
),
),
array(),
),
With the
'remove' => false above, we’re stating that the nested Paragraph block should be allowed to be removed. Yes, the
false is confusing, but this is how ya do it! 😉
Now we have our desired control of the block, with both template locking and individual block locking in place.
Author Info block example with lines pointing to differentiated blocks.
Next Steps and Considerations
This tutorial shows how you can use block and template locking to set editorial conditions and prevent unauthorized removal or modification of your ACF Blocks, but there is a lot of room left to explore.
There is another element to curating your editorial experience, which can be utilized when placing your blocks within patterns. If you plan to leverage your ACF Blocks in the context of patterns, then you’ll want to check out content-only block locking.
You could also extend your block content control strategy by preventing certain roles or users from locking and unlocking blocks. Be sure to check out how to restrict locking and unlocking for roles, specific users, or even post types.
If you’ve been following along, your final, full plugin code should match our version: author-info-block-v2.zip
In the next tutorial, we’ll show you how to use WordPress global styles and block styles with your ACF Blocks, providing a consistent and easy to use experience when managing settings and styles.
Key Concepts
ACF Blocks allows you to build on top of the WordPress blocks system introduced in WordPress 5.0 “Bebo”, giving you access to many of the same features available to core blocks, but with the output rendered from a PHP template. ACF Blocks are highly flexible, allowing you to define attributes, block styles, and block variations. You can then compose your ACF Blocks into patterns, templates and template parts, save them as synced patterns, and extend them to incorporate WordPress styles.
A thorough understanding of the Block Editor Handbook will greatly expand what you can build with ACF Blocks, but you don’t have to read the whole thing to get started. Below we highlight some of the key points to remember when working with blocks.
Key Terminology
Here are some common terms we’ll use to help distinguish between WordPress core block APIs and ACF Blocks APIs when necessary:
ACF Block(s): Represents the ACF product’s API extensions, which mostly leverage and are scaffolded on top of WordPress core block’s APIs.
WordPress core block(s): Refers to WordPress’s native and core APIs for blocks, which most of ACF Blocks is built upon. WordPress core blocks are mostly written in React.
Block(s) or block(s): When used without the prefix “ACF” or “WordPress core”, this refers to the general concept and lower-level APIs used by both WordPress core blocks and ACF Blocks, as well as the end output from the block.
Points to Remember
Block data is saved within the
post_content database table as serialized HTML. This makes them unique to meta boxes that save data to the
postmeta table.
Every block in WordPress requires a
block.json file to register its properties. This is the entry point for every new block type.
Native WordPress blocks can be static or dynamic. ACF Blocks are a custom type of dynamic block, rendered by ACF on the server and allowing for PHP logic.
Elements of ACF Blocks
There are three essential elements when it comes to ACF Blocks: a
block.json file, a PHP file, and a CSS file. In fact, the CSS file is optional as your block may inherit styles from your theme, but you’ll need it to incorporate any unique styling. Most ACF Blocks also have an ACF field group associated with them, allowing the ACF Block to pull data from the fields. However, this is not actually essential to creating an ACF Block.
ACF Blocks and block.json
Both WordPress core blocks and ACF Blocks register their properties in a file called
block.json to define their settings, styles, and metadata. The process is very similar to the one used for WordPress core blocks, but with the addition of the
acf configuration key.
Block Variables (or Parameters for Callbacks) in PHP
You have access to data about your block by default when creating an ACF Block, either by variables made available in your template or passed into your callback as parameters. New parameters are defined in exactly the same way as any other PHP template file.
$block (array) The block settings and attributes.
$content (string) The block inner HTML (empty).
$is_preview (boolean) True during backend preview render, i.e., when rendering inside the block editor’s content, or rendered inside the block editor when adding a new block, showing a preview when hovering over the new block. This variable is only set to true when is_admin() and current screen is_block_editor() both return true.
$post_id (integer) The Post ID of the current context. This will be the page/post a block is saved against, or if the block is used in a template, synced pattern or query loop block, it will be the post_id of the currently displayed item.
$context (array) The context provided to the block by the post or its parent block.
For render callbacks, the parameters are provided in the following order:
callback_function( $block, $content, $is_preview, $post_id, $wp_block, $context );
Next: Create Your First ACF Block
acf/blocks/top_toolbar_fields
Description
This filter allows you to add fields to the top toolbar of a specific ACF Block, enabling direct editing from the block’s header in the editor.
When a field is added to the toolbar, it appears as a button. Clicking this button opens a popover containing the field’s input, allowing for a more streamlined and integrated editing experience.
Changelog
Added in version 6.7.
Parameters
apply_filters( 'acf/blocks/top_toolbar_fields', $fields, $block, $content, $is_preview, $post_id, $wp_block, $context );
$fields (array) An array of fields to be displayed in the toolbar.
Defaults to an empty array.
$block (array) An array of block properties.
$content (string) The block’s inner content.
$is_preview (bool) A boolean that is true when the block is being rendered
for editing preview.
$post_id (int) The ID of the post being edited.
$wp_block (WP_Block|null) The WP_Block instance, or null.
$context (array) The block context.
Return
(array) The modified array of fields.
Example
This example demonstrates how to add an image field to the toolbar of the ACF Block:
function my_block_top_toolbar_fields($block_top_toolbar_field_names, $block) {
// If the block in question is our block.
if ( 'acf/my-acf-block' === $block['name'] ) {
// Make some ACF fields show in the primary block toolbar.
return array( 'my_background_image_field', 'my_background_color_field');
}
// If the block in question is not our block, just pass the variable as is.
return $block_top_toolbar_field_names;
}
add_filter( 'acf/blocks/top_toolbar_fields', 'my_block_top_toolbar_fields', 10, 2 );
ACF Blocks: Using get_block_wrapper_attributes()
The get_block_wrapper_attributes() function allows you to use the styles built by WordPress’ native
supports for a block, such as background and text colors, padding, margin, etc.
In the block editor, this is automatically output for you, on the wrapper WordPress adds around your block:
For this reason, you shouldn’t try to always apply
get_block_wrapper_attributes in your ACF Block PHP template. If you try to use that function when your block is rendered in the editor, you’ll get a PHP warning when your block is rendered there and no output due to the way ACF blocks are rendered, isolated from the rest of the page.
Instead, use ACF’s
$is_preview variable to know when your block is being output on the frontend, and then use
get_block_wrapper_attributes() to add all the styles selected for your block.
The following code makes sure we’re not in preview mode before outputting the wrapper attributes.
>
// Block output goes here.
This does mean your DOM structures are slightly different on the backend and the frontend, as your styles are applied one layer deeper. If that’s an issue, you can get around it by adding a new wrapper element to contain your styles, and apply it only to the frontend view:
>
// Standard block template goes here
ACF Blocks: Using InnerBlocks and Parent/Child Relationships
In this tutorial, we’ll show you how to utilize the InnerBlocks component within an ACF Block. We’ll also demonstrate how you can leverage relationships to nest blocks while limiting their discoverability.
By the end of the tutorial, you’ll know how to create an “Author Info” block that mixes ACF Blocks with WordPress core blocks, allowing editors to assign an author image, name, bio, and a social link.
In future tutorials, we’ll demonstrate how to use the Block Locking API (introduced in WordPress 5.9) to lock certain blocks from being modified or moved, and show how to extend your ACF Blocks with alternative Block Styles.
New to ACF Blocks? Start with our tutorial on creating your first ACF Block!
The video below provides a walkthrough of the Author Info block we’re going to create.
https://www.advancedcustomfields.com/wp-content/uploads/2023/06/ACF-block-example-optimized.mp4
Author Info block example with lines pointing to differentiated blocks.
Steps to complete
Create a WordPress plugin to organize our custom code
Register parent and child ACF Blocks with
block.json
Register ACF field for the author’s Twitter
Create display logic with InnerBlocks and block template
Requirements
ACF Blocks is a premium feature found only in ACF PRO. You will also need a WordPress site where you have access to the
wp-content directory. We highly recommend using Local or another WordPress development environment to create a sandbox site so you can experiment in complete safety.
Nesting Blocks With InnerBlocks
The InnerBlocks WordPress component is handy for creating a custom block that passes a series of curated nested blocks. There are a few things about how
InnerBlocks works that we should cover before we get too deep into the tutorial.
Some native WordPress blocks already utilize
InnerBlocks as part of their functionality, including the Columns and Social Icons blocks.
It is important to note that a block can only contain a single
InnerBlocks component. This is due to the way the contents of
InnerBlocks is stored on the block.
Using nested templates in InnerBlocks
Passing a template of blocks into the
InnerBlocks component can pre-populate nested blocks and placeholder attributes, expediting the editorial experience.
Admittedly, the process to create your nested block template can be a bit clumsy, especially if you’re using several blocks and nesting is a few levels deep. Typically, we recommend something like the following process:
Create your nested block layout in the block editor, assigning all desired styles and attributes.
Select the parent block in the editor and choose Copy.
Visit the WPHTML Converter and paste your block markup from the editor. Click Convert to PHP, and copy the converted markup.
Paste the converted markup into your block’s
template.php and assign it to a variable so you can use it later on. Be sure to nest it within an
array(). We’ll cover this in our last step in this tutorial.
Here is a simple example of what this might look like:
Example of passing a template to InnerBlocks
array(
'type' => 'constrained',
),
),
array(
array(
'core/paragraph',
array(
'align' => 'center',
'content' => 'I'm a paragraph.',
),
array(),
),
array(
'core/separator',
array(),
array(),
),
),
),
);
//...
Using parent and ancestor relationships in blocks
A common pattern for using InnerBlocks is to create a custom block that’s only available if its parent block is inserted. This allows builders to establish a relationship between blocks, while also limiting a nested block’s discoverability. Currently, there are two relationships builders can use:
parent and
ancestor. The differences are:
If you assign a
parent, then you’re stating that the nested block can only be used and inserted as a direct descendant of the parent.
If you assign an
ancestor, then you’re stating that the nested block can be used and inserted as any descendant of the parent.
The key difference between
parent and
ancestor is that
parent has finer specificity, while an
ancestor has greater flexibility in its nested hierarchy.
In our Author Info block, we want the Author Twitter block to be nested inside as a direct descendant. Author Info is defined as the parent in the Author Twitter’s
block.json file:
Example block.json with parent key
{
...
"parent": [ "acf/author-info" ]
}
Alright, let’s start building our custom plugin and blocks!
1. Create a WordPress plugin to organize our custom code
For our example, we’ll create a custom WordPress plugin to organize our code, although you can create the blocks directly in your theme if you wish. Create a new
author-info-block folder in your WordPress site’s
wp-content/plugins folder. Then add an
author-info-block.php file in the folder. It’s within this file that we’ll define our new WordPress plugin with the following code:
wp-content/plugins/author-info-block/author-info-block.php
Instructions:
https://twitter.com/[username]
Presentation > Prepend:
https://twitter.com/
We could stop here, because technically our field group is registered and assigned to the block. However, we want to keep our entire custom block plugin portable and distributable between projects. So, we’ll want to co-locate the registration of our newly created Author Twitter field group to reside within our custom plugin. Lucky for us ACF makes this easy too!
Click on Tools in the ACF menu, then select your Author Twitter field group and click Generate PHP. This will give you the code to drop right into your plugin.
Once you’ve added the generated code to your plugin’s
author-info-block.php, you can go ahead and delete the field group that you created in ACF’s UI, because it is now registered with code.
wp-content/plugins/author-info-block/author-info-block.php
'group_64e3e09959e8f',
'title' => 'Author Twitter',
'fields' => array(
array(
'key' => 'field_64e3e09a7a544',
'label' => 'Twitter',
'name' => 'twitter',
'type' => 'text',
'instructions' => 'https://twitter.com/[username]',
'prepend' => 'https://twitter.com/',
),
),
'location' => array(
array(
array(
'param' => 'block',
'operator' => '==',
'value' => 'acf/author-twitter',
),
),
),
)
);
}
);
We’ve gone ahead and streamlined the output above, because not all options are totally necessary. ACF will use defaults for the omitted options. As mentioned previously, it’s entirely possible to skip registering the fields in the UI, and just write the PHP code needed. The Author Info block is controlled by the PHP in
author-info-block.php, not the selections made in the admin UI.
4. Create display logic with InnerBlocks and block template
At this point, you have two blocks registered, but there is no display logic for either of them. This is where we utilize
InnerBlocks and pass down a block
template string to assign and automatically populate the Author Info block upon creation.
First, we’ll set up our display logic for our Author Twitter block, which is outputting the Author Twitter field group we created in the last step.
Open the Author Twitter block’s
author-info-block/blocks/author-twitter/template.php and insert the following code.
blocks/author-twitter/template.php
There is a lot going on in the code snippet above. Let’s break it down. The biggest piece of this snippet is the
$inner_blocks_template (near the top), a variable we assign to our
template property within
(near the bottom). The
$inner_blocks_template variable consists of an array of blocks and their attributes, with further nested blocks within those. Near the bottom of the long nested array you’ll see that we’re passing our custom
acf/author-twitter block with a default
twitter field value of
wp_acf. This will help pre-populate the field when the Author Info block is added in a new post.
The nesting and proper syntax to get these complex template strings correct can be pretty hard to figure out. The array that defines the
$inner_blocks_template has over 30 more arrays nested within it. The first array is
core/columns, a WordPress core block that allows us to display multiple columns that each contain blocks. Diving a little deeper into the
core/columns array, we see it’s a further array containing style values:
$inner_blocks_template = array(
array(
'core/columns',
array(
'verticalAlignment' => 'center',
'style' => array(
'spacing' => array(
'padding' => array(
'top' => 'var:preset|spacing|30',
'right' => 'var:preset|spacing|30',
'bottom' => 'var:preset|spacing|30',
'left' => 'var:preset|spacing|30',
),
),
),
),
This nesting quickly becomes complex, even for relatively simple uses of
InnerBlocks. The easiest way to create an array like this is to create the layout and design within the block editor, and then switch to “List View” and click the three dots to the right of your block. Click Copy block to copy the WordPress block HTML to your clipboard. Finally, paste it into a tool like WPHTML Converter to convert the markup into the proper array format.
Below is a video demonstrating the conversion process.
https://www.advancedcustomfields.com/wp-content/uploads/2023/06/Convert-block-markup-optimized.mp4
If you’ve been following along, your final, full plugin code should match our version: author-info-block-v1.zip
Wrapping Up
This tutorial illustrates how to create an Author Info block and integrate
InnerBlocks with ACF Blocks to create nested blocks with parent/child relationships. However, there is still much more to explore.
In the next tutorial, we’ll show you how to use block and template locking to lock down key blocks in your markup and set editorial conditions. This helps ensure your editors only edit what they need to, setting them up for the best editorial experience.
ACF Blocks V3
ACF Blocks V3
ACF Blocks Version 3 brings your ACF Blocks improved usability, new functionality, and fixes some issues as well:
New: ACF Blocks v3 is compatible with WordPress/Gutenberg blocks v3 (iframe)
New: ACF Blocks Edit Mode has been removed and replaced with a slide-out sidebar/modal. The preview area is always the preview area, and fields can be edited either in the sidebar, or in the larger slide-out/modal sidebar
Fixed: You can now edit ACF blocks in Edit mode inside WP Core’s pattern editor
Fixed/Changed: Validation errors now first appear after you click “Save/publish”, as opposed to immediately, while you are typing into a field for the first time
Fixed/Changed: After fixing a field validation error it shows as fixed immediately as opposed to needing to click out of the block and back into it
Fixed: Blocks with radio buttons no longer affect each other’s field values
Fixed: Blocks with required radio buttons now validate correctly
Fixed: ACF field validation now works in the Site Editor
Fixed: WYSIWYG fields are no longer affected by typing into other blocks
Upgrading to v3
To upgrade your blocks to version 3, you have a few options depending on your needs.
If using block.json
If you are using block.json to register your blocks, you can add a
blockVersion key to the
acf object, and set its value to
3. For example:
{
"name": "acf/my-block",
"title": "My Block",
"acf": {
"blockVersion": 3,
"renderTemplate": "render-template.php"
},
}
If using acf_register_block_type
If you are using the
acf_register_block_type PHP function to register your blocks, add the acf_block_version to it. For example:
function my_acf_blocks_init() {
acf_register_block_type(
array(
'name' => 'testimonial',
'title' => 'Testimonial',
'render_template' => 'blocks/testimonial-block.php'
'api_version' => 3,
'acf_block_version' => 3,
)
);
}
add_action('acf/init', 'my_acf_blocks_init');
If you want to opt-in all of your blocks in a single line
If you want to opt all of your blocks into version 3 you can use the
acf/blocks/default_block_version PHP filter, which will make any blocks without a specific version defined use version 3. For example:
function my_custom_function_to_bump_the_block_version( $version, $block ) {
return 3;
}
add_filter( 'acf/blocks/default_block_version', 'my_custom_function_to_bump_the_block_version', 10, 2 );
Note that if you have defined the blockVersion specifically in your block.json file, the
acf/blocks/default_block_version filter will not override that.
Notable changes from V2
In ACF Blocks Version 2, you could have your fields show up in the preview area by using “Edit” mode, or you could have them show up in the block editor sidebar if your block is in “Preview” mode. You could also toggle between the two by clicking the pencil icon in the block’s toolbar.
But in ACF Blocks Version 3, the concept of modes no longer exists. Rather, your block will always be in “preview”, always showing what’s in your PHP render template in the block preview area.
The block’s ACF fields show up in the sidebar, and also in a pop-out sidebar that has more space.
The pencil icon button in the block toolbar remains, and when clicked it will open the fields in the larger pop-out sidebar, allowing you to have more space for editing your fields.
ACF Blocks Version 3 is available from ACF PRO version 6.6 or later.
acf/compatibility
Description
Used to enable backwards compatibility support for changed functionality.
Support for each compatibility can be enabled by its own filter. Compatibilities are disabled by default and can be opted-in using the
__return_true() function.
Changelog
Added in version 5.2.0
Parameters
apply_filters( "acf/compatibility/{$name}", $enabled );
$enabled (bool) Whether of not backwards compatibility support is enabled. Defaults to
false.
Compatibilities
The following table lists the available compatibilities which can be enabled.
Name
Added
Description
field_wrapper_class
5.2.0
Field class names changed in v5.2.0 from
field_type-{$type} to
acf-field-{$type}. This change was introduced to better optimise JS performance.
Example
This example demonstrates how to enable backwards-compatibility for field class names.
functions.php
add_filter('acf/compatibility/field_wrapper_class', '__return_true');
Updates to ACF Field Functions in 5.11
Updates to ACF Field Functions in 5.11
In versions of ACF prior to 5.11, the ACF shortcode
[acf field="field_name"], along with the
get_field() and
the_field() functions, could also be used to retrieve WordPress options or post, user or term meta values which weren’t ACF fields. Depending how these functions were used, it could have security implications as site options could inadvertently be exposed to the frontend or to users who do not have admin permissions. In addition, these functions could retrieve values of fields that are no longer registered with ACF, as their meta values remain in the database.
Aside from being a security risk, we don’t recommend using functions like
get_field() to get anything other than an ACF field. These functions run additional logic and database queries to find a valid field and format it correctly. As a result it would be less performant to use
get_field instead of the relevant WordPress core functions.
With ACF 5.11.2 and above, the ACF shortcode will only retrieve values for registered ACF fields, whilst
get_field() and
the_field() will prevent access to site options which are not registered ACF fields. While this should be fine for most sites, there are a few scenarios that might require special attention. This doc will go over some of those scenarios and offer some solutions.
For ACF 5.11 and 5.11.1, the data access changes for the ACF shortcode were also applied to
get_field() and
the_field().
Using ACF Functions to Retrieve Data From Outside ACF
The update to ACF version 5.11.2 means that calling the ACF shortcode on non-ACF options or post, user or term meta will return null, whereas before it might have returned the value.
Calls to get_field() or the_field() on non-ACF WordPress options will also return null. However, using those functions to retrieve any post, user or term meta will return the value, regardless of if the meta is an ACF field.
To avoid this, we recommend using WordPress core functions to retrieve non-ACF field data. Developers should use the
get_option() function to retrieve data in the
wp_options table, or the
get_post_meta() function to retrieve meta from the
wp_postmeta table.
In ACF 5.12.1, these restrictions now also correctly apply when using a field key to access an option value, the same as using the field name.
Registering Fields via PHP
Any fields registered using the acf_add_local_field_group() and acf_add_local_field() PHP functions should be registered before
get_field() is used. We recommend registering any local fields on the acf/init action hook or directly in your theme’s
functions.php file.
It’s important to note that calling
get_field() or
the_field() will initialize ACF if it hasn’t done so already. This means that if you call those functions before your local field groups are registered, ACF won’t be able to find those fields.
Starting with 5.11.1, ACF will detect if this has happened, and output a
_doing_it_wrong notice to your PHP error log. From 5.11.2, we will still return data along side this warning to avoid site errors while you modify your code to be compatible.
To correct this, make sure that:
Field groups registered via PHP are registered after ACF has initialized, preferably on the
acf/init hook.
Calls to
get_field() or
the_field() happen inside an action hook/filter which fires after your fields have been registered, or inside your theme’s template files.
Below is an example of how to correctly register fields using the
acf/init hook.
add_action( 'acf/init', 'my_acf_add_local_field_groups' );
function my_acf_add_local_field_groups() {
acf_add_local_field_group(array(
'key' => 'group_1',
'title' => 'Page Hero',
'fields' => array (
array (
'key' => 'field_1',
'label' => 'Hero Title',
'name' => hero_title,
'type' => 'text',
)
),
'location' => array (
array (
array (
'param' => 'post_type',
'operator' => '==',
'value' => page,
),
),
),
));
}
Registering Fields Inside Conditional Logic
Care should be taken when registering local fields/field groups inside conditional logic, as
get_field() and related functions may not work as intended.
For example, the following code registers a field in PHP, but only in the WordPress admin due to the
is_admin() check. Any calls to
get_field() in frontend theme code wouldn’t be able to retrieve the value for that field:
if ( is_admin() ) {
add_action( 'acf/init', 'my_acf_add_local_field_groups' );
}
function my_acf_add_local_field_groups() {
acf_add_local_field_group(array(
'key' => 'group_1',
'title' => 'Page Hero',
'fields' => array (
array (
'key' => 'field_1',
'label' => 'Hero Title',
'name' => hero_title,
'type' => 'text',
)
),
'location' => array (
array (
array (
'param' => 'post_type',
'operator' => '==',
'value' => page,
),
),
),
));
}
The conditional logic needs to be removed so that the ‘acf/init’ action is called on both the admin and frontend of the site:
add_action( 'acf/init', 'my_acf_add_local_field_groups' );
Multisite Installs Using the Same Field Across Multiple Subsites
ACF fields are only available to the subsite that registered them. If you want to use the same ACF field on multiple subsites, you should create the field on any subsites that will use the field.
Alternatively, you could export the field groups that you want to re-use as PHP (via Custom Fields -> Tools -> Generate PHP), and include that PHP in the
functions.php file of any themes used by the subsites. This will register the fields via PHP, and make sure they are available across the multisite network.
acf/field_group/admin_enqueue_scripts
Description
Used to enqueue scripts and styles on the field group admin edit page.
This action is similar to the WordPress admin_enqueue_scripts, except that it is only fired on the field group admin edit page.
Changelog
Added in version 5.0.0
Example
This example demonstrates how to enqueue custom styles and scripts to customize field group settings.
functions.php
HTML to the field group admin edit page.
This action is similar to the WordPress admin_footer, except that it is only fired on the field group admin edit page.
Changelog
Added in version 5.0.0
Example
This example demonstrates how to output additional inline style and script tags to customize field group settings.
functions.php
HTML to the field group admin edit page.
This action is similar to the WordPress admin_head, except that it is only fired on the field group admin edit page.
Changelog
Added in version 4.0.0
Example
This example demonstrates how to output additional inline style and script tags to customize field group settings.
functions.php
';
}
// load text sub field
if( $text = get_sub_field('text') ) {
$title .= '' . esc_html($text) . '';
}
return $title;
}
acf/fields/google_map/api
Description
Used to modify the url parameters used to load the Google Maps JS API.
Primarily, this filter exists to set a Google API key, however, it may also be used to customize
other_params used in the
google.load function.
Changelog
Added in version 5.3.10
Parameters
apply_filters( 'acf/fields/google_map/api', $args );
$args
(array) Array of url parameters.
– libraries
(string) A comma separated list of libraries to load. Defaults to “places”.
‘libraries’ => ‘places’,
key
(string) A Google Maps API key. Defaults to an empty string.
'key' => '',
client
(string) Optional. A Google API client ID. Defaults to an empty string.
'client' => '',
callback
(string) Optional. A global JavaScript function to call when the API has loaded. Defaults to
Function.prototype (a no-op).
'callback' => 'Function.prototype',
Example
This example demonstrates how to register a Google API key to be used when loading the Google Maps JS library.
functions.php
post_type . ')';
return $text;
}
acf/fields/relationship/query
Description
Filters the query
$args used by
WP_Query to display posts in the Relationship field.
Changelog
Added in version 4.1.2
Parameters
apply_filters( 'acf/fields/relationship/query', $args, $field, $post_id );
$args (array) The query args. See WP_Query for available args.
$field (array) The field array containing all settings.
$post_id (int|string) The current post ID being edited.
Modifers
This filter provides modifiers to target specific fields. The following filter names are available:
acf/fields/relationship/query Applies to all fields.
acf/fields/relationship/query/name={$name} Applies to all fields of a specific name.
acf/fields/relationship/query/key={$key} Applies to all fields of a specific key.
Example
This example demonstrates how to modify some of the Relationship field query args.
functions.php
ID );
if( $page_views ) {
$text .= ' ' . sprintf( '(%s views)', $page_views );
}
return $text;
}
This example demonstrates how to display the Order ID for WooCommerce shop orders in a relationship field.
functions.php
post_type !== 'shop_order' ) {
return $text;
}
return str_replace( 'Order', 'Order ' . $post->ID, $text );
}
acf/fields/taxonomy/query
Description
Filters the query
$args used by
WP_Term_Query to display terms in the Taxonomy field when displayed as a Select or Multiselect dropdown.
Changelog
Added in version 5.0.0
Parameters
apply_filters( 'acf/fields/taxonomy/query', $args, $field, $post_id );
$args (array) The query args. See WP_Term_Query for available args.
$field (array) The field array containing all settings.
$post_id (int|string) The current post ID being edited.
Modifers
This filter provides modifiers to target specific fields. The following filter names are available:
acf/fields/taxonomy/query Applies to all fields.
acf/fields/taxonomy/query/name={$name} Applies to all fields of a specific name.
acf/fields/taxonomy/query/key={$key} Applies to all fields of a specific key.
Example
This example demonstrates how to modify some of the Taxonomy field query args.
functions.php
slug . ')';
return $text;
}
acf/fields/taxonomy/wp_list_categories
Description
Filters the query
$args used by
WP_Term_Query to display terms in the Taxonomy field when displayed as a Radio or Checkbox list.
Changelog
Added in version 4.0.0
Parameters
apply_filters( 'acf/fields/taxonomy/wp_list_categories', $args, $field );
$args (array) The query args. See wp_list_categories() for available args.
$field (array) The field array containing all settings.
Modifers
This filter provides modifiers to target specific fields. The following filter names are available:
acf/fields/taxonomy/wp_list_categories Applies to all fields.
acf/fields/taxonomy/wp_list_categories/name={$name} Applies to all fields of a specific name.
acf/fields/taxonomy/wp_list_categories/key={$key} Applies to all fields of a specific key.
Example
This example demonstrates how to modify some of the Taxonomy field wp_list_categories args.
functions.php
ID );
$text .= ' (' . $recipient . ')';
return $text;
}
acf/format_value
Description
Filters the field
$value after being loaded by a template function such as
get_field().
Changelog
Added in version 5.0
Previously named "acf/format_value_for_api" in version 4.0
Parameters
apply_filters( 'acf/format_value', $value, $post_id, $field );
$value (mixed) The field value.
$post_id (int|string) The post ID where the value is saved.
$field (array) The field array containing all settings.
Modifers
This filter provides modifiers to target specific fields. The following filter names are available:
acf/format_value Applies to all fields.
acf/format_value/type={$type} Applies to all fields of a specific type.
acf/format_value/name={$name} Applies to all fields of a specific name.
acf/format_value/key={$key} Applies to all fields of a specific key.
Example
This example demonstrates how to modify a field’s value when loaded by a template function.
functions.php
HTML to pages where ACF fields appear.
This action is similar to the WordPress admin_footer, except that it is only fired on pages where ACF fields appear – such as when editing posts, users, taxonomy terms, options pages and front-end forms.
Changelog
Added in version 5.0.0
Example
This example demonstrates how to output additional inline style and script tags to customize fields.
functions.php
HTML to pages where ACF fields appear.
This action is similar to the WordPress admin_head, except that it is only fired on pages where ACF fields appear – such as when editing posts, users, taxonomy terms, options pages and front-end forms.
Changelog
Added in version 4.0.0
Example
This example demonstrates how to output additional inline style and script tags to customize fields.
functions.php
element.
This element is output within each form, and includes hidden inputs used to process the form data.
Parameters
do_action( 'acf/form_data', $data );
$data (array) The current form data including "screen", "post_id" and "nonce".
Changelog
Added in version 5.0.0
Example
This example demonstrates how to output a hidden input, and then later perform an action depending on that value.
functions.php
';
}
add_action('acf/save_post', 'my_acf_save_post');
function my_acf_save_post( $post_id ) {
if( isset($_POST['_my_hidden_input']) ) {
// Do something.
}
}
acf/json/eof_newline
Description
Used to change the newline character at the end of JSON files.
Changelog
Added in version 6.2.
Parameters
apply_filters( 'acf/json/eof_newline', $newline_character );
$newline_character (string) The current newline character,
PHP_EOL by default.
Example
This example demonstrates how to change the newline character at the end of JSON files.
functions.php
'My Custom Choice',
'custom_2' => 'My Custom Choice 2'
);
return $field;
}
// Apply to all fields.
// add_filter('acf/load_field', 'my_acf_load_field');
// Apply to select fields.
// add_filter('acf/load_field/type=select', 'my_acf_load_field');
// Apply to fields named "custom_select".
add_filter('acf/load_field/name=custom_select', 'my_acf_load_field');
// Apply to field with key "field_123abcf".
// add_filter('acf/load_field/key=field_123abcf', 'my_acf_load_field');
acf/load_value
Description
Filters the field
$value after being loaded.
Changelog
Added in version 4.0.0
Parameters
apply_filters( 'acf/load_value', $value, $post_id, $field );
$value (mixed) The field value.
$post_id (int|string) The post ID where the value is saved.
$field (array) The field array containing all settings.
Modifers
This filter provides modifiers to target specific fields. The following filter names are available:
acf/load_value Applies to all fields.
acf/load_value/type={$type} Applies to all fields of a specific type.
acf/load_value/name={$name} Applies to all fields of a specific name.
acf/load_value/key={$key} Applies to all fields of a specific key.
Example
This example demonstrates how to modify a field’s value.
functions.php
against your site through the
.local-wp.sh wrapper we set up earlier, one invocation per term, skipping any that already exist. For example:
./.local-wp.sh term create property_type "Villa"
./.local-wp.sh term create region "Downtown"
./.local-wp.sh term create amenity "wifi"
# ...and so on
A note on MCP scope: ACF abilities are registered dynamically. Before a custom post type or taxonomy exists, the available MCP abilities are focused on creating the schema, such as registering ACF-managed post types, taxonomies, and field groups.
After those post types and taxonomies are created, ACF dynamically registers additional CRUD abilities for the content that belongs to them. For example, once the property post type exists, ACF can expose abilities for creating and managing property posts. Once taxonomies like region or amenity exist, ACF can expose abilities for managing their terms.
So if you do not see post or term creation abilities at the beginning of the workflow, that does not mean ACF does not support them. It usually means the relevant post type or taxonomy has not been registered yet.
For this demo, I used MCP to create the schema and WP-CLI to seed terms and import sample property content from a CSV file. That kept the import process simple and repeatable while still showing how ACF makes the content model discoverable through MCP.
At this point, the WordPress install has:
A property post type
12 property type terms
10 Austin region terms
9 amenity terms
A Property Details ACF field group
Now we can configure the Google Map field.
Configure the ACF Google Map Field
Because the Property Details field group includes an ACF Google Map field, we need to give it a Google Maps API key. Please follow the documentation on ACF Google Maps here.
Import Sample Property Data with AI
At this point, we have the content model, but we do not have any property content yet.
To make the demo realistic, I created a CSV file with 15 Austin short-term rental properties.
Create a file called:
austin-properties.csv
The CSV includes columns for:
name
description
property_type
region
amenities
price_per_night
bedrooms
bathrooms
max_guests
address
city
lat
lng
checkin_time
checkout_time
rating
The amenities column uses pipe-separated values, for example
wifi|pool|parking, so you can assign multiple amenities to one property.
Here is a simplified example row (header + one data row):
name,description,property_type,region,amenities,price_per_night,bedrooms,bathrooms,max_guests,address,city,lat,lng,checkin_time,checkout_time,rating
Zilker Park Bungalow Hideaway,"Two-bedroom bungalow tucked between Zilker Park and Barton Springs.",bungalow,Zilker,wifi|ac|parking|garden|hot_tub,245,2,2,4,2014 Goodrich Ave,Austin,30.2638,-97.7702,15:00,11:00,4.8
Once the MCP server is wired up, Claude can discover the property CPT’s abilities — creating posts, assigning taxonomy terms, updating ACF fields — and run the import for you. Open Claude in the project directory and ask something like:
“Read
austin-properties.csv and import each row into the property CPT. For each row, create the post, assign the
property_type, region, and amenity taxonomy terms (creating any that don’t exist), and populate the ACF fields. Format the location field as an array with address, lat, lng, and zoom: 14, and the check-in/out times as
H:i:s. Skip any rows where a property with that title already exists.“
Claude will walk the CSV, call the right abilities for each row, and report back what it created and
skipped. This is the demo’s whole point: structured WordPress data, driven by natural language, through
MCP.
Option 2: Use a deterministic import script
If you’d rather have a repeatable, scriptable seed — useful for rebuilding the demo from scratch, or for
larger CSVs where streaming hundreds of tool calls may cause bottlenecks — here’s a WP-CLI script that does the same thing.
This script should:
Read the CSV
Loop over each row
Skip the row if a property with that title already exists
Create a new property post
Look up taxonomy terms by slug or name, and create them if missing
Update each ACF field with update_field()
Format the Google Map field as an array with address, lat, lng, and zoom
Format check-in and check-out times as H:i:s
The file is called
import-properties.php at the project’s root. Please reference the script from my GitHub repo here if needed.
After importing, you can verify the posts. For this demo, the import created 15 properties with IDs 31 through 45.
You can also verify terms for a specific property:
./.local-wp.sh post term list 31 property_type
./.local-wp.sh post term list 31 region
./.local-wp.sh post term list 31 amenity
To verify ACF values, run:
./.local-wp.sh eval 'print_r( get_fields(31) );'
If you see the ACF field values returned, the import worked.
Render Property Data on the Frontend
ACF field values are stored with the post, but they do not automatically appear on the frontend. Your theme still needs to decide how that data should be displayed.
For this demo, I created a small child theme of Twenty Twenty-Five and added a custom
single-property.html template for the
property post type.
The template renders the normal WordPress content, such as the title, featured image, and post content, along with a few shortcode blocks that output the ACF fields and taxonomy terms.
Those shortcodes use standard WordPress and ACF functions like
get_field() and
get_the_terms() to retrieve the property details, including the price, bedrooms, bathrooms, address, amenities, region, and Google Map location.
I also conditionally loaded the Google Maps JavaScript only on single property pages, so the map script is not loaded across the entire site.
Once the child theme was ready, I activated it with WP-CLI:
bash
./.local-wp.sh theme activate twentytwentyfive-child
After that, visiting a property page showed the post content, ACF field values, taxonomy terms, and a live Google Map pin rendered together:
How you render this data is a theming decision. You could use a block theme template, classic PHP templates, custom blocks, shortcodes, or a headless frontend. The important part is that ACF gives you the structured data, and your frontend decides how to present it.
In the next section, we will look at the Schema.org output, which gives us another machine-readable layer on the frontend without requiring the fields to be visually rendered in the same way.
Enable Schema.org Support in ACF
Now that the content model and frontend are working, we can enable ACF’s Schema.org functionality. This is what allows ACF fields to be mapped to structured data.
Open the mu-plugin again:
wp-content/mu-plugins/site.php
Add this filter:
add_filter( 'acf/settings/enable_schema', '__return_true' );
Your full mu-plugin should now look similar to this:
If the Schema.org mapping is configured correctly, you should see JSON-LD output for the property page. You can also copy the JSON-LD and test it in Google’s Rich Results Test: https://search.google.com/test/rich-results.
This confirms that the content is not just visible to humans. It is also being output in a machine-readable format.
Conclusion
ACF Stoke!!! You now have a local WordPress site that uses Advanced Custom Fields as more than a custom field UI.
In this guide, we created a structured content model for Austin short-term rentals. We registered a custom post type, taxonomies, and ACF field group through MCP.
We imported sample property data from a CSV file, rendered that data in a Twenty Twenty-Five child theme, and enabled ACF’s Schema.org support so the content could be mapped to machine-readable JSON-LD.
With ACF 6.8, your content model can become discoverable, structured, and machine-readable for AI tools, automation workflows, search engines, and external applications.
[1] WP Engine is a proud member and supporter of the community of WordPress® users. The WordPress® trademark is the intellectual property of the WordPress Foundation. Uses of the WordPress® trademarks in this website are for identification purposes only and do not imply an endorsement by WordPress Foundation. WP Engine is not endorsed or owned by, or affiliated with, the WordPress Foundation.
acf/options_page/save
Description
Fires after publishing a save on an options page.
This action allows you to hook in after an options page has been saved in the admin.
Parameters
do_action( 'acf/options_page/save', $post_id, $menu_slug );
$post_id (int|string) The ID of the page being edited.
$menu_slug (string) The current options page menu slug.
The
$post_id defaults to ‘options’, but can be set as a post or a user ID when registering the options page.
Changelog
Added in version 6.1.7
Example
add_action('acf/options_page/save', 'my_acf_save_options_page', 10, 2);
function my_acf_save_options_page( $post_id, $menu_slug ) {
if ( 'theme-settings' !== $menu_slug ) {
return;
}
// Get newly saved values for the theme settings page.
$values = get_fields( $post_id );
// Check the new value of a specific field.
$analytics_code = get_field('analytics_code', $post_id);
if( $analytics_code ) {
// Do something...
}
}
acf/options_page/settings
This filter allows you to modify the setting used by the options page add-on.
Changelog
Deprecated in ACF PRO
Added to the Options Page Add-on
Notes
This filter has been deprecated in ACF PRO as it is no longer needed. ACF PRO does not add an options page by default and requires each options page to be added using the add_options_page() and add_options_sub_page() functions.
Parameters
apply_filters('acf/options_page/settings', $settings);
$settings (array) an array of settings described below
$settings
$settings = array(
/* (string) the options page title. Defaults to 'Options' */
'title' => __('Options', 'acf'),
/* (string) the options page menu title. Defaults to 'Options' */
'menu' => __('Options', 'acf'),
/* (string) the options page url slug. Defaults to 'acf-options' */
'slug' => 'acf-options',
/* the capability needed to access this admin page. Defaults to 'edit_posts' */
'capability' => 'edit_posts',
/* an array of sub menu pages (strings or arrays). Defaults to an empty array */
'pages' => array()
);
Usage
This example will change the menu item title to ‘Global’ and add 3 sub pages!
function my_acf_options_page_settings( $settings )
{
$settings['title'] = 'Global';
$settings['pages'] = array('Header', 'Sidebar', 'Footer');
return $settings;
}
add_filter('acf/options_page/settings', 'my_acf_options_page_settings');
acf/pre_save_post
Description
This filter allows you to modify the $post_id before any custom field data is saved from the front end form (acf_form()). This filter is used in the tutorial Using acf_form to create a new post.
This filter is not required to create a new post due to the
new_post argument added to acf_form() in v5.0.0
Changelog
Added in v4.0.0
Parameters
Name
Type
Description
post_id
int
The post ID to which all the $_POST data (values) will be saved to
Usage
This code could be used in the functions.php file, or on the page template which features the front end form (above the acf_form_head function)
functions.php
'draft' ,
'post_title' => 'A title, maybe a $_POST variable' ,
'post_type' => 'post' ,
);
// insert the post
$post_id = wp_insert_post( $post );
// return the new ID
return $post_id;
}
add_filter('acf/pre_save_post' , 'my_pre_save_post', 10, 1 );
?>
acf/prepare_field
Description
Used to modify the
$field settings or to prevent the field from being rendered within a form.
This filter is similar to
acf/load_field, only it is applied later in the lifecycle when the field is about to be rendered. By this time, the field’s value has also been loaded.
Changelog
Added in version 5.0.0
Parameters
apply_filters( 'acf/prepare_field', $field );
$field (array) The field array containing all settings (including value).
Modifers
This filter provides modifiers to target specific fields. The following filter names are available:
acf/prepare_field Applies to all fields.
acf/prepare_field/type={$type} Applies to all fields of a specific type.
acf/prepare_field/name={$name} Applies to all fields of a specific name.
acf/prepare_field/key={$key} Applies to all fields of a specific key.
Examples
Modifying a field
This example demonstrates how to modify a specific field’s settings before it is rendered.
functions.php
Or use Google Rich Results Test
Copy the JSON output and validate it is using https://validator.schema.org
Suggested Schema Types to Test
Article — Blog posts, news articles
Recipe — Food/cooking content
Product — E-commerce items
Event — Event listings
LocalBusiness — Business information
FAQPage — FAQ content
Testing Mindset & Environments
The validation process involves two distinct testing approaches that we recommend are performed in different environments:
Validation & Exploration (Staging/Dev Site)
Goal: This is the environment to manually validate the feature’s core functionality, including the field mapping UI and the generated JSON-LD structure. Test the inference logic and ensure the output validates correctly using tools like the Google Rich Results Test.
Focus: Logic and stability. Performance is not relevant here as the content is not being consumed by search engines.
Performance & Impact (Production Site)
Goal: This thread is to monitor the real-world impact of the generated structured data on performance and LLM/AI consumption. Configure on production and monitor changes in AI Overviews, ChatGPT responses, and search visibility over a few weeks.
Focus: Page load performance and impact on content discovery/indexing by AI systems.
acf/register_block_type_args
Description
Filters the arguments for registering a block type.
This filter is applied during the acf_register_block_type() function after defaults have been merged and before the block type has been registered.
Changelog
Added in version 5.8.9
Parameters
apply_filters( 'acf/register_block_type_args', $args );
$args (array) The array of arguments for registering a block type.
Example
This example demonstrates how to apply a custom render callback for all block types.
functions.php
Some extra HTML.';
}
// Apply to all fields.
add_action('acf/render_field', 'my_acf_render_field');
// Apply to image fields.
// add_action('acf/render_field/type=image', 'my_acf_render_field');
// Apply to fields named "hero_text".
// add_action('acf/render_field/name=hero_text', 'my_acf_render_field');
// Apply to field with key "field_123abcf".
// add_action('acf/render_field/key=field_123abcf', 'my_acf_render_field');
Notes
Priority
In order to hook-in before ACF outputs any field HTML, use a priority less than 10 with either the "global" or "type" action names.
acf/save_post
Description
Fires when saving the submitted
$_POST data.
This action allows you to hook in before or after the
$_POST data has been saved, making it useful to perform additional functionality when updating a post or other WP object.
Parameters
do_action( 'acf/save_post', $post_id );
$post_id (int|string) The ID of the post being edited.
Changelog
Changed namespace from
$_POST['fields'] to
$_POST['acf'] in version 5.0.0
Added in version 4.0.0
Examples
Applied after save
This example demonstrates how to perform additional functionality after ACF has saved the
$_POST data.
functions.php
add_action('acf/save_post', 'my_acf_save_post');
function my_acf_save_post( $post_id ) {
// Get newly saved values.
$values = get_fields( $post_id );
// Check the new value of a specific field.
$hero_image = get_field('hero_image', $post_id);
if( $hero_image ) {
// Do something...
}
}
Applied before save
This example demonstrates how to perform additional functionality before ACF has saved the
$_POST data by using a priority less than 10.
functions.php
add_action('acf/save_post', 'my_acf_save_post', 5);
function my_acf_save_post( $post_id ) {
// Get previous values.
$prev_values = get_fields( $post_id );
// Get submitted values.
$values = $_POST['acf'];
// Check if a specific value was updated.
if( isset($_POST['acf']['field_abc123']) ) {
// Do something.
}
}
Notes
Parameters
Unlike the WordPress save_post action, this action does not contain the
$post and
$updated parameters. If you require access to these parameters, consider using an alternative action instead.
acf/schema/auto_add_author
Control whether to automatically add author information to JSON-LD output.
Description
By default, ACF automatically includes the post author in the JSON-LD output as a
Person object with name and URL. This filter allows you to disable this behavior for specific posts or post types.
Changelog
Added in version 6.8.0
Parameters
apply_filters( 'acf/schema/auto_add_author', $add_author, $post, $post_type );
$add_author (bool) Whether to add the author. Default:
true
$post (WP_Post) The post object
$post_type (string) The post type name
Return
(bool) Whether to add author information to JSON-LD output.
Example
This example disables auto author for pages.
/**
* Disable auto author for pages.
*
* @param bool $add_author Whether to add author.
* @param WP_Post $post The post object.
* @param string $post_type The post type.
* @return bool Whether to add author.
*/
function my_acf_schema_disable_page_author( $add_author, $post, $post_type ) {
if ( $post_type === 'page' ) {
return false;
}
return $add_author;
}
add_filter( 'acf/schema/auto_add_author', 'my_acf_schema_disable_page_author', 10, 3 );
This example disables auto author when using a custom author ACF field.
/**
* Disable auto author when custom author field exists.
*
* @param bool $add_author Whether to add author.
* @param WP_Post $post The post object.
* @param string $post_type The post type.
* @return bool Whether to add author.
*/
function my_acf_schema_custom_author_field( $add_author, $post, $post_type ) {
// If we have a custom author field mapped, don't add the auto author
$custom_author = get_field( 'article_author', $post->ID );
if ( $custom_author ) {
return false;
}
return $add_author;
}
add_filter( 'acf/schema/auto_add_author', 'my_acf_schema_custom_author_field', 10, 3 );
acf/schema/auto_add_image
Control whether to automatically add the featured image to JSON-LD output.
Description
By default, ACF automatically includes the post’s featured image in the JSON-LD output as an
ImageObject. This filter allows you to disable this behavior for specific posts or post types.
Changelog
Added in version 6.8.0
Parameters
apply_filters( 'acf/schema/auto_add_image', $add_image, $post, $post_type );
$add_image (bool) Whether to add the featured image. Default:
true
$post (WP_Post) The post object
$post_type (string) The post type name
Return
(bool) Whether to add the featured image to JSON-LD output.
Example
This example disables auto image for products (using a custom ACF image field instead).
/**
* Disable auto image for products.
*
* @param bool $add_image Whether to add featured image.
* @param WP_Post $post The post object.
* @param string $post_type The post type.
* @return bool Whether to add featured image.
*/
function my_acf_schema_disable_product_image( $add_image, $post, $post_type ) {
if ( $post_type === 'product' ) {
return false;
}
return $add_image;
}
add_filter( 'acf/schema/auto_add_image', 'my_acf_schema_disable_product_image', 10, 3 );
This example only adds images for posts with a featured image set.
/**
* Only add image if featured image exists.
*
* @param bool $add_image Whether to add featured image.
* @param WP_Post $post The post object.
* @param string $post_type The post type.
* @return bool Whether to add featured image.
*/
function my_acf_schema_require_featured_image( $add_image, $post, $post_type ) {
if ( ! has_post_thumbnail( $post->ID ) ) {
return false;
}
return $add_image;
}
add_filter( 'acf/schema/auto_add_image', 'my_acf_schema_require_featured_image', 10, 3 );
acf/schema/block_field_objects/block_name={block_name}
Filter field objects for a specific block type.
Description
This filter is a block-specific version of
acf/schema/block_field_objects. It allows you to modify field objects only for a specific block type without affecting other blocks.
The dynamic portion of the hook name,
{block_name}, refers to the full block name (e.g.,
acf/recipe).
Changelog
Added in version 6.8.0
Parameters
apply_filters( 'acf/schema/block_field_objects/block_name={block_name}', $field_objects, $block, $block_type, $post_id );
$field_objects (array|null) Field objects array from previous filters
$block (array) The block props array
$block_type (array) The registered block type settings
$post_id (int) The post ID where the block appears
Return
(array|null) Modified field objects array.
Example
This example adds nutrition data to a recipe block.
/**
* Add nutrition schema to recipe block.
*
* @param array|null $field_objects The field objects array.
* @param array $block The block props.
* @param array $block_type The block type settings.
* @param int $post_id The post ID.
* @return array Modified field objects.
*/
function my_acf_schema_recipe_nutrition( $field_objects, $block, $block_type, $post_id ) {
if ( null === $field_objects ) {
$field_objects = array();
}
// Add nutrition fields with NutritionInformation qualified properties
if ( isset( $block['data']['calories'] ) ) {
$field_objects['calories'] = array(
'value' => $block['data']['calories'] . ' calories',
'schema_property' => 'NutritionInformation.calories',
'type' => 'text',
);
}
if ( isset( $block['data']['protein'] ) ) {
$field_objects['protein'] = array(
'value' => $block['data']['protein'] . ' g',
'schema_property' => 'NutritionInformation.proteinContent',
'type' => 'text',
);
}
return $field_objects;
}
add_filter( 'acf/schema/block_field_objects/block_name=acf/recipe', 'my_acf_schema_recipe_nutrition', 10, 4 );
acf/schema/block_field_objects
Filter field objects before processing for a block.
Description
This filter allows you to modify or replace the field objects that are processed for JSON-LD output on ACF blocks. Return a non-null value to override the default field retrieval.
Changelog
Added in version 6.8.0
Parameters
apply_filters( 'acf/schema/block_field_objects', $field_objects, $block, $block_type, $post_id );
$field_objects (array|null) Field objects array, or null to use default retrieval
$block (array) The block props array
$block_type (array) The registered block type settings
$post_id (int) The post ID where the block appears
Return
(array|null) Modified field objects array, or null to use default behavior.
Example
This example adds computed fields to a recipe block.
/**
* Add computed fields to recipe block JSON-LD.
*
* @param array|null $field_objects The field objects array.
* @param array $block The block props.
* @param array $block_type The block type settings.
* @param int $post_id The post ID.
* @return array Modified field objects.
*/
function my_acf_schema_recipe_block_fields( $field_objects, $block, $block_type, $post_id ) {
if ( $block['name'] !== 'acf/recipe' ) {
return $field_objects;
}
if ( null === $field_objects ) {
$field_objects = array();
}
// Calculate total time from block data
$prep_time = $block['data']['prep_time'] ?? 0;
$cook_time = $block['data']['cook_time'] ?? 0;
$field_objects['total_time'] = array(
'value' => $prep_time + $cook_time,
'schema_property' => 'totalTime',
'type' => 'number',
);
return $field_objects;
}
add_filter( 'acf/schema/block_field_objects', 'my_acf_schema_recipe_block_fields', 10, 4 );
acf/schema/block_jsonld_enabled
Enable or disable JSON-LD output for specific blocks.
Description
This filter allows you to programmatically control whether JSON-LD output is enabled for specific ACF blocks. This runs after checking the block’s
autoJsonLd setting, allowing you to override the default behavior.
Changelog
Added in version 6.8.0
Parameters
apply_filters( 'acf/schema/block_jsonld_enabled', $enabled, $block, $block_type );
$enabled (bool) Whether JSON-LD is enabled for this block (from
autoJsonLd setting)
$block (array) The block props array containing block data
$block_type (array) The registered block type settings
Return
(bool) Whether to output JSON-LD for this block.
Example
This example enables JSON-LD for all recipe blocks regardless of settings.
/**
* Force enable JSON-LD for recipe blocks.
*
* @param bool $enabled Whether JSON-LD is enabled.
* @param array $block The block props.
* @param array $block_type The block type settings.
* @return bool Whether to enable JSON-LD.
*/
function my_acf_schema_enable_recipe_blocks( $enabled, $block, $block_type ) {
if ( $block['name'] === 'acf/recipe' ) {
return true;
}
return $enabled;
}
add_filter( 'acf/schema/block_jsonld_enabled', 'my_acf_schema_enable_recipe_blocks', 10, 3 );
This example disables JSON-LD for blocks in preview mode.
/**
* Disable JSON-LD in preview context.
*
* @param bool $enabled Whether JSON-LD is enabled.
* @param array $block The block props.
* @param array $block_type The block type settings.
* @return bool Whether to enable JSON-LD.
*/
function my_acf_schema_disable_preview_jsonld( $enabled, $block, $block_type ) {
if ( isset( $block['data']['preview'] ) && $block['data']['preview'] ) {
return false;
}
return $enabled;
}
add_filter( 'acf/schema/block_jsonld_enabled', 'my_acf_schema_disable_preview_jsonld', 10, 3 );
acf/schema/data
Filter the final JSON-LD data before output.
Description
This filter allows you to modify the complete JSON-LD structured data array before it is rendered to the page. Use this to add custom properties, modify existing values, or conditionally alter the output based on the post or block context.
This filter runs for both post-based and block-based JSON-LD output.
Changelog
Added in version 6.8.0
Parameters
apply_filters( 'acf/schema/data', $data, $object, $type );
$data (array) The JSON-LD data array containing all mapped properties
$object (WP_Post|array) The post object (for posts) or block array (for blocks)
$type (string|array) The post type name or block type settings
Return
(array) The modified JSON-LD data array.
Example
This example adds a publisher organization to all Article schema types.
/**
* Add publisher to Article JSON-LD output.
*
* @param array $data The JSON-LD data array.
* @param WP_Post|array $object The post or block object.
* @param string|array $type The post type or block type.
* @return array Modified JSON-LD data.
*/
function my_acf_schema_add_publisher( $data, $object, $type ) {
// Only add publisher to Articles
if ( isset( $data['@type'] ) && $data['@type'] === 'Article' ) {
$data['publisher'] = array(
'@type' => 'Organization',
'name' => get_bloginfo( 'name' ),
'url' => home_url(),
'logo' => array(
'@type' => 'ImageObject',
'url' => get_site_icon_url(),
),
);
}
return $data;
}
add_filter( 'acf/schema/data', 'my_acf_schema_add_publisher', 10, 3 );
acf/schema/debug
Enable debug HTML comments showing JSON-LD processing steps.
Description
This filter enables debug mode for JSON-LD output. When enabled, ACF outputs HTML comments showing each step of the JSON-LD processing, including which post types are checked, which fields are found, and why output may be skipped.
This is useful for troubleshooting when JSON-LD is not appearing as expected.
Changelog
Added in version 6.8.0
Parameters
apply_filters( 'acf/schema/debug', $debug );
$debug (bool) Whether to output debug comments. Default:
false
Return
(bool) Whether debug mode is enabled.
Example
This example enables debug mode.
add_filter( 'acf/schema/debug', '__return_true' );
This example enables debug mode only for administrators.
/**
* Enable JSON-LD debug mode for admins only.
*
* @param bool $debug Whether debug mode is enabled.
* @return bool Modified debug setting.
*/
function my_acf_schema_debug_for_admins( $debug ) {
if ( current_user_can( 'manage_options' ) ) {
return true;
}
return $debug;
}
add_filter( 'acf/schema/debug', 'my_acf_schema_debug_for_admins' );
Debug Output
When enabled, you’ll see HTML comments like:
Or when output is skipped:
acf/schema/disable_output
Disable JSON-LD output for a specific data set.
Description
This filter allows you to conditionally prevent JSON-LD output based on the data that would be rendered. Unlike
acf/schema/enabled_post_types which controls output at the post type level, this filter runs after data processing and allows you to inspect the actual JSON-LD data before deciding whether to output it.
Changelog
Added in version 6.8.0
Parameters
apply_filters( 'acf/schema/disable_output', $disable, $jsonld_data );
$disable (bool) Whether to disable output. Default:
false
$jsonld_data (array) The complete JSON-LD data array that would be output
Return
(bool) Whether to disable JSON-LD output for this data.
Example
This example disables output when no custom fields have been mapped.
/**
* Disable JSON-LD if only auto-generated data exists.
*
* @param bool $disable Whether to disable output.
* @param array $jsonld_data The JSON-LD data array.
* @return bool Whether to disable output.
*/
function my_acf_schema_require_mapped_fields( $disable, $jsonld_data ) {
// Check if we only have auto-generated properties
$auto_properties = array( '@context', '@type', 'name', 'url', 'datePublished', 'dateModified', 'author', 'image' );
$custom_properties = array_diff( array_keys( $jsonld_data ), $auto_properties );
if ( empty( $custom_properties ) ) {
return true; // Disable output
}
return $disable;
}
add_filter( 'acf/schema/disable_output', 'my_acf_schema_require_mapped_fields', 10, 2 );
This example disables output for specific schema types.
/**
* Disable JSON-LD for Person schema type.
*
* @param bool $disable Whether to disable output.
* @param array $jsonld_data The JSON-LD data array.
* @return bool Whether to disable output.
*/
function my_acf_schema_disable_person( $disable, $jsonld_data ) {
if ( isset( $jsonld_data['@type'] ) && $jsonld_data['@type'] === 'Person' ) {
return true;
}
return $disable;
}
add_filter( 'acf/schema/disable_output', 'my_acf_schema_disable_person', 10, 2 );
acf/schema/enabled_post_types
Filter the list of post types that have JSON-LD output enabled.
Description
This filter allows you to programmatically enable JSON-LD output for post types without using the admin UI. This is useful for enabling JSON-LD on post types registered by other plugins or for dynamically controlling which post types output structured data.
Changelog
Added in version 6.8.0
Parameters
apply_filters( 'acf/schema/enabled_post_types', $post_types );
$post_types (array) Array of post type names that have JSON-LD enabled via the admin UI
Return
(array) The modified array of post type names.
Example
This example enables JSON-LD output for WooCommerce products.
/**
* Enable JSON-LD for WooCommerce products.
*
* @param array $post_types Array of enabled post type names.
* @return array Modified array of post type names.
*/
function my_acf_schema_enable_products( $post_types ) {
$post_types[] = 'product';
return $post_types;
}
add_filter( 'acf/schema/enabled_post_types', 'my_acf_schema_enable_products' );
This example conditionally enables JSON-LD based on environment.
/**
* Only enable JSON-LD on production.
*
* @param array $post_types Array of enabled post type names.
* @return array Modified array of post type names.
*/
function my_acf_schema_production_only( $post_types ) {
if ( wp_get_environment_type() !== 'production' ) {
return array(); // Disable all JSON-LD output
}
return $post_types;
}
add_filter( 'acf/schema/enabled_post_types', 'my_acf_schema_production_only' );
acf/schema/format_value/name={field_name}
Filter formatted values for a specific field name.
Description
This filter is a field name specific version of
acf/schema/format_value. It allows you to modify formatted values only for fields with a specific name.
The dynamic portion of the hook name,
{field_name}, refers to the ACF field name.
Changelog
Added in version 6.8.0
Parameters
apply_filters( 'acf/schema/format_value/name={field_name}', $formatted_value, $value, $field_object );
$formatted_value (mixed) The value after default formatting
$value (mixed) The original raw field value
$field_object (array) The field object with settings
Return
(mixed) The modified formatted value.
Example
This example formats a price field with currency.
/**
* Format price field with currency symbol.
*
* @param mixed $formatted_value The formatted value.
* @param mixed $value The raw value.
* @param array $field_object The field object.
* @return mixed Modified value.
*/
function my_acf_schema_format_price( $formatted_value, $value, $field_object ) {
// Ensure 2 decimal places
return number_format( (float) $formatted_value, 2, '.', '' );
}
add_filter( 'acf/schema/format_value/name=price', 'my_acf_schema_format_price', 10, 3 );
This example converts duration minutes to ISO 8601 format.
/**
* Convert duration field to ISO 8601.
*
* @param mixed $formatted_value The formatted value.
* @param mixed $value The raw value (minutes).
* @param array $field_object The field object.
* @return string ISO 8601 duration.
*/
function my_acf_schema_format_duration( $formatted_value, $value, $field_object ) {
$minutes = (int) $value;
$hours = floor( $minutes / 60 );
$mins = $minutes % 60;
if ( $hours > 0 ) {
return sprintf( 'PT%dH%dM', $hours, $mins );
}
return sprintf( 'PT%dM', $mins );
}
add_filter( 'acf/schema/format_value/name=cooking_time', 'my_acf_schema_format_duration', 10, 3 );
add_filter( 'acf/schema/format_value/name=prep_time', 'my_acf_schema_format_duration', 10, 3 );
acf/schema/format_value/pre/name={field_name}
Pre-filter values for a specific field name before default formatting.
Description
This filter is a field name specific version of
acf/schema/format_value/pre. It allows you to pre-process values before ACF’s default formatting, but only for a specific field name.
The dynamic portion of the hook name,
{field_name}, refers to the ACF field name.
Changelog
Added in version 6.8.0
Parameters
apply_filters( 'acf/schema/format_value/pre/name={field_name}', $pre_value, $value, $field_object );
$pre_value (mixed) Pre-formatted value from previous filters, or null
$value (mixed) The raw field value
$field_object (array) The field object with settings
Return
(mixed|null) The pre-formatted value, or null to use default formatting.
Example
This example provides custom formatting for a specific event date field.
/**
* Custom date formatting for event_date field.
*
* @param mixed $pre_value Pre-formatted value or null.
* @param mixed $value The raw value (date string).
* @param array $field_object The field object.
* @return mixed Pre-formatted value or null.
*/
function my_acf_schema_format_event_date( $pre_value, $value, $field_object ) {
if ( ! $value ) {
return $pre_value;
}
// Convert to ISO 8601 with timezone
$date = DateTime::createFromFormat( 'Y-m-d H:i:s', $value );
if ( ! $date ) {
return $pre_value;
}
// Set timezone from WordPress settings
$timezone = wp_timezone();
$date->setTimezone( $timezone );
return $date->format( 'c' );
}
add_filter( 'acf/schema/format_value/pre/name=event_date', 'my_acf_schema_format_event_date', 10, 3 );
This example enriches a product SKU field with additional data.
/**
* Enrich product_sku field with full product data.
*
* @param mixed $pre_value Pre-formatted value or null.
* @param mixed $value The raw SKU value.
* @param array $field_object The field object.
* @return mixed Pre-formatted value or null.
*/
function my_acf_schema_format_product_sku( $pre_value, $value, $field_object ) {
if ( ! $value ) {
return $pre_value;
}
// Look up product by SKU in external system
$product = my_get_product_by_sku( $value );
if ( ! $product ) {
return $value; // Return SKU as-is
}
return array(
'@type' => 'Product',
'sku' => $value,
'name' => $product->name,
'description' => $product->description,
'offers' => array(
'@type' => 'Offer',
'price' => $product->price,
'priceCurrency' => 'USD',
),
);
}
add_filter( 'acf/schema/format_value/pre/name=product_sku', 'my_acf_schema_format_product_sku', 10, 3 );
acf/schema/format_value/pre/type={field_type}
Pre-filter values for a specific field type before default formatting.
Description
This filter is a field type specific version of
acf/schema/format_value/pre. It allows you to pre-process values before ACF’s default formatting, but only for a specific field type.
The dynamic portion of the hook name,
{field_type}, refers to the ACF field type.
Changelog
Added in version 6.8.0
Parameters
apply_filters( 'acf/schema/format_value/pre/type={field_type}', $pre_value, $value, $field_object );
$pre_value (mixed) Pre-formatted value from previous filters, or null
$value (mixed) The raw field value
$field_object (array) The field object with settings
Return
(mixed|null) The pre-formatted value, or null to use default formatting.
Example
This example provides custom user formatting.
/**
* Custom user field formatting for Person schema.
*
* @param mixed $pre_value Pre-formatted value or null.
* @param mixed $value The raw value (user ID or array).
* @param array $field_object The field object.
* @return mixed Pre-formatted value or null.
*/
function my_acf_schema_format_user( $pre_value, $value, $field_object ) {
if ( ! $value ) {
return $pre_value;
}
$user_id = is_array( $value ) ? $value['ID'] : $value;
$user = get_userdata( $user_id );
if ( ! $user ) {
return $pre_value;
}
return array(
'@type' => 'Person',
'name' => $user->display_name,
'url' => get_author_posts_url( $user_id ),
'email' => $user->user_email,
'sameAs' => array(
get_user_meta( $user_id, 'twitter', true ),
get_user_meta( $user_id, 'linkedin', true ),
),
);
}
add_filter( 'acf/schema/format_value/pre/type=user', 'my_acf_schema_format_user', 10, 3 );
acf/schema/format_value/pre
Filter a field value before default formatting is applied.
Description
This filter allows you to modify or replace field values before ACF applies its default JSON-LD formatting. Return a non-null value to bypass the default formatting entirely.
Changelog
Added in version 6.8.0
Parameters
apply_filters( 'acf/schema/format_value/pre', $pre_value, $value, $field_object, $field_type );
$pre_value (mixed) Pre-formatted value, or null to use default formatting
$value (mixed) The raw field value
$field_object (array) The field object with settings
$field_type (string) The field type name
Return
(mixed|null) The pre-formatted value, or null to use default formatting.
Example
This example provides custom duration formatting.
/**
* Custom ISO 8601 duration formatting.
*
* @param mixed $pre_value Pre-formatted value or null.
* @param mixed $value The raw value.
* @param array $field_object The field object.
* @param string $field_type The field type.
* @return mixed Pre-formatted value or null.
*/
function my_acf_schema_duration_format( $pre_value, $value, $field_object, $field_type ) {
$property = $field_object['schema_property'] ?? '';
// Handle duration properties
$duration_properties = array( 'prepTime', 'cookTime', 'totalTime', 'duration' );
if ( in_array( $property, $duration_properties, true ) && is_numeric( $value ) ) {
$hours = floor( $value / 60 );
$minutes = $value % 60;
if ( $hours > 0 && $minutes > 0 ) {
return sprintf( 'PT%dH%dM', $hours, $minutes );
} elseif ( $hours > 0 ) {
return sprintf( 'PT%dH', $hours );
} else {
return sprintf( 'PT%dM', $minutes );
}
}
return $pre_value; // Use default formatting
}
add_filter( 'acf/schema/format_value/pre', 'my_acf_schema_duration_format', 10, 4 );
This example handles custom date formatting.
/**
* Custom date formatting for events.
*
* @param mixed $pre_value Pre-formatted value or null.
* @param mixed $value The raw value.
* @param array $field_object The field object.
* @param string $field_type The field type.
* @return mixed Pre-formatted value or null.
*/
function my_acf_schema_event_dates( $pre_value, $value, $field_object, $field_type ) {
$property = $field_object['schema_property'] ?? '';
// Format event dates with timezone
if ( in_array( $property, array( 'startDate', 'endDate' ), true ) && $value ) {
$timestamp = strtotime( $value );
if ( $timestamp ) {
return date( 'c', $timestamp ); // ISO 8601 with timezone
}
}
return $pre_value;
}
add_filter( 'acf/schema/format_value/pre', 'my_acf_schema_event_dates', 10, 4 );
acf/schema/format_value/type={field_type}
Filter formatted values for a specific field type.
Description
This filter is a field type specific version of
acf/schema/format_value. It allows you to modify formatted values only for a specific ACF field type.
The dynamic portion of the hook name,
{field_type}, refers to the ACF field type (e.g.,
text,
number,
image).
Changelog
Added in version 6.8.0
Parameters
apply_filters( 'acf/schema/format_value/type={field_type}', $formatted_value, $value, $field_object );
$formatted_value (mixed) The value after default formatting
$value (mixed) The original raw field value
$field_object (array) The field object with settings
Return
(mixed) The modified formatted value.
Example
This example ensures all number fields output as floats.
/**
* Format numbers as floats.
*
* @param mixed $formatted_value The formatted value.
* @param mixed $value The raw value.
* @param array $field_object The field object.
* @return mixed Modified value.
*/
function my_acf_schema_format_numbers( $formatted_value, $value, $field_object ) {
return (float) $formatted_value;
}
add_filter( 'acf/schema/format_value/type=number', 'my_acf_schema_format_numbers', 10, 3 );
This example customizes image output format.
/**
* Custom image formatting with additional metadata.
*
* @param mixed $formatted_value The formatted value.
* @param mixed $value The raw value (attachment ID).
* @param array $field_object The field object.
* @return mixed Modified value.
*/
function my_acf_schema_format_images( $formatted_value, $value, $field_object ) {
if ( ! is_array( $formatted_value ) || ! isset( $formatted_value['@type'] ) ) {
return $formatted_value;
}
// Add license info to all images
$formatted_value['license'] = 'https://creativecommons.org/licenses/by/4.0/';
// Add content URL
if ( isset( $formatted_value['url'] ) ) {
$formatted_value['contentUrl'] = $formatted_value['url'];
}
return $formatted_value;
}
add_filter( 'acf/schema/format_value/type=image', 'my_acf_schema_format_images', 10, 3 );
acf/schema/format_value
Filter a field value after default formatting is applied.
Description
This filter allows you to modify field values after ACF has applied its default JSON-LD formatting. Use this for post-processing values or applying custom transformations.
For pre-processing before default formatting, use
acf/schema/format_value/pre.
Changelog
Added in version 6.8.0
Parameters
apply_filters( 'acf/schema/format_value', $formatted_value, $value, $field_object, $field_type );
$formatted_value (mixed) The value after default formatting
$value (mixed) The original raw field value
$field_object (array) The field object with settings
$field_type (string) The field type name
Return
(mixed) The modified formatted value.
Example
This example ensures prices always have 2 decimal places.
/**
* Format prices with 2 decimal places.
*
* @param mixed $formatted_value The formatted value.
* @param mixed $value The raw value.
* @param array $field_object The field object.
* @param string $field_type The field type.
* @return mixed Modified value.
*/
function my_acf_schema_format_prices( $formatted_value, $value, $field_object, $field_type ) {
$property = $field_object['schema_property'] ?? '';
if ( $property === 'Offer.price' || $property === 'price' ) {
return number_format( (float) $formatted_value, 2, '.', '' );
}
return $formatted_value;
}
add_filter( 'acf/schema/format_value', 'my_acf_schema_format_prices', 10, 4 );
This example converts plain text URLs to proper link objects.
/**
* Convert URLs to WebPage objects.
*
* @param mixed $formatted_value The formatted value.
* @param mixed $value The raw value.
* @param array $field_object The field object.
* @param string $field_type The field type.
* @return mixed Modified value.
*/
function my_acf_schema_format_urls( $formatted_value, $value, $field_object, $field_type ) {
$property = $field_object['schema_property'] ?? '';
// Convert mainEntityOfPage to WebPage object
if ( $property === 'mainEntityOfPage' && is_string( $formatted_value ) ) {
return array(
'@type' => 'WebPage',
'@id' => $formatted_value,
);
}
return $formatted_value;
}
add_filter( 'acf/schema/format_value', 'my_acf_schema_format_urls', 10, 4 );
acf/schema/output_format_choices
Filter available output format choices for a field type and property combination.
Description
This filter allows you to modify the list of output format choices available when configuring a field’s Schema.org property mapping. Formats determine how field values are transformed for JSON-LD output.
Changelog
Added in version 6.8.0
Parameters
apply_filters( 'acf/schema/output_format_choices', $choices, $field_type, $property );
$choices (array) Array of format choices (key => label)
$field_type (string) The ACF field type
$property (string) The Schema.org property name
Return
(array) The modified format choices array.
Example
This example adds a custom format option.
/**
* Add custom output format choice.
*
* @param array $choices Format choices.
* @param string $field_type The ACF field type.
* @param string $property The Schema.org property.
* @return array Modified choices.
*/
function my_acf_schema_add_format( $choices, $field_type, $property ) {
if ( $field_type === 'number' && in_array( $property, array( 'price', 'Offer.price' ), true ) ) {
$choices['currency'] = 'Currency (with symbol)';
}
return $choices;
}
add_filter( 'acf/schema/output_format_choices', 'my_acf_schema_add_format', 10, 3 );
This example removes format options for specific properties.
/**
* Limit format choices for duration properties.
*
* @param array $choices Format choices.
* @param string $field_type The ACF field type.
* @param string $property The Schema.org property.
* @return array Modified choices.
*/
function my_acf_schema_duration_formats( $choices, $field_type, $property ) {
$duration_properties = array( 'prepTime', 'cookTime', 'totalTime', 'duration' );
if ( in_array( $property, $duration_properties, true ) ) {
// Only allow ISO 8601 duration format
return array(
'duration' => 'ISO 8601 Duration',
);
}
return $choices;
}
add_filter( 'acf/schema/output_format_choices', 'my_acf_schema_duration_formats', 10, 3 );
acf/schema/post_field_objects/post_type={post_type}
Filter field objects for a specific post type.
Description
This filter is a post type specific version of
acf/schema/post_field_objects. It allows you to modify field objects only for a specific post type without affecting other post types.
The dynamic portion of the hook name,
{post_type}, refers to the post type slug.
Changelog
Added in version 6.8.0
Parameters
apply_filters( 'acf/schema/post_field_objects/post_type={post_type}', $field_objects, $post );
$field_objects (array|null) Field objects array from previous filters
$post (WP_Post) The post object
Return
(array|null) Modified field objects array.
Example
This example adds product-specific data for WooCommerce products.
/**
* Add WooCommerce product data to JSON-LD.
*
* @param array|null $field_objects The field objects array.
* @param WP_Post $post The post object.
* @return array Modified field objects.
*/
function my_acf_schema_product_fields( $field_objects, $post ) {
if ( null === $field_objects ) {
$field_objects = get_field_objects( $post->ID, false );
}
if ( ! is_array( $field_objects ) ) {
$field_objects = array();
}
// Get WooCommerce product
$product = wc_get_product( $post->ID );
if ( ! $product ) {
return $field_objects;
}
// Add price as Offer
$field_objects['wc_price'] = array(
'value' => $product->get_price(),
'schema_property' => 'Offer.price',
'type' => 'number',
);
$field_objects['wc_currency'] = array(
'value' => get_woocommerce_currency(),
'schema_property' => 'Offer.priceCurrency',
'type' => 'text',
);
$field_objects['wc_availability'] = array(
'value' => $product->is_in_stock() ? 'https://schema.org/InStock' : 'https://schema.org/OutOfStock',
'schema_property' => 'Offer.availability',
'type' => 'url',
);
return $field_objects;
}
add_filter( 'acf/schema/post_field_objects/post_type=product', 'my_acf_schema_product_fields', 10, 2 );
This example adds recipe-specific calculated fields.
/**
* Add calculated fields for recipes.
*
* @param array|null $field_objects The field objects array.
* @param WP_Post $post The post object.
* @return array Modified field objects.
*/
function my_acf_schema_recipe_fields( $field_objects, $post ) {
if ( null === $field_objects ) {
$field_objects = get_field_objects( $post->ID, false );
}
if ( ! is_array( $field_objects ) ) {
$field_objects = array();
}
// Add recipe category from taxonomy
$categories = get_the_terms( $post->ID, 'recipe_category' );
if ( $categories && ! is_wp_error( $categories ) ) {
$field_objects['recipe_category'] = array(
'value' => $categories[0]->name,
'schema_property' => 'recipeCategory',
'type' => 'text',
);
}
return $field_objects;
}
add_filter( 'acf/schema/post_field_objects/post_type=recipe', 'my_acf_schema_recipe_fields', 10, 2 );
acf/schema/post_field_objects
Filter field objects before processing for a post.
Description
This filter allows you to modify or replace the field objects that are processed for JSON-LD output on posts. Return a non-null value to override the default field retrieval via
get_field_objects().
This is useful for adding custom data sources, filtering out specific fields, or providing field data from alternative sources.
Changelog
Added in version 6.8.0
Parameters
apply_filters( 'acf/schema/post_field_objects', $field_objects, $post, $post_type );
$field_objects (array|null) Field objects array, or null to use default retrieval
$post (WP_Post) The post object
$post_type (string) The post type name
Return
(array|null) Modified field objects array, or null to use default behavior.
Example
This example adds a virtual field for calculated data.
/**
* Add calculated field to JSON-LD output.
*
* @param array|null $field_objects The field objects array.
* @param WP_Post $post The post object.
* @param string $post_type The post type.
* @return array Modified field objects.
*/
function my_acf_schema_add_calculated_field( $field_objects, $post, $post_type ) {
// Get default field objects if not already set
if ( null === $field_objects ) {
$field_objects = get_field_objects( $post->ID, false );
}
if ( ! is_array( $field_objects ) ) {
$field_objects = array();
}
// Add calculated total time for recipes
if ( $post_type === 'recipe' ) {
$prep_time = get_field( 'prep_time', $post->ID );
$cook_time = get_field( 'cook_time', $post->ID );
$field_objects['total_time'] = array(
'value' => $prep_time + $cook_time,
'schema_property' => 'totalTime',
'type' => 'number',
);
}
return $field_objects;
}
add_filter( 'acf/schema/post_field_objects', 'my_acf_schema_add_calculated_field', 10, 3 );
This example excludes specific fields from JSON-LD output.
/**
* Exclude internal fields from JSON-LD output.
*
* @param array|null $field_objects The field objects array.
* @param WP_Post $post The post object.
* @param string $post_type The post type.
* @return array Modified field objects.
*/
function my_acf_schema_exclude_internal_fields( $field_objects, $post, $post_type ) {
if ( null === $field_objects ) {
$field_objects = get_field_objects( $post->ID, false );
}
if ( ! is_array( $field_objects ) ) {
return $field_objects;
}
// Remove fields starting with underscore
foreach ( $field_objects as $key => $field ) {
if ( strpos( $key, '_' ) === 0 ) {
unset( $field_objects[ $key ] );
}
}
return $field_objects;
}
add_filter( 'acf/schema/post_field_objects', 'my_acf_schema_exclude_internal_fields', 10, 3 );
acf/schema/render_script
Action hook fired before the JSON-LD script tag is rendered.
Description
This action allows you to execute code immediately before the JSON-LD script tag is output to the page. This is useful for logging, analytics, or adding additional markup around the JSON-LD output.
Note: This is an action hook, not a filter. It does not modify the JSON-LD data.
Changelog
Added in version 6.8.0
Parameters
do_action( 'acf/schema/render_script', $jsonld_data );
$jsonld_data (array) The JSON-LD data array that will be rendered
Example
This example logs JSON-LD output for debugging.
/**
* Log JSON-LD data before rendering.
*
* @param array $jsonld_data The JSON-LD data array.
*/
function my_acf_schema_log_output( $jsonld_data ) {
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
error_log( 'ACF JSON-LD Output: ' . wp_json_encode( $jsonld_data ) );
}
}
add_action( 'acf/schema/render_script', 'my_acf_schema_log_output' );
This example adds a comment before the JSON-LD for identification.
/**
* Add identifying comment before JSON-LD.
*
* @param array $jsonld_data The JSON-LD data array.
*/
function my_acf_schema_add_comment( $jsonld_data ) {
$type = $jsonld_data['@type'] ?? 'Unknown';
echo '' . "\n";
}
add_action( 'acf/schema/render_script', 'my_acf_schema_add_comment' );
This example tracks which schema types are being output.
/**
* Track schema type usage.
*
* @param array $jsonld_data The JSON-LD data array.
*/
function my_acf_schema_track_usage( $jsonld_data ) {
if ( ! isset( $jsonld_data['@type'] ) ) {
return;
}
// Send to analytics
if ( function_exists( 'my_analytics_track' ) ) {
my_analytics_track( 'schema_rendered', array(
'type' => $jsonld_data['@type'],
'post_id' => get_the_ID(),
) );
}
}
add_action( 'acf/schema/render_script', 'my_acf_schema_track_usage' );
acf/schema/schema_priority_types
Filter which Schema.org types appear first in dropdowns.
Description
This filter allows you to customize which Schema.org types appear at the top of selection dropdowns. Priority types are shown first for quick access to commonly used types.
When a field group context ID is provided, types from associated post types are automatically prepended to provide context-aware suggestions.
Changelog
Added in version 6.8.0
Parameters
apply_filters( 'acf/schema/schema_priority_types', $priority_types, $context_id );
$priority_types (array) Array of priority type names
$context_id (int) Field group ID for context, or 0
Return
(array) The modified priority types array.
Example
This example adds custom types to the priority list.
/**
* Add custom priority Schema.org types.
*
* @param array $priority_types Array of priority type names.
* @param int $context_id Field group ID or 0.
* @return array Modified priority types.
*/
function my_acf_schema_priority_types( $priority_types, $context_id ) {
// Add our commonly used types to the top
array_unshift( $priority_types, 'SoftwareApplication', 'Course' );
return $priority_types;
}
add_filter( 'acf/schema/schema_priority_types', 'my_acf_schema_priority_types', 10, 2 );
This example customizes priority types based on field group context.
/**
* Context-aware priority types.
*
* @param array $priority_types Array of priority type names.
* @param int $context_id Field group ID or 0.
* @return array Modified priority types.
*/
function my_acf_schema_contextual_types( $priority_types, $context_id ) {
if ( ! $context_id ) {
return $priority_types;
}
$field_group = acf_get_field_group( $context_id );
if ( ! $field_group ) {
return $priority_types;
}
// Check field group title for context clues
$title = strtolower( $field_group['title'] );
if ( strpos( $title, 'recipe' ) !== false ) {
array_unshift( $priority_types, 'Recipe', 'HowTo' );
} elseif ( strpos( $title, 'product' ) !== false ) {
array_unshift( $priority_types, 'Product', 'Offer' );
}
return array_unique( $priority_types );
}
add_filter( 'acf/schema/schema_priority_types', 'my_acf_schema_contextual_types', 10, 2 );
acf/schema/schema_properties
Filter available Schema.org properties for a field type.
Description
This filter allows you to modify the list of Schema.org properties available in the field settings dropdown. Properties are filtered by field type compatibility and organized by Schema.org type.
Changelog
Added in version 6.8.0
Parameters
apply_filters( 'acf/schema/schema_properties', $properties, $field_type );
$properties (array) Hierarchical array of properties grouped by Schema.org type
$field_type (string) The ACF field type (e.g.,
text,
number,
image)
Return
(array) The modified properties array.
Example
This example adds custom properties for text fields.
/**
* Add custom Schema.org properties.
*
* @param array $properties Grouped array of properties.
* @param string $field_type The ACF field type.
* @return array Modified properties.
*/
function my_acf_schema_add_properties( $properties, $field_type ) {
if ( $field_type === 'text' ) {
// Add custom properties for text fields
$properties['Custom'] = array(
'customProperty' => 'customProperty',
'internalCode' => 'internalCode',
);
}
return $properties;
}
add_filter( 'acf/schema/schema_properties', 'my_acf_schema_add_properties', 10, 2 );
This example removes properties that shouldn’t be used.
/**
* Remove deprecated Schema.org properties.
*
* @param array $properties Grouped array of properties.
* @param string $field_type The ACF field type.
* @return array Modified properties.
*/
function my_acf_schema_remove_deprecated( $properties, $field_type ) {
// Remove deprecated properties from all types
foreach ( $properties as $type => &$props ) {
if ( is_array( $props ) ) {
unset( $props['deprecatedProperty'] );
}
}
return $properties;
}
add_filter( 'acf/schema/schema_properties', 'my_acf_schema_remove_deprecated', 10, 2 );
acf/schema/schema_types
Filter available Schema.org types in admin dropdowns.
Description
This filter allows you to modify the list of Schema.org types available in the admin UI when configuring post types and blocks. Types are organized in groups for easier navigation.
Changelog
Added in version 6.8.0
Parameters
apply_filters( 'acf/schema/schema_types', $types );
$types (array) Hierarchical array of types grouped by category
Return
(array) The modified types array.
Example
This example adds custom Schema.org types.
/**
* Add custom Schema.org types.
*
* @param array $types Grouped array of Schema.org types.
* @return array Modified types array.
*/
function my_acf_schema_add_types( $types ) {
// Add custom types group
$types['Custom Types'] = array(
'SoftwareApplication' => 'SoftwareApplication',
'MobileApplication' => 'MobileApplication',
'WebApplication' => 'WebApplication',
);
return $types;
}
add_filter( 'acf/schema/schema_types', 'my_acf_schema_add_types' );
This example removes types not needed for your site.
/**
* Remove unused Schema.org types.
*
* @param array $types Grouped array of Schema.org types.
* @return array Modified types array.
*/
function my_acf_schema_remove_types( $types ) {
// Remove types we don't use
if ( isset( $types['Common Types'] ) ) {
unset( $types['Common Types']['Recipe'] );
unset( $types['Common Types']['Event'] );
}
return $types;
}
add_filter( 'acf/schema/schema_types', 'my_acf_schema_remove_types' );
ACF Security Principles
Introduction
Advanced Custom Fields is a plugin for WordPress that allows you to easily store custom data attached to WordPress data types, such as posts, pages, users, taxonomies, etc.
This additional data is stored in the database in either associated meta tables, or the WordPress options table, depending on the location where an ACF field group is displayed.
ACF uses core WordPress functionality for reading and writing from the database tables, so it directly inherits a lot of security and compatibility from WordPress core.
Security Considerations
By default, the data stored inside ACF is not publicly visible. The exception to this is when a field group or individual fields are made available via the REST API.
The ACF Shortcode has historically allowed access to any ACF field value in any location. This meant any user with access to publish posts on your site could access any field they knew the name of. The ACF Shortcode was disabled by default in ACF 6.3.0 for new installations of ACF. ACF 6.3.4 also restricted access to prevent users accessing ACF field values in non-public posts.
Version 6.3.6 of ACF introduced the new security model for accessing fields, with access to fields by editors using the ACF Shortcode or Block Bindings controlled via a new toggle in the “Presentation” tab of each field. For any fields created before 6.3.6, this value is set to true to ensure the previous behavior is inherited, but it will be set to false for any new fields created after 6.3.6.
If a user tries to access a field which is not set to “Allow Access to Value in Editor UI”, the output will be blank, but an error message will be displayed when previewing the post to explain why the value will not be shown.
We recommend users disable editor UI access to all fields unless it’s intended for content editors to be able to access the value of the field via the ACF shortcode or block bindings, especially if that field contains information that is intended to be secure, such as access keys or other secret information.
Installation
ACF is a standard WordPress plugin and can be installed as either a normal plugin or a must-use plugin.
There are no specific security considerations regarding installation, and normal WordPress plugin rules and permissions should be applied. Users installing ACF for the first time should follow the steps outlined here.
Ensuring access to security updates is critical. ACF has instituted an alternative update mechanism, as documented here. This process should be completed for every WordPress site where the free version of ACF is installed. Once completed, plugin updates should be available in the WordPress admin as normal.
Outputting ACF Data Securely
ACF will attempt to use the
unfiltered_html capability to ensure only admins can store potentially unsafe HTML, but it’s possible for users of contributor level or higher to bypass this protection using other WordPress provided methods of updating post meta. For this reason it’s very important that you escape your field values on output too.
Many users will use ACF to store potentially unsafe HTML, such as iframes or script tags, so by default, ACF does not perform any escaping when using
get_field(). Therefore, users are required to escape fields on output in their template or themes when using
get_field or
get_sub_field.
We provide
acf_esc_html as a function which can help you do this, which requires you to pass a string which will be run through the WordPress kses system. Alternatively, you could use any other escaping function, such as
wp_kses_post or
wp_kses directly, or other PHP escaping options.
Whenever possible, we recommend formatting your fields and theme so that limited HTML is stored in ACF field values and rendered by your theme. For example, instead of storing an entire HTML link tag in your field values and rendering that in your theme, you could store the link URL in your field value, and in your theme use the more specific
esc_url() function to escape it:
$link = ‘link text`
Prior to ACF 6.2.7,
the_field and
the_sub_field were also unescaped, but users had no options to escape values using these functions. Since ACF 6.2.7, these functions have handled escaping automatically with
acf_esc_html.
Since ACF 6.2.5, the output of the ACF Shortcode has also been escaped by default.
acf/settings/enable_datastore
Enables the ACF datastore, which integrates ACF fields with Gutenberg’s native
wp.data store. When enabled, ACF field values are saved through WordPress’s REST API instead of the legacy metabox AJAX request.
The datastore unlocks several capabilities:
Full revision support for ACF fields
Autosave integration
JavaScript API via
wp.data.select('acf/fields') and
wp.data.dispatch('acf/fields')
Live preview and editing for block bindings
This filter requires WordPress 6.7 or later.
Changelog
Added in version 6.8.1
Parameters
This filter has no additional parameters. Return
true to enable,
false to disable.
Example
Enable the datastore for all posts:
add_filter( 'acf/settings/enable_datastore', '__return_true' );
Enable conditionally for specific post types:
add_filter( 'acf/settings/enable_datastore', function( $enabled ) {
// Only enable for products and pages
$post_type = get_post_type();
if ( in_array( $post_type, array( 'product', 'page' ) ) ) {
return true;
}
return $enabled;
});
Disable after previously enabling (useful for troubleshooting):
add_filter( 'acf/settings/enable_datastore', '__return_false', 100 );
Notes
The datastore is disabled by default
Currently available in ACF PRO only
Custom JavaScript hooked into ACF’s legacy metabox save events may need to be updated to work with Gutenberg’s REST save flow
We recommend testing thoroughly in a staging environment before enabling on production sites
Related
Using the ACF Datastore – Full guide to the datastore feature
Block Bindings – Using ACF fields with WordPress block bindings
acf/settings/enable_options_pages_ui
Description
Used to disable the UI for registering options pages.
Changelog
Added in version 6.2.
Example
This example demonstrates how to disable the UI for registering options pages. Options pages can still be registered with PHP using the
acf_add_options_page() or
acf_add_options_sub_page() functions.
functions.php
\_\_(‘My Options’),
menu_title
(string) The title displayed in the admin menu. Defaults to ‘page_title’ value.
'menu_title' => __('My Options'),
menu_slug
(string) The URL slug used to uniquely identify this options page. Defaults to a url friendly version of menu_title.
'menu_slug' => 'my-options',
capability
(string) The capability required for this menu to be displayed to the user. Defaults to ‘edit_posts’. Read more about Roles and Capabilities.
'capability' => 'edit_posts',
position
(int|string) The position in the menu order where this menu should appear.
WARNING: if two menu items use the same position, one of the items may be overwritten. Risk of conflict can be reduced by using decimal instead of integer values, e.g. ‘63.3’ instead of 63 (must use quotes). Defaults to bottom of utility menu items.
'position' => '',
parent_slug
(string) The slug of another WP admin page. If set, this will become a child page of that parent.
'parent_slug' => 'my-parent-page',
icon_url
(string) The icon class for this menu. Defaults to default WordPress gear. Read more about Dashicons.
'icon_url' => '',
redirect
(bool) If set to true, this options page will redirect to the first child page (if a child page exists).
If set to false, this parent page will appear alongside any child pages as its own page. Defaults to true.
'redirect' => true,
post_id
(int|string) The
$post_id to save and load values from. Can be set to a numeric post ID (123), or a string (‘user_2’). Read more about the available post_id values. Defaults to ‘options’. Added in v5.2.7.
'post_id' => 'options',
autoload
(bool) Data saved in the wp_options table is given an “autoload” identifier.
When set to true, WP will automatically load these values within a single SQL query which can improve page load performance. Defaults to false. Added in v5.2.8.
'autoload' => false,
update_button
(string) The text displayed on the options page submit button. Added in v5.3.7.
'update_button' => __('Update', 'acf'),
updated_message
(string) The message shown above the form after updating the options page. Added in v5.6.0.
'updated_message' => __("Options Updated", 'acf'),
Return
(array) The validated and final page settings. This is useful to find the page’s menu_slug and use it later when adding child options pages.
Examples
Default options page
This example shows how to create the default options page.
functions.php
add_action('acf/init', function() {
if( function_exists('acf_add_options_page') ) {
acf_add_options_page();
}
} );
Customized options page
This example shows how to create a customized options page and store the data in a variable for later use.
functions.php
add_action('acf/init', 'my_acf_op_init');
function my_acf_op_init() {
// Check function exists.
if( function_exists('acf_add_options_page') ) {
// Register options page.
$option_page = acf_add_options_page(array(
'page_title' => __('Theme General Settings'),
'menu_title' => __('Theme Settings'),
'menu_slug' => 'theme-general-settings',
'capability' => 'edit_posts',
'redirect' => false
));
}
}
Creating sub pages
This example shows how to create an options sub page using the parent_slug attribute.
functions.php
add_action('acf/init', 'my_acf_op_init');
function my_acf_op_init() {
// Check function exists.
if( function_exists('acf_add_options_page') ) {
// Add parent.
$parent = acf_add_options_page(array(
'page_title' => __('Theme General Settings'),
'menu_title' => __('Theme Settings'),
'redirect' => false,
));
// Add sub page.
$child = acf_add_options_page(array(
'page_title' => __('Social Settings'),
'menu_title' => __('Social'),
'parent_slug' => $parent['menu_slug'],
));
}
}
Notes
Priority
This function must be used before the action
admin_menu (priority 99) as this is when admin pages are registered in WordPress core. We advise using the “acf/init” action.
WordPress 6.8
Since WordPress 6.8, any function that causes ACF to initialise early such as this one will trigger an PHP notice, if you call it before the
acf/init action:
Notice: Function _load_textdomain_just_in_time was called incorrectly. Translation loading for the acf domain was triggered too early. This is usually an indicator for some code in the plugin or theme running too early. Translations should be loaded at the init action or later.
To avoid this, you must make sure you don’t call any ACF functions before the
acf/init action. Our code samples above show how to wrap these calls appropriately.
acf_add_options_sub_page()
Description
Adds a new options sub page to the admin menu.
Options pages are used to store global settings. These settings are not tied to a specific post, but are instead stored in the
wp_options table.
Once registered, your page will appear in the admin menu. You can then assign fields to your page via the "Options Page" location rule when editing a field group.
This function is essentially a wrapper for acf_add_options_page() providing a default value for the parent_slug attribute of "acf-options".
Parameters
acf_add_options_sub_page( [$settings] );
$settings
(array) (Optional) Array of arguments for registering an options page. See list of available parameters
Examples
Default options sub page
This example shows how to create a default options sub page.
functions.php
if( function_exists('acf_add_options_sub_page') ) {
acf_add_options_sub_page();
}
Customized options sub page
This example shows how to create a customized options sub page and store the data in a variable for later use.
functions.php
add_action('acf/init', 'my_acf_op_init');
function my_acf_op_init() {
// Check function exists.
if( function_exists('acf_add_options_sub_page') ) {
// Add parent.
$parent = acf_add_options_page(array(
'page_title' => __('Theme General Settings'),
'menu_title' => __('Theme Settings'),
'redirect' => false,
));
// Add sub page.
$child = acf_add_options_sub_page(array(
'page_title' => __('Social Settings'),
'menu_title' => __('Social'),
'parent_slug' => $parent['menu_slug'],
));
}
}
Notes
Priority
This function must be used before the action
admin_menu (priority 99) as this is when admin pages are registered in WordPress core. We advise using the "acf/init" action.
acf_form()
Description
Displays a form to add or edit a post. There are many settings available to customize the form and these are set by adding to the
$options array as explained below.
You may also register a form using the acf_register_form() function.
Parameters
$settings
(String | Array) Array of settings or ‘id’ of a registered form.
id
(String) A unique identifier for the form. Defaults to ‘acf-form’.
'id' => 'acf-form',
post_id
(Integer | String) The post ID used to determine which fields to show, where data is loaded, and where data is saved. Defaults to current post ID. Can also be sent to ‘new_post’ to create a new post on submit.
'post_id' => false,
new_post
(Array) When the above attribute is set to "new_post", this setting is used to create the post. See wp_insert_post for available parameters.
'new_post' => false,
field_groups
(Array) An array of field group IDs/keys to override the fields displayed in this form.
'field_groups' => false,
fields
(Array) An array of field IDs/keys to override the fields displayed in this form.
'fields' => false,
post_title
(Boolean) Whether or not to show the post title text field. Defaults to false.
'post_title' => false,
post_content
(Boolean) Whether or not to show the post content editor field. Defaults to false.
'post_content' => false,
form
(Boolean) Whether or not to create a
form element. Useful when adding to an existing form. Defaults to true.
'form' => true,
form_attributes
(Array) An array or HTML attributes for the form element.
'form_attributes' => array(),
return
(String) The URL to be redirected to after the form is submitted. Defaults to the current URL with a GET parameter ‘?updated=true’.
A special placeholder ‘%post_url%’ will be converted to post’s permalink.
A special placeholder ‘%post_id%’ will be converted to post’s ID.
'return' => '',
html_before_fields
(String) Extra HTML to add before the fields.
'html_before_fields' => '',
html_after_fields
(String) Extra HTML to add after the fields.
'html_after_fields' => '',
submit_value
(String) The text displayed on the submit button.
'submit_value' => __("Update", 'acf'),
updated_message
(String) The message displayed above the form after being redirected. Can also be set to false for no message.
'updated_message' => __("Post updated", 'acf'),
label_placement
(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',
instruction_placement
(String) Determines where field instructions are placed in relation to fields. Defaults to ‘label’.
Choice of ‘label’ (below labels) or ‘field’ (below fields).
'instruction_placement' => 'label',
field_el
(String) Determines element used to wrap a field. Defaults to ‘div’.
Choices of ‘div’, ‘tr’, ‘td’, ‘ul’, ‘ol’, ‘dl’.
'field_el' => 'div',
uploader
(String) Whether to use the WP uploader or a basic input for image and file fields. Defaults to ‘wp’ .
Choices of ‘wp’ or ‘basic’.
'uploader' => 'wp',
honeypot
(Boolean) Whether to include a hidden input field to capture non-human form submission. Defaults to true.
'honeypot' => true,
html_updated_message
(String) The HTML used to render the updated message.
'html_updated_message' => '
%s
',
html_submit_button
(String) The HTML used to render the submit button.
'html_submit_button' => '',
html_submit_spinner
(String) The HTML used to render the submit button loading spinner.
'html_submit_spinner' => '',
kses
(Boolean) Whether or not to sanitize all
$_POST data with the
wp_kses_post() function. Defaults to true.
'kses' => true
Changelog
kses added in version 5.6.5.
uploader added in version 5.2.4.
honeypot added in version 5.3.4
html_updated_message,
html_submit_button, and
html_submit_spinner added in version 5.5.10
Examples
Editing current post
This example demonstrates how to display a basic form to edit the current post.
page-basic-form.php
Editing a specific post
This example demonstrates how to display a form which edits the meta fields of a specific post.
page-specific-form.php
Notes
Displaying within an AJAX modal
When displaying an ACF form within an AJAX modal (or any other dynamically appended method), please note that the page will require some extra PHP and JavaScript code.
PHP
The following function must be run within the
tags and before the "wp_footer" action. This will create a hidden WYSIWYG field and enqueue the required JS templates for the WP media popups.
// Enqueue uploadedr scripts.
acf_enqueue_uploader();
JS
The following JS must be run after the AJAX request has completed and new HTML (containing the ACF form) has been appended to the DOM. This will allow ACF to initialize the fields within the newly added HTML.
// Trigger the append action and provide the newly appended jQuery element.
acf.do_action('append', $('#popup-id'));
acf_form_head()
It is important to note that whilst the
acf_form() function will display a form, it will not process the form when submit. This task is handled by another function called
acf_form_head(). To allow the form to save data, you will need to place the
acf_form_head() function at the top of your page template before any HTML is rendered.
Security
Since version 5.6.5, ACF uses the wp_kses_post() function to sanitize content and strip out evil scripts. This sanitization can be disabled if needed by changing the form’s
kses setting to false.
acf_form_head()
Description
Used to process, validate and save the submitted form data created by the acf_form() function. It will also enqueue all ACF related scripts and styles for the form to display correctly.
This function must be placed before any HTML has been output, preferably above the
get_header() function of your theme file.
Parameters
acf_form_head();
Example
This example demonstrates a basic
acf_form() to edit the current post being viewed.
Actions & Filters
The following actions and filters are provided to customize the submission process.
acf/pre_submit_form
This filter is run after a form has been submit, and before any data has been saved.
Use this filter to modify the
$form array before
$_POST data is saved.
add_filter('acf/pre_submit_form', 'my_acf_pre_submit_form', 10, 1);
function my_acf_pre_submit_form( $form ) {
// Create post using $form['new_post'].
// Modify $form['redirect'].
return $form;
}
acf/pre_save_post
This filter is run after the acf/pre_submit_form filter, and before any data has been saved.
Use this filter to modify the
$post_id value used to save the
$_POST data.
add_filter('acf/pre_save_post', 'my_acf_pre_save_post', 10, 2);
function my_acf_pre_save_post( $post_id, $form ) {
// Create post using $form and update $post_id.
return $post_id;
}
acf/save_post
This action runs when ACF saves the
$_POST data.
For more information, please refer to the acf/save_post guide.
add_action('acf/save_post', 'my_acf_save_post', 20);
function my_acf_save_post( $post_id ) {
// Get new value.
$value = get_field('my_field', $post_id);
// Do something.
}
acf/submit_form
This action runs after the
$_POST data has been saved.
Use this action to perform custom logic before the return setting is used to redirect the browser.
add_action('acf/submit_form', 'my_acf_submit_form', 10, 2);
function my_acf_submit_form( $form, $post_id ) {
// Get new value.
$value = get_field('my_field', $post_id);
// Redirect.
wp_redirect( 'http://www.website.com/' . $value );
exit;
}
Changelog
acf/pre_submit_form added in version 5.5.10
acf/submit_form added in version 5.5.10
acf/pre_save_post added in version 4.1.6
acf_get_field_groups()
Description
Retrieves all ACF field groups filtered by
WP_Query args, returning them as an array.
This function should not be confused with get_fields(), which returns an array of field values for a specific post, get_field_objects(), which returns all fields and settings but doesn’t separate them by field group, or acf_get_fields(), which retrieves all the fields from a specific field group.
Parameters
acf_get_field_groups( $filter );
$filter (array) (Optional) An array of args to filter the post query by.
Examples
Basic usage
This example demonstrates how to return all field groups associated with a post ID as an array. It retrieves all the field groups, runs a filter on them, and then checks the Location Rules for each field group.
The post ID must be passed as an argument, or no field groups will be returned. You will have to replace
$post_id with the actual ID of the post.
$groups = acf_get_field_groups( array( 'post_id' => $post_id ) );
Advanced usage
This example demonstrates how to dynamically retrieve field groups based on the current page’s post type and template, and then use the retrieved field groups to generate a custom page layout based on the field groups assigned to a post.
Let’s say you have a custom post type called “portfolio” and you want to display a different layout for each portfolio item based on the field groups assigned to it. You can use
acf_get_field_groups() to retrieve the field groups and then loop through them to generate the custom layout.
// Get the current post ID
$post_id = get_the_ID();
// Retrieve all field groups associated with the current post
$field_groups = acf_get_field_groups(array('post_id' => $post_id));
// Loop through each field group
foreach ($field_groups as $field_group) {
// Get the field group ID
$field_group_id = $field_group['ID'];
// Get the fields within the field group
$fields = acf_get_fields($field_group_id);
// Check if the field group has a specific layout
if ($field_group['layout'] == 'gallery') {
// Loop through each field and display the gallery layout
foreach ($fields as $field) {
if ($field['type'] == 'gallery') {
// Display the gallery field
the_field($field['name']);
}
}
} elseif ($field_group['layout'] == 'video') {
// Loop through each field and display the video layout
foreach ($fields as $field) {
if ($field['type'] == 'video') {
// Display the video field
the_field($field['name']);
}
}
}
}
In this example, we first retrieve the current post ID using
get_the_ID(). Then, we use
acf_get_field_groups() to retrieve all field groups associated with the current post. We loop through each field group and retrieve the fields within it using
acf_get_fields(). Finally, we check the layout of each field group and display the corresponding layout based on the field types within the group.
Notes
Exercise caution when using this function, as it is the same function ACF uses to retrieve field groups and fields.
The function caches results so the fields do not need to be retrieved from the database every time, but since the values are cached, changes to them are not updated. You will need to manually clear the cached versions if you want to change the settings of a field group or field after you’ve called this function.
acf_get_fields()
Description
Retrieves all the fields from a specific field group, returning them as an array of field objects. This function should not be confused with get_fields(), which returns an array of field values for a specific post rather than a field group.
Parameters
acf_get_fields( $parent );
$parent (mixed) (Required) The field group’s ID or key.
Examples
Basic usage
This example demonstrates how to return an array of fields for a given parent. Note that you will have to replace the field group key shown below with your own.
acf_get_fields('group_6525b4469c71d');
Advanced usage
The following example demonstrates how to retrieve the values in the
foreach for every field contained in the field group and then output them for viewing.
$specifications_group_id = 'group_6525b4469c71d'; // Replace with your group ID
$specifications_fields = array();
$fields = acf_get_fields( $specifications_group_id );
foreach ( $fields as $field ) {
$field_value = get_field( $field['name'] );
if ( ! empty( $field_value ) ) {
$specifications_fields[ $field['name'] ] = $field_value;
}
}
acf_inline_text_editing_attrs()
Description
Helper function that returns the HTML attributes required for inline text editing as a string, escaped and ready for output.
It is used within ACF Block render templates to make an HTML element directly editable, primarily for Text and Text Area fields, allowing authors to type content directly into the block preview area.
Changelog
Added in version 6.7
Parameters
acf_inline_text_editing_attrs( $field_name, $args = array() );
$field_name
(string) The name of the ACF field that will be updated when the user types into the HTML element..
$args
(array) (Optional) An array of arguments for customizing the inline text editing behavior. The available keys are:
toolbar_icon
(string) (Optional) An HTML tag (e.g., SVG) to be used as the toolbar icon.
toolbar_title
(string) (Optional) A string to be used as the toolbar title.
placeholder
(string) (Optional) A string to be used as the placeholder text when the field is empty.
Return
(string) A string containing the required HTML attributes ready to be placed inside an HTML tag. The returned output is already escaped.
Examples
Making a text field used in an
h3 element text editable:
>
To customize the experience even further, you can control the icons used in the toolbar, or the placeholder text shown when a field is empty. For example:
'your svg html here',
'toolbar_title' => 'My custom toolbar title',
'placeholder' => 'Type to edit...'
)
); ?>
acf_inline_toolbar_editing_attrs()
Description
Helper function that returns the HTML attributes required for toolbar inline editing as a string, escaped and ready for output.
It is used within ACF Block render templates to make an HTML element show a popup toolbar when clicked, allowing authors to edit multiple fields at once.
Changelog
Added in version 6.7
Parameters
acf_inline_toolbar_editing_attrs( $fields, $args = array() );
$fields
(array) Required A list of the fields, each of which will be displayed in the popup toolbar.
Each field can be passed as:
A string (e.g. ‘my_field_name’)
An associative array with specific keys:
field_name: (string) The name of the field to display in the toolbar.
field_icon: (string) (Optional) An HTML tag, can be an SVG, to be used as the toolbar icon. If not passed, the icon of the first field will be used.
field_label: (string) (Optional) A string to use as the label for the button in the toolbar.
popover_min_width: (string) (Optional) Minimum width of the popover, defaults to ‘300px’
use_expanded_editor: (bool) (Optional) If
true opens field editing in the Expanded Editor Panel,
false uses the popover. Defaults to
false/.
$args
(array) (Optional) An array of arguments for customizing the inline text editing behavior. The available keys are:
toolbar_icon
(string) (Optional) An HTML tag (e.g., SVG) to be used as the toolbar icon.
toolbar_title
(string) (Optional) A string to be used as the toolbar title.
uid
(string) (Optional) A unique identifier that isn’t used by any other inline fields in this block. Pass if you have 2 elements that conflict.
render
(bool) (Optional) True if it should return the output, false if it should return an empty string.
Return
(string) A string containing the required HTML attributes ready to be placed inside an HTML tag. The returned output is already escaped.
Examples
Customizing the icon in the toolbar to edit an Image field type, with a custom field label (used as a tooltip)
‘my_image_field’,
‘field_icon’ => ‘your svg html here’,
‘field_label’ => ‘My custom field label’
)
) ); ?> />
You can also customize the title and icon of the whole toolbar by passing a second array. For example:
‘my_image_field’,
‘field_icon’ => ‘your svg html here’,
‘field_label’ => ‘My custom field label’
),
),
array(
‘toolbar_icon’ => ‘your svg html here’,
‘toolbar_title’ => ‘My custom toolbar title
)
); ?> />
You can ensure specific fields open in the expanded editing panel:
‘my_image_field’,
‘use_expanded_editor’ => true,
),
) ); ?> />
You can define the minimum width of the popover:
‘my_image_field’,
‘popover_min_width’ => ‘500px’,
),
) ); ?> />
acf_register_block_type()
Since ACF 6.0, we recommend you register blocks with the new block.json syntax syntax rather than the deprecated
acf_register_block_type() detailed here.
Functionality detailed in this documentation may not work with modern versions of WordPress.
Description
Registers a custom block type in the Gutenberg editor.
Blocks are the fundamental element of the Gutenberg editor. WordPress provides many default block types such as paragraph, heading and image. The acf_register_block_type() function can be used to add new block types via PHP.
Once registered, your block will appear in the “Block” location rules when editing a field group. This allows you to map fields to your block and define the content.
To render the block, create a PHP template (or callback function) to output the block HTML using PHP functions like get_field() and the_field().
Note: Block type registration should be done within the acf/init action. This is not required, but is a safe way to ensure that ACF is fully initialized.
Block types can support any number of built-in core features such as name, icon, description, category and more. See the $settings argument for a complete list of supported features.
Additionally, all properties from the WordPress Block Supports API may be used.
Parameters
acf_register_block_type( $settings );
$settings
(array) (Required) Array of arguments for registering a block type. Any argument from the JavaScript registerBlockType() function may also be used.
name
(String) A unique name that identifies the block (without namespace). For example ‘testimonial’.
Note: A block name can only contain lowercase alphanumeric characters and dashes, and must begin with a letter.
'name' => 'testimonial',
title
(String) The display title for your block. For example ‘Testimonial’.
'title' => __('Testimonial'),
description
(String) (Optional) This is a short description for your block.
'description' => __('My testimonial block.'),
category
(String) Blocks are grouped into categories to help users browse and discover them. The core provided categories are [ common | formatting | layout | widgets | embed ]. Plugins and Themes can also register custom block categories.
'category' => 'embed',
icon
(String|Array) (Optional) An icon property can be specified to make it easier to identify a block. These can be any of WordPress’ Dashicons, or a custom svg element.
// Specifying a dashicon for the block
'icon' => 'book-alt',
// Specifying a custom HTML svg for the block
'icon' => '',
// Specifying colors
'icon' => array(
// Specifying a background color to appear with the icon e.g.: in the inserter.
'background' => '#7e70af',
// Specifying a color for the icon (optional: if not set, a readable color will be automatically defined)
'foreground' => '#fff',
// Specifying a dashicon for the block
'src' => 'book-alt',
),
keywords
(Array) (Optional) An array of search terms to help user discover the block while searching.
'keywords' => array('quote', 'mention', 'cite'),
post_types
(Array) (Optional) An array of post types to restrict this block type to.
'post_types' => array('post', 'page'),
mode
(String) (Optional) The display mode for your block. Available settings are “auto”, “preview” and “edit”. Defaults to “preview”.
auto: Preview is shown by default but changes to edit form when block is selected.
preview: Preview is always shown. Edit form appears in sidebar when block is selected.
edit: Edit form is always shown.
Note. When in “preview” or “edit” modes, an icon will appear in the block toolbar to toggle between modes.
'mode' => 'auto',
align
(String) (Optional) The default block alignment. Available settings are “left”, “center”, “right”, “wide” and “full”. Defaults to an empty string.
'align' => 'full',
align_text
(String) (Optional) The default block text alignment (see supports setting for more info). Available settings are “left”, “center” and “right”. Defaults to the current language’s text alignment.
'align_text' => 'center',
align_content
(String) (Optional) The default block content alignment (see supports setting for more info). Available settings are “top”, “center” and “bottom”. When utilising the “Matrix” control type, additional settings are available to specify all 9 positions from “top left” to “bottom right”. Defaults to “top”.
'align_content' => 'center',
render_template
(String) The path to a template file used to render the block HTML. This can either be a relative path to a file within the active theme or a full path to any file.
// Specifying a relative path within the active theme
'render_template' => 'template-parts/blocks/testimonial/testimonial.php',
// Specifying an absolute path
'render_template' => plugin_dir_path( __FILE__ ) . 'template-parts/blocks/testimonial/testimonial.php',
render_callback
(Callable) (Optional) Instead of providing a render_template, a callback function name may be specified to output the block’s HTML.
// Specifying a function
'render_callback' => 'my_acf_block_render_callback',
// Specifying a class method
'render_callback' => array($this, 'block_render_callback'),
enqueue_style
(String) (Optional) The url to a .css file to be enqueued whenever your block is displayed (front-end and back-end). Since WordPress 5.8, scripts and styles may not load correctly in block patterns, styles, and iframed previews. To resolve this, you’ll need to use the new
block.json format with the
script and
style keys.
'enqueue_style' => get_template_directory_uri() . '/template-parts/blocks/testimonial/testimonial.css',
enqueue_script
(String) (Optional) The url to a .js file to be enqueued whenever your block is displayed (front-end and back-end). Since WordPress 5.8, scripts and styles may not load correctly in block patterns, styles, and iframed previews. To resolve this, you’ll need to use the new
block.json format with the
script and
style keys.
'enqueue_script' => get_template_directory_uri() . '/template-parts/blocks/testimonial/testimonial.js',
enqueue_assets
(Callable) (Optional) A callback function that runs whenever your block is displayed (front-end and back-end) and enqueues scripts and/or styles.
// Specifying a function name
'enqueue_assets' => 'my_acf_block_enqueue_assets',
// Specifying a class method
'enqueue_assets' => array($this, 'block_enqueue_assets'),
// Specifying an anonymous function
'enqueue_assets' => function(){
wp_enqueue_style( 'block-testimonial', get_template_directory_uri() . '/template-parts/blocks/testimonial/testimonial.css' );
wp_enqueue_script( 'block-testimonial', get_template_directory_uri() . '/template-parts/blocks/testimonial/testimonial.js', array('jquery'), '', true );
},
supports
(Array) (Optional) An array of features to support. All properties from the JavaScript block supports documentation may be used. The following options are supported:
'supports' => array( /* ... */ ),
align
This property enables a toolbar button to control the block’s alignment. Defaults to
true. Set to
false to hide the alignment toolbar. Set to an array of specific alignment names to customize the toolbar.
// disable alignment toolbar
'align' => false,
// customize alignment toolbar
'align' => array( 'left', 'right', 'full' ),
align_text
This property enables a toolbar button to control the block’s text alignment. Defaults to
false. Set to
true to show the alignment toolbar button.
The current selected alignment value will be accessible within the render callback/template via
$block['align_text'].
// Show text alignment toolbar.
'align_text' => true,
align_content
This property enables a toolbar button to control the block’s inner content alignment. Defaults to
false. Set to
true to show the alignment toolbar button, or set to
'matrix' to enable the full alignment matrix in the toolbar
The current selected alignment value will be accessible within the render callback/template via
$block['align_content'].
// Show content alignment toolbar.
'align_content' => true,
// Show full alignment matrix in toolbar.
'align_content' => 'matrix',
full_height
This property enables the full height button on the toolbar of a block and adds the
$block[‘full_height’] property inside the render template/callback.
$block[‘full_height’] will only be true if the full height button is enabled on the block in the editor. Defaults to
false.
// enable full_height
'full_height' => true,
mode
This property allows the user to toggle between edit and preview modes via a button. Defaults to
true.
// disable preview/edit toggle
'mode' => false,
multiple
This property allows the block to be added multiple times. Defaults to
true.
'multiple' => false,
example
(Array) (Optional) An array of structured data used to construct a preview shown within the block-inserter.
All values entered into the ‘data’ attribute array will become available within the block render template/callback via
$block['data'] or
get_field().
'example' => array(
'attributes' => array(
'mode' => 'preview',
'data' => array(
'testimonial' => "Your testimonial text here",
'author' => "John Smith"
)
)
)
acf_block_version
(Integer) (Optional) This property can be used to change between the various ACF block versions (1, 2, or 3). Defaults to
2.
// Switch to ACF Blocks v3.
'acf_block_version' => 3,
Return
(array) The validated and registered block settings.
Changelog
Added in version 5.8.0
Added “align_text” settings in version 5.9.0.
Added “align_content” settings in version 5.9.0.
Examples
Registering a block with template
This example shows how to register a block using the render_template setting.
functions.php
add_action('acf/init', 'my_acf_blocks_init');
function my_acf_blocks_init() {
// Check function exists.
if( function_exists('acf_register_block_type') ) {
// Register a testimonial block.
acf_register_block_type(array(
'name' => 'testimonial',
'title' => __('Testimonial'),
'description' => __('A custom testimonial block.'),
'render_template' => 'template-parts/blocks/testimonial/testimonial.php',
'category' => 'formatting',
));
}
}
template-parts/blocks/testimonial/testimonial.php
Registering a block with callback
This example shows how to register a block using the render_callback setting.
functions.php
'testimonial',
'title' => __('Testimonial'),
'description' => __('A custom testimonial block.'),
'render_callback' => 'my_acf_block_render_callback',
'category' => 'formatting',
));
}
}
/**
* Testimonial Block Callback Function.
*
* @param array $block The block settings and attributes.
* @param string $content The block inner HTML (empty).
* @param bool $is_preview True during AJAX preview.
* @param (int|string) $post_id The post ID this block is saved to.
*/
function my_acf_block_render_callback( $block, $content = '', $is_preview = false, $post_id = 0, $wp_block = false, $context = false ) {
// Create id attribute allowing for custom "anchor" value.
$id = 'testimonial-' . $block['id'];
if( !empty($block['anchor']) ) {
$id = $block['anchor'];
}
// Create class attribute allowing for custom "className" and "align" values.
$className = 'testimonial';
if( !empty($block['className']) ) {
$className .= ' ' . $block['className'];
}
if( !empty($block['align']) ) {
$className .= ' align' . $block['align'];
}
// Load values and handle defaults.
$text = get_field('testimonial') ?: 'Your testimonial here...';
$author = get_field('author') ?: 'Author name';
$role = get_field('role') ?: 'Author role';
$image = get_field('image') ?: 295;
$background_color = get_field('background_color');
$text_color = get_field('text_color');
?>
testimonial.css
.testimonial {
background: #00e4ba;
color: #fff;
}
Note: If creating individual stylesheets is not your cup of tea, please take a look at the enqueue_block_assets and enqueue_block_editor_assets actions that WordPress provide to enqueue your styles.
Adding block scripts ⚡️
Since WordPress 5.8, scripts and styles may not load correctly in block patterns, styles, and iframed previews. To resolve this, you’ll need to use the new
block.json format with the
script and
style keys.
Similar to styles, we recommend making use of either the enqueue_script or enqueue_assets settings to correctly enqueue JavaScript for your block.
For JavaScript to run as intended in both the editor and front-end, it is important to understand the lifecycle of a block when editing a post.
Depending on if the block preview is shown, and whether or not changes have been made, your block may be rendered multiple times during a single page load. In this case, the term “rendered” means that the block’s HTML has been updated/replaced via an AJAX call to your PHP template or callback function.
Each time a block is rendered, the previous HTML is discarded, and the new HTML is displayed. As a result, any JavaScript modifications to the previous DOM elements will also be lost.
To solve this problem, simply hook into our JS action “render_block_preview/type={$type}” and apply your JavaScript functionality as if the block was freshly painted.
This example demonstrates how to enqueue a script whilst providing compatibility with both the front-end and back-end states of a block.
functions.php
acf_register_block_type(array(
'name' => 'testimonial',
'title' => __('Testimonial'),
'description' => __('A custom testimonial block.'),
'render_template' => get_template_directory() . '/template-parts/blocks/testimonial/testimonial.php',
'enqueue_script' => get_template_directory_uri() . '/template-parts/blocks/testimonial/testimonial.js',
));
testimonial.php
...
testimonial.js
(function($){
/**
* initializeBlock
*
* Adds custom JavaScript to the block HTML.
*
* @date 15/4/19
* @since 1.0.0
*
* @param object $block The block jQuery element.
* @param object attributes The block attributes (only available when editing).
* @return void
*/
var initializeBlock = function( $block ) {
$block.find('img').doSomething();
}
// Initialize each block on page load (front end).
$(document).ready(function(){
$('.testimonial').each(function(){
initializeBlock( $(this) );
});
});
// Initialize dynamic block preview (editor).
if( window.acf ) {
window.acf.addAction( 'render_block_preview/type=testimonial', initializeBlock );
}
})(jQuery);
Adding block previews 🌄
Block previews offer an elegant solution for identifying and differentiating the various block types shown in the inserter panel.
Screenshot of the inserter panel showing a block preview.
To add support for block previews, use the “example” setting to define an array of attributes used by WordPress to construct the preview as shown in the following example.
functions.php
acf_register_block_type(array(
'name' => 'testimonial',
'title' => __('Testimonial'),
'description' => __('A custom testimonial block.'),
'example' => array(
'attributes' => array(
'mode' => 'preview',
'data' => array(
'testimonial' => "Blocks are...",
'author' => "Jane Smith",
'role' => "Person",
'is_preview' => true
)
)
)
));
All values defined in the “data” attribute array will become available within the block render template/callback via
$block['data'] or
get_field().
In the example above, three values are defined matching the names of three existing custom fields (‘testimonial’, ‘author’ & ‘role’). An additional non-custom-field value (‘is_preview’) is defined which could be used within the renderer to display alternative markup.
👨💻 As previews are intended to communicate a visual design, we advise using the “preview” mode, however, it is also possible to set this to “edit” which will display the custom fields connected to that block.
Adding inner blocks 👩👧👦
The term “Inner Blocks” refers to the ability to enable nested content – blocks within blocks. This short video demonstrates how inner blocks can be used to create a date restricted block with only basic PHP.
https://www.advancedcustomfields.com/wp-content/uploads/2022/02/ACF-5.9-Inner-Blocks.mp4
To add support for inner blocks, use the
Component within your render template/callback to define an editable area. This special element will be displayed as a native “block inserter area” when editing content, and the saved “inner blocks content” when viewing content.
Please note that only a single
Component may be used per block.
In order for the
Component to function within the React based block editor, your block HTML must first be parsed as JSX. This can easily be done by adding support for the
jsx property.
The following example demonstrates how to create the previous mentioned “Restricted” content block.
functions.php
add_action('acf/init', 'my_acf_init_blocks');
function my_acf_init_blocks() {
// Check function exists.
if( function_exists('acf_register_block_type') ) {
// Register a restricted block.
acf_register_block_type(array(
'name' => 'restricted',
'title' => 'Restricted',
'description' => 'A restricted content block.',
'category' => 'formatting',
'mode' => 'preview',
'supports' => array(
'align' => true,
'mode' => false,
'jsx' => true
),
'render_template' => 'template-parts/blocks/restricted/restricted.php',
));
}
}
template-parts/blocks/restricted/restricted.php
$now ) {
echo sprintf( '
Content restricted until %s. Please check back later.
The
Component may also be customized with the following attributes as documented in the InnerBlocks Component Guide.
allowedBlocks
(Array) An array of block names that restricted the types of content that can be inserted.
$allowed_blocks = array( 'core/image', 'core/paragraph' );
echo '';
template
(Array) A structured array of block content as documented in the CPT block template guide. An additional attribute named templateLock may be used in conjunction to lock the template content.
$template = array(
array( 'core/paragraph', array(
'placeholder' => 'Add a root-level paragraph',
) ),
array( 'core/columns', array(), array(
array( 'core/column', array(), array(
array( 'core/image', array() ),
) ),
array( 'core/column', array(), array(
array( 'core/paragraph', array(
'placeholder' => 'Add a inner paragraph'
) ),
) ),
) )
);
echo '';
templateLock
(String) Locks the template content. Available settings are “all” or “insert”. See the InnerBlocks Component for further information.
acf_register_form()
Description
Registers a form for use with the acf_form() function. There are many settings available to customize a form which are set by adding to the
$settings array (see below).
Parameters
$settings
(String | Array) Array of settings or ‘id’ of a registered form.
id
(String) A unique identifier for the form. Defaults to ‘acf-form’.
'id' => 'acf-form',
post_id
(Integer | String) The post ID used to determine which fields to show, where data is loaded, and where data is saved. Defaults to current post ID. Can also be sent to ‘new_post’ to create a new post on submit.
'post_id' => false,
new_post
(Array) When the above attribute is set to "new_post", this setting is used to create the post. See wp_insert_post for available parameters.
'new_post' => false,
field_groups
(Array) An array of field group IDs/keys to override the fields displayed in this form.
'field_groups' => false,
fields
(Array) An array of field IDs/keys to override the fields displayed in this form.
'fields' => false,
post_title
(Boolean) Whether or not to show the post title text field. Defaults to false.
'post_title' => false,
post_content
(Boolean) Whether or not to show the post content editor field. Defaults to false.
'post_content' => false,
form
(Boolean) Whether or not to create a
form element. Useful when adding to an existing form. Defaults to true.
'form' => true,
form_attributes
(Array) An array or HTML attributes for the form element.
'form_attributes' => array(),
return
(String) The URL to be redirected to after the form is submitted. Defaults to the current URL with a GET parameter ‘?updated=true’.
A special placeholder ‘%post_url%’ will be converted to post’s permalink.
A special placeholder ‘%post_id%’ will be converted to post’s ID.
'return' => '',
html_before_fields
(String) Extra HTML to add before the fields.
'html_before_fields' => '',
html_after_fields
(String) Extra HTML to add after the fields.
'html_after_fields' => '',
submit_value
(String) The text displayed on the submit button.
'submit_value' => __("Update", 'acf'),
updated_message
(String) The message displayed above the form after being redirected. Can also be set to false for no message.
'updated_message' => __("Post updated", 'acf'),
label_placement
(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',
instruction_placement
(String) Determines where field instructions are placed in relation to fields. Defaults to ‘label’.
Choice of ‘label’ (below labels) or ‘field’ (below fields).
'instruction_placement' => 'label',
field_el
(String) Determines element used to wrap a field. Defaults to ‘div’.
Choices of ‘div’, ‘tr’, ‘td’, ‘ul’, ‘ol’, ‘dl’.
'field_el' => 'div',
uploader
(String) Whether to use the WP uploader or a basic input for image and file fields. Defaults to ‘wp’ .
Choices of ‘wp’ or ‘basic’.
'uploader' => 'wp',
honeypot
(Boolean) Whether to include a hidden input field to capture non-human form submission. Defaults to true.
'honeypot' => true,
html_updated_message
(String) The HTML used to render the updated message.
'html_updated_message' => '
%s
',
html_submit_button
(String) The HTML used to render the submit button.
'html_submit_button' => '',
html_submit_spinner
(String) The HTML used to render the submit button loading spinner.
'html_submit_spinner' => '',
kses
(Boolean) Whether or not to sanitize all
$_POST data with the
wp_kses_post() function. Defaults to true.
'kses' => true
Changelog
kses added in version 5.6.5.
uploader added in version 5.2.4.
honeypot added in version 5.3.4
html_updated_message,
html_submit_button, and
html_submit_spinner added in version 5.5.10
Examples
Basic usage
This example demonstrates how to register a form in the
functions.php file and later display that form within a page template.
functions.php
add_action('acf/init', 'my_acf_form_init');
function my_acf_form_init() {
// Check function exists.
if( function_exists('acf_register_form') ) {
// Register form.
acf_register_form(array(
'id' => 'new-event',
'post_id' => 'new_post',
'new_post' => array(
'post_type' => 'event',
'post_status' => 'publish'
),
'post_title' => true,
'post_content'=> true,
));
}
}
page-new-event.php
acf_set_options_page_capability()
Description
This function has been deprecated. Please use the acf/options_page/settings filter instead.
Modifies the default Options Page capability setting.
The term ‘capability’ refers to the user roles and permissions that grant access to the Options Page. You can learn more about capability settings here.
Requirements
Options Page Add-on version 1.1.0 or later.
Parameters
acf_set_options_page_capability( $capability );
$capability (string) (Required) The capability for the default Options Page. Defaults to ‘edit_posts’.
Example
This example demonstrates how to change the default Options Page capability to ‘manage_options’.
functions.php
if( function_exists('acf_set_options_page_capability') ) {
acf_set_options_page_capability('manage_options');
}
acf_set_options_page_menu()
Description
This function has been deprecated. Please use the acf/options_page/settings filter instead.
Modifies the default Options Page menu name, displayed in the admin menu.
Requirements
Options Page Add-on version 1.2.0 or later
Parameters
acf_set_options_page_menu( $menu_name );
$menu_name (string) (Required) The menu name for the default Options Page. Defaults to ‘Options’.
Example
This example demonstrates how to change the default Options Page menu name to ‘Extra’.
if( function_exists('acf_set_options_page_menu') ) {
acf_set_options_page_menu( __('Extra') );
}
acf_set_options_page_title()
Description
This function has been deprecated. Please use the acf/options_page/settings filter instead.
Modifies the default Options Page title, displayed when viewing the admin page.
Requirements
Options Page Add-on version 1.1.0 or later
Parameters
acf_set_options_page_title( $title );
$title (string) (Required) The title for the default Options Page. Defaults to ‘Options’.
Example
This example demonstrates how to change the default Options Page title to ‘Theme Options’.
if( function_exists('acf_set_options_page_title') ) {
acf_set_options_page_title( __('Theme Options') );
}
add_row()
Adds a new row of data to an existing Repeater or Flexible Content field value.
Parameters
add_row($selector, $value, [$post_id])
$selector (string) (Required) The field name or field key.
$value (array) (Required) The new row data.
$post_id (mixed) (Optional) The post ID where the value is saved. Defaults to the current post.
Return
(int|false) The new total row count on successful update, false on failure.
Change Log
Added in version 5.3.2
Examples
Add a new row using field names
This example shows how to add a new row of data to an existing repeater field called ‘images’. This repeater field contains 3 sub fields (‘image’, ‘alt’, ‘link’).
$row = array(
'image' => 123,
'alt' => 'Another great sunset',
'link' => 'http://website.com'
);
add_row('images', $row);
Add a new row using field keys
This example demonstrates how to add a new row of data to an existing repeater field using keys instead of names. The repeater field is the same above.
Similar to the
update_field() function, using a field’s key rather than its name allows ACF to correctly find the field if no existing value has been saved.
$row = array(
'field_560389746a525' => 123,
'field_560389746a524' => 'Another great sunset',
'field_560389746a528' => 'http://website.com'
);
add_row('field_560389746a51f', $row);
add_sub_row()
Adds a new row of data to a Repeater or Flexible Content sub field value.
This function can be used inside or outside of a
have_rows() loop. When used inside, the current row will be used to update the sub field value. When used outside, the rows and parents must be specified to target the correct value place.
Please note this function is used to modify a sub field value. To modify a parent field value, please use the add_row() function.
Parameters
add_sub_row($selector, $value, [$post_id]);
$selector (string|array) (Required) The sub field name or key, or an array of ancestors and row numbers.
$value (array) (Required) The new row data.
$post_id (mixed) (Optional) The post ID where the value is saved. Defaults to the current post.
Return
(bool) True on successful update, false on failure.
Change Log
Added in version 5.4.7
Add a new sub row inside of a have_rows() loop
This example shows how to add a new row of data to an existing nested repeater field called ‘images’. This nested repeater field contains 3 sub fields (‘image’, ‘alt’, ‘link’).
// Loop over all staff members.
if( have_rows('staff_members') ) {
while( have_rows('staff_members') ) {
the_row();
// Get this staff member's name.
$name = get_sub_field('name');
// Append new row to this staff member's images.
$row = array(
'image' => 123,
'alt' => "Another photo of $name",
'link' => 'http://website.com'
);
add_sub_row('images', $row);
}
}
Add a new sub row outside of a have_rows() loop
This example shows how to add a new row of data outside of a
have_rows() loop. Here, the
$selector parameter is provided an array containing a mixture of field names and row numbers. This array should read from left to right, the parents to children relationship separated by the row number.
Please see notes regarding index offset.
// Update only the first staff member's images.
$row = array(
'image' => 123,
'alt' => "Another photo of the first staff member",
'link' => 'http://website.com'
);
add_sub_row( array('staff_members', 1, 'images'), $row );
Notes
Index offset
When targeting a sub field using a specific row number, please note that row numbers begin from 1 and not 0. This means that the first row has an index of 1, the second row has an index of 2, and so on.
To begin indexes from 0, please use the row_index_offset setting like so.
functions.php
add_filter('acf/settings/row_index_offset', '__return_zero');
Adding custom javascript to fields
✋ We’ve launched a new JavaScript API full of powerful functions, actions and filters! If you are using ACF 5.7 or above, please checkout our JavaScript API.
This article will cover how to add custom JS to interact with and modify ACF fields and settings. Similar to the many WordPress actions and filters available in PHP, ACF adopts a similar model for it’s Javascript.
Getting Started
There are two methods to add custom javascript to the WordPress dashboard; include a script file or append an inline script. It is recommended that you include a JS file if you intend to write lots of functionality.
Include
To include a JS file within the dashboard, you can make use of the wp_enqueue_script function like so.
functions.php
function my_admin_enqueue_scripts() {
wp_enqueue_script( 'my-admin-js', get_template_directory_uri() . '/js/example.js', array(), '1.0.0', true );
}
add_action('acf/input/admin_enqueue_scripts', 'my_admin_enqueue_scripts');
Inline
To append inline JS within the dashboard, you can make use of the
acf/input/admin_footer action. This action is run in the footer of any admin page where ACF fields may exist.
functions.php
function my_acf_input_admin_footer() {
?>
__( 'Admin Only?', 'my-textdomain' ),
'instructions' => '',
'name' => 'admin_only',
'type' => 'true_false',
'ui' => 1,
), true ); // If adding a setting globally, you MUST pass true as the third parameter!
}
add_action( 'acf/render_field_settings', 'my_admin_only_render_field_settings' );
2. Using the Setting
With the new “Admin Only?” setting added, we can hook into any part of ACF and use the setting. The following code will hook into the
acf/prepare_field filter which is run just before a field is rendered into a form. This will allow us to check if the current user is an administrator, and if not, prevent the field from being displayed:
function my_admin_only_prepare_field( $field ) {
// Bail early if no 'admin_only' setting or if set to false.
if ( empty( $field['admin_only'] ) ) {
return $field;
}
// Prevent field from displaying if current user is not an admin.
if ( ! current_user_can( 'manage_options' ) ) {
return false;
}
// Return the original field otherwise.
return $field;
}
add_filter( 'acf/prepare_field', 'my_admin_only_prepare_field' );
3. Testing the Setting
With the above code added to the
functions.php file and a field using the “Admin Only?” setting, we can now login with either an administrator or editor account and note the field’s existence!
Adding Settings for a Specific Field Type
Field settings can be added or restricted to individual field types (text, image, etc.). In ACF 6.0 and above, these settings can also be shown in specific tabs within a field type (General, Validation, Presentation, or Conditional Logic).
The following action hooks can be used for adding field settings to these tabs:
acf/render_field_settings/type={type} (legacy action for the “General” tab – can be used in ACF 5 to add field type-specific settings)
acf/render_field_general_settings/type={type} (for adding settings to the “General” tab)
acf/render_field_validation_settings/type={type} (for adding settings to the “Validation” tab)
acf/render_field_presentation_settings/type={type} (for adding settings to the “Presentation” tab)
acf/render_field_conditional_logic_settings/type={type} (for adding settings to the “Conditional Logic” tab)
These filters are also applied on the
acf_field base class, so if you have a custom field type that extends
acf_field, you can instead just add one or more of the following methods to your custom class:
render_field_settings()
render_field_general_settings()
render_field_validation_settings()
render_field_presentation_settings()
render_field_conditional_logic_settings()
The following example will add a new “Exclude Words” setting to the “Validation” tab of the textarea field type. This adds a text input which we’ll later use to store a list of words that shouldn’t be allowed in textareas.
1. Adding the Setting
Since this example is adding a setting to the “Validation” tab, we’ll be using the
acf/render_field_validation_settings/type={$type} action hook to render the setting.
Please note that the third parameter for the
acf_render_field_setting() function is excluded – making it specific to the field, rather than a global setting as shown above.
function my_textarea_render_field_settings( $field ) {
acf_render_field_setting( $field, array(
'label' => __( 'Exclude Words', 'my-textdomain' ),
'instructions' => __( 'Enter words separated by a comma', 'my-textdomain' ),
'name' => 'exclude_words',
'type' => 'text',
) );
}
add_action( 'acf/render_field_validation_settings/type=textarea', 'my_textarea_render_field_settings' );
2. Using the Setting
With the new “Exclude Words” setting added and a new textarea field added (using the setting), we can hook into any part of ACF and use the setting. The following code will hook into the
acf/validate_value filter which is run during validation. This will allow us to check if the current value contains any words from the exclude list and notify the user via a validation error message.
function my_textarea_validate_value( $valid, $value, $field, $input ) {
// Bail early if the field is already invalid.
if ( ! $valid ) {
return $valid;
}
// Bail early if the "Exclude Words" setting is not set.
if ( empty( $field['exclude_words'] ) ) {
return $valid;
}
// Explode the words into an array we can loop over.
$words = explode( ',', $field['exclude_words'] );
$words = array_map( 'trim', $words ); // Trim white spaces.
$words = array_values( $words ); // Remove empty values.
foreach( $words as $word ) {
// Check if the word exists.
if( stripos( $value, $word ) !== false ) {
$valid = sprintf( __( 'Value must not include "%s"', 'my-textdomain' ), $word );
break;
}
}
return $valid;
}
add_filter( 'acf/validate_value/type=textarea', 'my_textarea_validate_value', 10, 4 );
3. Testing the Setting
With the above code added to the
functions.php file and a field using the ‘exclude_words’ setting, we can now edit a post and attempt to save a value.
Adding a Custom Field Setting Tab
With our new tab format introduced in ACF 6.0, plugins which add settings to fields can add do so with the new
acf/field_group/additional_field_settings_tabs filter introduced in ACF 6.1.
For example, to add a new Tab called ‘My Settings’ to every field, you’d use:
add_filter( 'acf/field_group/additional_field_settings_tabs', function ( $tabs ) {
$tabs['my-settings'] = 'My Settings';
return $tabs;
} );
To add a field to this new tab you would use the
acf/field_group/render_field_settings_tab/$tab-key filter::
add_action( 'acf/field_group/render_field_settings_tab/my-settings', function ( $field ) {
acf_render_field_setting(
$field,
array(
'label' => 'Admin Only?',
'instructions' => '',
'name' => 'admin_only',
'type' => 'true_false',
'ui' => 1,
),
true
);
} );
Adding a Custom Tab to the Field Group Settings
It is also possible to add a custom settings tab to the ‘Settings’ meta box at the bottom of the Field Group editor screen using the
acf/field_group/additional_group_settings_tabs filter in the same way as above.
Upgrading Existing Field Settings to ACF 6
Custom field settings that were added using the
acf/render_field_settings or
acf/render_field_settings/type={type} action hooks will continue to work in ACF 6, with the settings appearing on the “General” tab for any fields those settings were added to.
However, there are some changes in ACF 6 that may require some additional code.
Moving an Existing Field Setting into a Different Tab
If you want to move your custom field setting to a different tab and also support users who may still be on ACF 5, you’ll likely need to add some code to make sure that the setting is registered differently on ACF 5 and 6 to prevent the setting from showing up twice.
One way to do that would be to update your existing field setting code to return early if on ACF 6.0 or above.
function render_field_settings( $field ) {
// We’re on ACF 6.0 or above, so we don’t need to register the setting here.
if ( version_compare( ACF_MAJOR_VERSION, '6.0', '>=' ) ) {
return;
}
// Rest of field settings code.
}
You could then add a separate function that hooks on one of the tab-specific action hooks as mentioned above.
Changes to acf_render_field_setting() in ACF 6
In ACF 5, field settings were rendered as table rows inside a parent table with a class of
.acf-table. In ACF 6 and above, field type settings are no longer rendered inside of a table.
As a result, the
acf_render_field_setting() function has been updated to render the field settings created by that function inside of
elements by default.
This likely won’t cause any issues if you’re using
acf_render_field_setting() in one of the action hooks mentioned above or in a class that extends
acf_field.
While not recommended, it is possible to use the
acf_render_field_setting() function outside of those action hooks. In that case, we would recommend checking any settings created with that function to ensure that they are displayed as expected, and updating your code as necessary.
Changes to Field Setting Instructions in ACF 6
In ACF 6, the value of the
instructions parameter passed to
acf_render_field_settings() is now rendered as a tooltip to reduce UI clutter.
If you would rather display the
instructions inline with the field setting (such as in ACF 5), you can do so by changing the
instructions parameter to
hint:
function my_textarea_render_field_settings( $field ) {
acf_render_field_setting( $field, array(
'label' => __( 'Exclude Words', 'my-textdomain' ),
'hint' => __( 'Enter words separated by a comma', 'my-textdomain' ),
'name' => 'exclude_words',
'type' => 'text',
) );
}
add_action( 'acf/render_field_validation_settings/type=textarea', 'my_textarea_render_field_settings' );
This will render the provided hint text underneath the field setting:
Conclusion
Adding extra field settings in ACF is easy and the possibilities are endless!
Adding fields to Media Attachments
This guide will demonstrate how to add custom fields to a WordPress Attachment and how to then display these fields.
All the template functions (get_field(), the_field(), etc) can be used to load values from a media attachment, however, a second parameter is required to target the attachment.
Changelog
Added attachment types to location rule in version 5.6.0
Adding fields
The Advanced Custom Fields plugin makes it very easy to add custom fields to an Attachment, please follow the steps below.
From the Custom Fields admin screen, click the Add New button to create a new field group
Add the fields you would like to see when editing an Attachment
Under Locations, select the Attachment rule and choose ‘All’ (to show this field group on all attachments) or a specific attachment type (to show this field group only for specific attachments)
Editing fields
Once you have created a field group and assigned it to appear for an Attachment edit screen, editing the field values is done by one of the following:
Navigating to the Media > Library admin page and selecting an attachment.
Using the Add Media button when editing a post’s content.
Using an ACF image field or file field to select an attachment.
WP stores each Attachment as a post object in the
wp_posts table. ACF will store all custom field values in the
wp_postmeta table.
Displaying fields
Customizing the HTML for a WordPress Attachment will differ depending on the context. Attachments are used in many ways by different themes. The following example uses a file field (from a post edit screen) to select an Attachment. The selected Attachment (.pdf) has been assigned a ‘Thumbnail’ which is displayed with the file info below.
Note how the Attachment ID is used to load the field value from the selected Attachment.
single.php
Read more
Result
Here is an example of the above code in action. Note the
tag created with the Attachment’s Thumbnail value**.**
Examples
Display a field
This example will display a field value from an Attachment (attachment ID = 12)
Retrieve a field
This example will load a field value from an Attachment (attachment ID = 12)
Retrieve from another image custom field
This example will show how to load a selected image from a custom field, and then load a custom field from that image.
Working with the Repeater Field
This example will show how to loop over an attachment field’s repeater field value (attachment ID = 123).
Note that when inside of a
have_rows loop, you do not need to use the
$post_id parameter for any sub field functions (get_sub_field(), the_sub_field())
';
// append style
$html_color = '';
// append html
$items = $html_logo . $items . $html_color;
}
// return
return $items;
}
Conclusion
Here is a look at how this may look in your browser. Notice the new logo
and color
Example
Here is a look at how the above code look in your browser. Note the site header image now reflects the category image and all entry titles are green.
Notes
Loading from a specific term
All the template functions can be used to load values from a taxonomy term, however, a second parameter is required to target the term. This is similar to passing through a
$post_id parameter to target a specific post object.
There are 3 different styles of
$post_id available and are listed below.
Example
Format
Description
'category_123'
$taxonomy . '_' . $term_id
A string containing the taxonomy name and term ID
'term_123'
'term_' . $term_id
A string containing the word ‘term’ and term ID. Added in version 5.5.0
WP_Term
A term object. You can get a term object via many of WP’s functions such as get_term()
auto-embed
When editing a WYSIWYG field on a taxonomy term, the auto-embed functionality may not work. This is due to code within the WordPress core which limits the auto-embed functionality to posts only.
This issue carries onto the front end and prevents embed urls (youtube, vimeo, etc) from being converted to play-able embed objects.
As a current workaround for the front end, use this code at the top of your template (most likely category.php or similar). This code will set a custom post_ID and allow WP to load the embed.
category.php
taxonomy;
$term_id = $queried_object->term_id;
$GLOBALS['wp_embed']->post_ID = $taxonomy . '_' . $term_id;
?>
Automatic Structured Data with Schema.org
Automatically output Schema.org structured data for ACF fields as JSON-LD in the page head.
Description
ACF 6.8 introduces JSON-LD structured data output for ACF fields. This feature maps ACF field values to Schema.org properties, enabling search engines and AI systems to better understand your content structure.
JSON-LD (JavaScript Object Notation for Linked Data) is Google’s recommended format for structured data. By mapping your ACF fields to Schema.org properties, you can:
Improve SEO with rich snippets in search results
Enable AI and LLM systems to understand your content (ChatGPT, Claude, Google AI Overviews)
Support Generative Engine Optimization (GEO) and Answer Engine Optimization (AEO)
Provide machine-readable data for content aggregators
ACF supports 867 Schema.org types and 1,509 properties out of the box.
See the ACF 6.8 release post for an overview.
Experimental Feature
This feature is marked as experimental in the ACF admin UI. The field of generative engine optimization (GEO) is evolving rapidly, and best practices for how AI systems interpret and surface structured data are still emerging. We encourage you to experiment with this feature and share your feedback.
Requirements
ACF 6.8 or later
WordPress 6.0 or later
Setup
Enable the Schema Feature
Add this filter to your theme’s
functions.php or a custom plugin:
add_filter( 'acf/settings/enable_schema', '__return_true' );
1. Enable JSON-LD for a Post Type
Edit your ACF custom post type and navigate to the Schema tab:
Enable “Automatically add JSON-LD data for fields on this post type”
Optionally select a Schema.org Type (e.g., Recipe, Product, Event)
The Schema.org type is auto-detected from your field mappings, but you can explicitly set it here.
2. Map Fields to Schema.org Properties
Edit each field and configure the Schema.org Property setting:
Open the field settings
Find “Schema.org Property” under general settings
Select the appropriate property (e.g.,
name,
description,
price)
Optionally configure the Output Format
Properties are filtered to show only those compatible with the field type.
Schema.org Types
ACF supports all Schema.org types. Common types include:
Type
Use Case
Article
Blog posts, news articles
BlogPosting
Blog entries
Product
E-commerce products
Recipe
Cooking recipes
Event
Events with dates/locations
Person
People, authors, team members
Organization
Companies, brands
LocalBusiness
Local business listings
HowTo
Step-by-step guides
FAQPage
FAQ content
Field Type Compatibility
Each ACF field type maps to specific Schema.org data types:
ACF Field Type
Schema.org Types
text,
textarea,
wysiwyg
Text, URL, Name
number,
range
Number, Integer, Float
email
Text (email format)
url
URL
date_picker
Date
date_time_picker
DateTime
time_picker
Time
true_false
Boolean
image
ImageObject, URL
select,
radio,
button_group
Text, Enumeration
user
Person
taxonomy
Text, Thing
Output Format
The JSON-LD is output in the
section of singular posts/pages:
Filters
ACF provides extensive filters for customizing JSON-LD output.
Output Control
Filter
Description
acf/schema/debug
Enable debug HTML comments
acf/schema/disable_output
Disable JSON-LD output for specific data
acf/schema/enabled_post_types
Filter post types with JSON-LD enabled
acf/schema/render_script
Action before script tag is rendered
Data Customization
Filter
Description
acf/schema/data
Modify final JSON-LD data before output
acf/schema/auto_add_image
Control automatic featured image inclusion
acf/schema/auto_add_author
Control automatic author inclusion
Post-Specific
Filter
Description
acf/schema/post_field_objects
Filter field objects for a post
acf/schema/post_field_objects/post_type={post_type}
Post type specific field objects
Block-Specific
Filter
Description
acf/schema/block_jsonld_enabled
Enable/disable JSON-LD for specific blocks
acf/schema/block_field_objects
Filter field objects for a block
acf/schema/block_field_objects/block_name={block_name}
Block-specific field objects
Value Formatting
Filter
Description
acf/schema/format_value/pre
Pre-format field value
acf/schema/format_value/pre/type={field_type}
Pre-format by field type
acf/schema/format_value/pre/name={field_name}
Pre-format by field name
acf/schema/format_value
Post-format field value
acf/schema/format_value/type={field_type}
Post-format by field type
acf/schema/format_value/name={field_name}
Post-format by field name
Schema Configuration
Filter
Description
acf/schema/schema_types
Filter available Schema.org types
acf/schema/schema_priority_types
Filter priority types in dropdowns
acf/schema/schema_properties
Filter available Schema.org properties
acf/schema/output_format_choices
Filter output format choices
ACF Blocks Support
JSON-LD output is also available for ACF Blocks. Enable via
block.json:
{
"name": "acf/recipe-card",
"title": "Recipe Card",
"acf": {
"autoJsonLd": true,
"schemaType": "Recipe"
}
}
Or via programmatic registration:
acf_register_block_type( array(
'name' => 'recipe-card',
'title' => 'Recipe Card',
'acf' => array(
'autoJsonLd' => true,
'schemaType' => 'Recipe',
),
));
Automatic Enrichment
ACF automatically enriches the JSON-LD output with core WordPress data:
Author: Person schema with name and archive URL
Featured Image: ImageObject with dimensions and URL
Post Metadata:
datePublished,
dateModified,
url,
name
This data is merged with your field mappings automatically.
Repeater Fields
Repeater sub-fields can map to Schema properties, creating arrays:
Field mapping: Repeater with Text sub-field mapped to
recipeIngredient
Output:
{
"recipeIngredient": [
"2 cups flour",
"1 cup sugar",
"3 eggs"
]
}
Notes
JSON-LD is only output on singular post/page views (not in block editor preview)
Empty field values are automatically excluded
Nested objects (like
author or
publisher) automatically get appropriate
@type values
The feature is marked as Experimental in the admin UI
Bidirectional Relationships
In a bidirectional relationship, each object (post, page, custom post type, user, or taxonomy) has a relationship field that refers to the other object. The relationship data is stored in an ACF field on both objects making it easier to query.
Currently, the Bidirectional setting is only available for the Relationship, User, Taxonomy, and Post Object fields
Setup
When editing a field group, supported field types will display a new “Advanced” tab with a Bidirectional toggle.
When enabled, you’ll be able to select one or more target fields which will be updated on each selected value for that field, back to the item being updated. This is a powerful and complicated feature. As such, it requires some thought about the connections you wish to make between fields across different item types. Here are some examples:
A Relationship field displayed on the
wc_product post type called “Related Products”. Enabling bidirectional, and setting the
Target Field to the same field (“This Field”) will automatically add the
wc_product Post ID being edited to the related products field on each of the selected values for related products.
A user field displayed on a post type “Business Sectors”, where the user selected indicates who to contact about that business sector. If you enable bidirectional and set the
Target Field to a relationship field output on a user, updating the business sector will automatically get all sectors they are responsible for on their author page.
The main complexity with bidirectional fields lies in determining where a field will be displayed in the edit screens. ACF supports showing the same field across multiple places, such as posts, users, taxonomies, option pages, blocks, etc., so the “item ID” being updated will vary depending on where it’s currently being displayed. This is usually a post ID, but could be a user ID or taxonomy term ID. However, you can’t save a user ID to a Post Object field, so the
Target Field for a field displayed on a user profile must be a User field to be updated.
Bidirectional enabled fields will therefore only update their targets when they’re displayed on a Post, User, or Taxonomy, and not on options pages, blocks, widgets, or any other location type which doesn’t resolve to a post ID, user ID, or taxonomy term ID. Whenever ACF tries to update a
Target Field it will ensure the item type being updated is compatible with the target field type. If not, it will skip the update.
You also can’t chain bidirectional updates; only the selected
Target Fields will be updated with the currently editing item ID. If the
Target Field also has bidirectionality enabled, it will not be updated past the original target field.
Known Issues
The bidirectional setting will currently only enable one-way syncing of the data to the target field, and not configure any reverse bidirectionality (unless you select
This Field as the
Target Field). If you wish to enable two-way syncing of data between two different fields, you’ll need to enable the bidirectional setting on the
Target Field field as well, and set its target back to the original field.
Bidirectional fields currently only support
Target Fields which are top level fields, and not fields contained within any other type of field, including Group fields.
Currently, while you can select a field which only allows single values, or a limited number of values, this is not respected when the field is being updated from a bidirectional origin field. This means, for example, if you’re trying to make a one-to-many relationship from a “User” field on a post, and more than one User references that post, it will not automatically be removed from the other User which previously had it selected, until you manually save the Post. This should not cause any display or templating errors, as the fields which are set to singular values will only return one value inside
get_field, but may lead to confusion in the UI.
Legacy Code Implementation
Previous to ACF 6.2 the only way to create a bidirectional relationship was with code.
View code
The following snippet adds a function to hook into the acf/update_value filter (run before a value is saved). It will update the custom field value of each selected post to include the current post’s ID as well as removing the current post’s ID from previously selected posts (which are no longer selected).
This function does not contain any hard-coded field names so it will work with any relationship field. The only change required is within the add_filter() parameter. It contains the name of the relationship field which in the example below is called ‘related_posts’.
functions.php
function bidirectional_acf_update_value( $value, $post_id, $field ) {
// vars
$field_name = $field['name'];
$field_key = $field['key'];
$global_name = 'is_updating_' . $field_name;
// bail early if this filter was triggered from the update_field() function called within the loop below
// - this prevents an infinite loop
if( !empty($GLOBALS[ $global_name ]) ) return $value;
// set global variable to avoid infinite loop
// - could also remove_filter() then add_filter() again, but this is simpler
$GLOBALS[ $global_name ] = 1;
// loop over selected posts and add this $post_id
if( is_array($value) ) {
foreach( $value as $post_id2 ) {
// load existing related posts
$value2 = get_field($field_name, $post_id2, false);
// allow for selected posts to not contain a value
if( empty($value2) ) {
$value2 = array();
}
// bail early if the current $post_id is already found in selected post's $value2
if( in_array($post_id, $value2) ) continue;
// append the current $post_id to the selected post's 'related_posts' value
$value2[] = $post_id;
// update the selected post's value (use field's key for performance)
update_field($field_key, $value2, $post_id2);
}
}
// find posts which have been removed
$old_value = get_field($field_name, $post_id, false);
if( is_array($old_value) ) {
foreach( $old_value as $post_id2 ) {
// bail early if this value has not been removed
if( is_array($value) && in_array($post_id2, $value) ) continue;
// load existing related posts
$value2 = get_field($field_name, $post_id2, false);
// bail early if no value
if( empty($value2) ) continue;
// find the position of $post_id within $value2 so we can remove it
$pos = array_search($post_id, $value2);
// remove
unset( $value2[ $pos] );
// update the un-selected post's value (use field's key for performance)
update_field($field_key, $value2, $post_id2);
}
}
// reset global varibale to allow this filter to function as per normal
$GLOBALS[ $global_name ] = 0;
// return
return $value;
}
add_filter('acf/update_value/name=related_posts', 'bidirectional_acf_update_value', 10, 3);
Block API v2
Introduction
Since WordPress 5.6, the block editor has a new version of the Block API. The ACF 5.10 release introduced support for the Block API v2. This is only available when ACF is installed on sites using WordPress 5.6 and above.
Changes
The block wrapper element for ACF Blocks with Block API v2 support now have a predefined class of
wp-block-{name}, where
name is generated from the name of the block. This is in line with the changes to how the block editor defines the default wrapper element.
Block Filters
In ACF 5.10 we moved to support version 2 of the WordPress Blocks API. The goal was to support more advanced functionality such as the ability to use the Block Editor’s
extraProps filter. Unfortunately, our implementation of this triggered re-rendering of ACF blocks anytime a property changed, which caused issues with other block editor features such as block styles and the built-in spacing/padding support.
ACF 5.11 removed support of the extraProps functionality to prevent these re-renders which will improve performance and solve issues with block styles. We want ACF blocks to function as closely as possible to core or custom-built WordPress blocks. Therefore, we’re working on re-introducing support for this in an upcoming release.
Block Bindings
Block bindings allow you to connect WordPress block attributes to ACF field values. Instead of hardcoding content in a Heading, Paragraph, Image, or Button block, you can bind the block’s content to an ACF field. When the field value changes, the bound block content updates automatically.
ACF 6.8.1 introduces full support for WordPress’s Block Bindings API, including integration with the editor’s Attributes panel UI and live preview with in-place editing.
Requirements
ACF PRO 6.8.1 or later
WordPress 6.7 or later
The ACF datastore enabled
Enabling Block Bindings
Block bindings require two things to be enabled:
1. Enable the Datastore
Add this filter to your theme or plugin:
add_filter( 'acf/settings/enable_datastore', '__return_true' );
See acf/settings/enable_datastore for more options.
2. Enable Fields for Bindings
For each field you want to use with block bindings, enable “Allow Access to Value in Editor UI” in the field settings:
Edit your field group
Select the field you want to expose
Go to the Presentation tab
Enable “Allow Access to Value in Editor UI”
Save the field group
Only fields with this setting enabled will appear in the Block Bindings UI.
Using Block Bindings in the Editor
Once enabled, you can bind blocks to ACF fields directly in the editor using WordPress’s Attributes panel.
Supported Blocks
The following core blocks support attribute bindings:
Heading – content attribute
Paragraph – content attribute
Image – url, alt, and title attributes
Button – text and url attributes
Binding a Block
Add or select a supported block (e.g., Heading)
Open the block settings sidebar
Look for the “Attributes” panel
Click the attribute you want to bind (e.g., “Content”)
Select “ACF Field” as the source
Choose from your available ACF fields
The block will now display the ACF field value, and updates to the field will reflect in the block.
Live Preview and Editing
When block bindings are enabled with the datastore, you get live preview and in-place editing:
Real-time updates – Changes to ACF fields immediately update bound blocks in the editor
In-place editing – Click on a bound block and edit its content directly
Bidirectional sync – Edits made in the block sync back to the ACF field
This creates a seamless editing experience where bound blocks behave like native Gutenberg content while remaining powered by your ACF field values.
Supported Field Types
Block bindings work with field types that return simple values compatible with block attributes:
Field Type
Supported
Notes
Text
Yes
Textarea
Yes
Number
Yes
Converted to string
Email
Yes
URL
Yes
Password
Yes
Select
Yes
Single value only
Radio Button
Yes
True/False
Yes
Returns “true” or “false”
Date Picker
Yes
Time Picker
Yes
Color Picker
Yes
Image
Yes
Returns URL for image bindings
File
Yes
Returns URL
Unsupported Field Types
Complex field types that return arrays or objects are not supported:
Repeater
Flexible Content
Gallery
Group (as a whole, but sub-fields can be bound)
Relationship (returns array of IDs)
Post Object (when set to return multiple)
Checkbox (returns array)
Value Formatting
Bound values are formatted for display in blocks:
Value Type
Display
Strings
Displayed as-is
Numbers
Converted to string
Booleans
“true” or “false”
Arrays of scalars
Joined with “, “
Objects/nested arrays
Empty string
Programmatic Bindings
You can also create bindings in code using the Block Bindings API.
In Block Markup
Add bindings to a block’s metadata:
In PHP Templates
';
echo do_blocks( $block_content );
?>
Image Bindings
Bind an image block to an ACF Image field:
Button Bindings
Bind a button’s text and URL:
Disabling Bindings for Specific Fields
To prevent a field from being used in bindings, you can:
In the Admin UI
Disable “Allow Access to Value in Editor UI” in the field’s Presentation tab.
In Code
Set
allow_in_bindings to
false when registering the field:
acf_add_local_field( array(
'key' => 'field_my_field',
'name' => 'my_field',
'type' => 'text',
'allow_in_bindings' => false,
) );
Or in a JSON field group:
{
"key": "field_my_field",
"name": "my_field",
"type": "text",
"allow_in_bindings": false
}
Troubleshooting
Fields Not Appearing in Attributes Panel
Verify the datastore is enabled (
acf/settings/enable_datastore filter returns
true)
Check that “Allow Access to Value in Editor UI” is enabled for the field
Confirm you’re using WordPress 6.7 or later
Ensure the field type is supported (see table above)
Bound Content Not Updating
Check the browser console for JavaScript errors
Verify the field has a saved value
Try refreshing the editor
Bindings Work in Editor but Not on Frontend
Server-side rendering should work regardless of datastore settings. If bound content isn’t appearing on the frontend:
Check that the field has a value for the current post
Verify the field key in the binding matches your field
Related
Using the ACF Datastore – Full guide to the datastore feature
WordPress Block Bindings API – WordPress developer documentation
blocks/expanded_editor_overlay_class
Customize the CSS class on the Expanded Editor modal overlay.
Description
This JavaScript filter allows you to modify the CSS class applied to the Expanded Editor modal overlay in ACF Blocks V3. This is useful for applying custom styling to the overlay.
Parameters
acf.addFilter( 'blocks/expanded_editor_overlay_class', function( className, block ) {
return className;
});
className
(string) The CSS class name for the overlay. Default:
'acf-expanded-editor-overlay'
block
(object) The block object containing block data and attributes.
Example
Add a custom class to the overlay
acf.addFilter( 'blocks/expanded_editor_overlay_class', function( className, block ) {
return className + ' my-custom-overlay';
});
Apply different classes based on block name
acf.addFilter( 'blocks/expanded_editor_overlay_class', function( className, block ) {
if ( block.name === 'acf/hero' ) {
return className + ' hero-overlay';
}
return className;
});
Replace the class entirely
acf.addFilter( 'blocks/expanded_editor_overlay_class', function( className, block ) {
return 'my-overlay-class';
});
Changelog
Added in version 6.8
Notes
This is a JavaScript filter, not a PHP filter
Use
acf.addFilter() to register the filter in your block editor scripts
The filter runs when the Expanded Editor modal is opened
This filter only applies to ACF Blocks V3
ACF Blocks
Introduction
ACF Blocks are customizable, dynamic, and integrate deeply with custom fields. A premium feature found in ACF PRO, ACF Blocks uses a powerful PHP-based framework to develop custom block types without the thorough knowledge of JavaScript or React required to create WordPress blocks.
The PHP-based nature of ACF Blocks means PHP developers can easily create bespoke solutions in line with modern WordPress theme development. ACF Blocks maintain compatibility with WordPress core, providing access to many of the same features as native blocks.
Simplify Your Workflow
PHP Environment
ACF Blocks is a PHP framework and does not require any JavaScript. This differentiates itself from the WordPress block API which relies heavily on modern JavaScript techniques, syntax and build tools.
Simple Templating
Similar to WordPress theme development, ACF Blocks are rendered using a PHP template file or callback function, allowing full control over the HTML output.
Custom Fields Compatible
ACF Blocks offer full compatibility with all field types including both the Repeater and Clone fields! Build your field group and attach it to your newly-registered block using ACF’s familiar Location rules.
It’s a similar story for template functions. Whether you are loading a field value via
get_field(), or looping over a Repeater field using
have_rows(), the experience remains familiar and consistent with regular theme development.
Live Previews
Content changes, and so do block previews! When editing an ACF Block, the HTML will update in the backend giving you a real-time preview of your content. If you use an ACF Block in a Query Loop block or in a Full Site Editing Block Theme, your block preview will automatically update as your query changes.
Total WordPress Compatibility
Native Compatibility
ACF Blocks maintain native compatibility with WordPress core. This allows features such as “alignment”, “anchor” and even Reusable Blocks to work!
ACF Blocks are not compatible with the standalone Gutenberg plugin, as the plugin forces on new, experimental features and API versions which are not yet supported by ACF.
Anywhere and Everywhere
ACF Blocks are not tied to metadata, meaning they can be used anywhere in WordPress, and multiple times per post.
Block Asset Loading
ACF Blocks supported enqueueing block-specific assets before WordPress did! WordPress now supports this, requiring assets be loaded using specific WordPress asset configuration keys. Blocks created with earlier versions of ACF Blocks should be migrated to use the WordPress provided methods.
block.json Support
ACF Blocks are registered with the standard WordPress function,
register_block_type(), which loads a
block.json file containing your configuration.
add_action( 'init', 'register_acf_blocks' );
function register_acf_blocks() {
register_block_type( __DIR__ . '/blocks/your-example-block' );
}
Flexible Design & Development
Block Versioning
Introduced in ACF 6.0, block versioning allows you to opt in to enable new features, or opt out to ensure blocks you’ve already created maintain backwards compatibility.
Blocks Without Fields
ACF Blocks can be created without fields, useful in cases where you want to show post templating elements such as titles or post content, or when you want to display fields which are added on the post being displayed, rather than from the block.
InnerBlock Support
ACF Blocks include full support for InnerBlocks, allowing you to nest blocks inside one another. This can be achieved by adding
to your PHP template file for the block.
Block Context Changes
ACF Blocks support block context. This means you can configure your blocks to pass data to their InnerBlocks, including data from the ACF fields on the parent block. When anything about this block context changes, it will automatically reload the template of the child blocks, while your template handles any changes the parent block’s field values may cause.
Next Steps
ACF Blocks give you the functionality of native WordPress blocks, in a familiar PHP environment. This feature of ACF PRO lets you give your clients perfectly tailored solutions that combine the power of Advanced Custom Fields with the ease of content editing and layout offered by the modern WordPress Site Editor.
Next, we’ll look at some of the key concepts used in WordPress blocks, and how they apply when creating ACF Blocks.
Next: Key Concepts
Questions about ACF Blocks? Check out our FAQ.
Building Layouts With the Flexible Content Field in a Theme
ACF’s Flexible Content fields allow you to create multiple groups of fields known as layouts. You can then use these to give content editors more control over how data is rendered.
In this article, I’ll give you a complete use case and show how you can leverage the Flexible Content field to create swappable site sections and integrate it all in a theme.
Think of Flexible Content as a way to make WordPress layout patterns, but with ACF PRO fields and subfields. Generally, the idea is to create atomic blocks, elements, units–or whatever you prefer to call the smaller pieces of UI–and compose them into whole flexible patterns. Ideally, these patterns are a starting point for editors to kickstart their content writing experience.
I’ve created a fictitious company site to demonstrate how to compose layouts with Flexible Content fields. Qorp is a new tech company that needs a site for its trendy new tech.
What is the tech? Nobody truly knows 🤪.
Qorp would like the ability to add and remove sections below their blog posts. Also, they want to be able to place them in any order. This is one example where Flexible Content fields can really shine. Below, I’ve included an image capturing the visual mixing and matching that Qorp required for their single blog posts.
There are three sections: Call to Action, Trust Signals, and Related Posts, all built with layouts created within a Flexible Content field. ACF makes it simple for Qorp’s content team to switch them around, add more of one layout, or remove them entirely if that’s what’s needed for a particular post.
Setting Up Our Flexible Content Field
The first thing we want to do is create a new field group with a Flexible Content field and give it a name. I named my field group: “Single Post: wrap-up sections” and my field “Sections.”
Next, make sure to set the Location Rules to Post Type – is equal to – Post. This ensures our fields only show when Qorp is editing a “Post” post type. Be sure to choose Flexible Content as the parent field type. I also recommend prefixing your Flexible Content field’s Name, e.g.,
qorp_post_sections.
New Flexible Content field group with Post Type = Post as the Location Rules.
At this point, we’ve got our Flexible Content field showing for our Qorp content creators, but there’s nothing on the frontend yet.
The Flexible Content field won’t do the client much good until we give them some layouts in the next section.
Creating Subfields Within the Flexible Content Field
Now that we’ve established our Flexible Content field, we’ll want to create our layouts. Remember, layouts are the nested field groups within a Flexible Content field which can be used to present the data differently for each layout.
Based on our design, we have the following sections we need to account for: Call to Action, Trust Signals, and Related Posts.
Call to Action: This features a small descriptive text, often called an eyebrow, followed by a heading and a button.
Label: Call to action
Name:
call_to_action
Layout: Block
Fields:
Label: Eyebrow / Name:
eyebrow / Type: Text
Label: Heading / Name:
heading / Type: Text
Label: Button / Name:
button / Type: Group
Button sub-fields:
Label: Button text / Name:
button_text / Type: Text
Label: Button link / Name:
button_link / Type: URL
Since we’ve added our first layout, there’s something to see now when our clients look at their posts. There’s only one section so far, but we’re on our way.
[
](https://www.advancedcustomfields.com/wp-content/uploads/2022/12/Call-to-Action-demo_resized.mp4)
Trust Signals: A heading with affiliated company logos underneath.
Label: Trust Signals
Name:
trust_signals
Layout: Block
Fields:
Label: Logo / Name:
logo / Type: Repeater
Repeater sub-fields:
Label: Logo / Name:
logo / Type: Image
Now that we’ve added a subfield for the Trust Signals section, we can see it has appeared on our client’s posts beneath their CTA.
[
](https://www.advancedcustomfields.com/wp-content/uploads/2022/12/Trust-Signals_Resized.mp4)
Related Posts: Manually curated posts related to the current post, which the Qorp editorial team can set.
Label: Related Posts
Name:
related_posts
Layout: Block
Fields:
Label: Posts / Name:
posts / Type: Relationship
When we look at the frontend, we can see the Related Posts field displaying as it should.
[
](https://www.advancedcustomfields.com/wp-content/uploads/2023/01/Related-Posts_resized.mp4)
With all of the layouts in place, our clients at Qorp can easily rearrange the layouts to suit the needs of the post.
[
](https://www.advancedcustomfields.com/wp-content/uploads/2022/12/Rearranging-content_resized.mp4)
Output Flexible Content Fields in a Block Theme
Next, we’ll walk through outputting the Flexible Content field data within a block theme. If you’re new to block themes, I recommend you check out “Introduction to block theme development“. WordPress is remarkable, as even block themes allow us to use classic template hierarchy and functionality. We’ll lean on these to output our post metadata. We can add a
single.php template file (complete source code) with the following logic:
single.php
get_header();
/* Start the Loop */
while ( have_posts() ) :
the_post();
get_template_part( 'template-parts/content/content-single' );
// ACF - Flexible Content fields.
$sections = get_field( 'qorp_post_sections' );
if ( $sections ) :
foreach ( $sections as $section ) :
$template = str_replace( '_', '-', $section['acf_fc_layout'] );
get_template_part( 'flexible-content/sections/' . $template, '', $section );
endforeach;
endif;
endwhile; // End of the loop.
get_footer();
The bulk of this logic is referencing other template files, but we’re grabbing our
qorp_post_sections and then looping through them and calling separate template files based on which Flexible Content layout is returned.
Here are the template files:
qorp-theme/flexible-content/sections/call-to-action.php
qorp-theme/flexible-content/sections/related-posts.php
qorp-theme/flexible-content/sections/trust-signals.php
All of the source code for the Qorp site is on GitHub. You can also see an example of the final output on Qorp’s site. Also, be sure to check out the final fields (layouts.json) within the qorp-plugin.
ACF’s Flexible Content fields give you the power to offer your clients flexibility for their content, while ensuring they don’t go too far afield from the way their site is supposed to look.
Below 👇 is a video that demonstrates the editorial flow for using these Flexible Content fields.
The Flexible Content field type is arguably one of the most powerful field types in ACF PRO. We’ve seen just how powerful it can be when we looked at how the agency Rareloop uses it to create a page builder experience for their clients.
Button Group
Description
The Button Group field provides a neat UI for selecting a value.
Screenshots
The Button Group field interface
The Button Group field settings
Changelog
Added in version 5.6.3.
Settings
Choices
The choices displayed when selecting a value. Enter each choice on a new line (eg.
Red). For more control over the value and label, you may use a colon to specify both (eg.
red : Red). You may also enter HTML as a choice as shown in the above screenshots.
Allow Null
Allows no value to be selected.
Default Value
The default values selected when first editing the field’s value. Enter only values, not labels.
Layout
The layout orientation of the inputs. Select from "Vertical" or "Horizontal".
Return Format
Specifies the value format returned by ACF functions. Select from "Value", "Label" or "Both".
Template usage
Display value
This example demonstrates how to display the selected value using the Return Format setting
Value.
Color:
Display value and label
This example demonstrates how to display the selected value and label using the Return Format setting
Both.
Color:
Conditional
This example demonstrates how to use a selected value to conditionally perform a task.
array(
array(
'key' => 'color',
'value' => 'red',
)
)
) );
if( $posts ) {
foreach( $posts as $post ) {
// Do something.
}
}
Checkbox
Description
The Checkbox field creates a list of check-able inputs.
Screenshots
The Checkbox field interface
The Checkbox field settings
Changelog
Added
Return Format setting in version 5.4.0.
Added
Toggle All setting in version 5.2.7.
Settings
Choices
The choices displayed when selecting a value. Enter each choice on a new line (eg.
Red). For more control over the value and label, you may use a colon to specify both (eg.
red : Red).
Default Value
The default values selected when first editing the field’s value. Enter only values, not labels.
Layout
The layout orientation of checkbox inputs. Select from “Vertical” or “Horizontal”.
Toggle
Prepends an extra checkbox to toggle on/off all inputs.
Return Format
Specifies the value format returned by ACF functions. Select from “Value”, “Label” or “Both”.
Allow Custom
Appends a button that allows custom values to be added when editing the field’s value.
Save Custom
Allows custom values to be saved back into the field’s choices. See Notes for more information.
Template usage
The checkbox field returns an array of selected choices.
Display value
This example demonstrates how to display the selected values in a comma-delimited list.
Colors:
Display values in a list
This example demonstrates how to display the selected values in an unordered list.
Display labels in a list
This example demonstrates how to display the selected labels in an unordered list when Return Format is set to
Value.
This example demonstrates how to display the selected labels in an unordered list when Return Format is set to
Both.
Conditional logic
This example demonstrates how to check if the choice “red” was selected in the field’s value.
$colors = get_field('colors');
if( $colors && in_array('red', $colors) ) {
// Do something.
}
Query posts
This example demonstrates how to query posts that contain a checkbox field named “colors” with the value “red” selected. Because the checkbox field saves its value as a serialized array, it is important to use the meta_query “LIKE” comparison.
$posts = get_posts(array(
'meta_query' => array(
array(
'key' => 'colors',
'value' => '"red"',
'compare' => 'LIKE'
)
)
));
if( $posts ) {
// Do something.
}
Notes
Save custom
If using the local JSON feature, any custom values saved to the field’s choices will not appear on page reload. This is because the JSON file will not be updated and will override any field settings found in the database.
Clone
Overview
The Clone field allows you to select and display existing fields. It does not duplicate any fields in the database. Instead, it loads and displays the selected fields at run time.
You may also select one (or more) field groups, making it possible to load in “module” groups. A good example of this can be seen in the demo video below, where a single field group is created for “Button” information. This field group is then cloned when a button is needed.
The Clone field may be used in one of two ways. It can replace itself with the selected fields (seamless) or display the selected fields as a group of sub fields.
Demo
https://www.advancedcustomfields.com/wp-content/uploads/2023/04/ACF-PRO-Clone-field-resized.mp4
For more, please see our tutorial on how to use the Clone field.
Changelog
Added in version 5.4.0
Settings
Name
Description
Fields
An array of fields/groups to clone.
Display
Specify how to display the cloned fields. - Seamless – Completely replaces the Clone field with selected fields. Very useful to re-use fields within a Repeater or Flexible Content field. - Group – Displays the selected fields within a group. Very useful to re-use an existing group or ‘modules’ such as a group containing “button” settings (used in following examples).
Layout
Change the layout style. - Block – fields are displayed as normal (labels top aligned). - Table – fields are displayed in a table (labels in table header) with each field in its own column. - Row – fields are displayed in rows (labels left aligned).
Prefix Field Labels
This setting will modify all selected fields labels and prefix the current Clone field’s label. Very useful when using the “Seamless” display. You could name your Clone field “Hero” and have it prefixed to all selected fields like “Hero Button Text,” “Hero Button URL,” etc.
Prefix Field Names
Similar to the above, but will modify the field’s name. The name is used to save/load values. Very useful when using the “Group” display. You could clone a group multiple times on 1 edit screen, but have them save data with different names, e.g.,: “hero_button_text,” “welcome_button_text,” etc.
Template Usage
Loading the value of a cloned field is the same as loading a normal field. If using the “Group” display setting, you may also load all cloned values as an array by loading the Clone field itself.
Some of the following examples use a Clone field called “main_button,” which is cloning a field group called “Button.” The Button field group contains 2 fields called “text” and “url.”
Basic
This example shows how to load a Clone field value with the following default settings. Note that these settings will essentially replace the Clone field with the selected fields:
Name: main_button
Display: seamless
Prefix Names: no
Fields: A field group called “Button”, as described above
Prefix field names
This example shows how to load a Clone field value with the following “Group” settings. Note that these settings will render the “button” fields within a group and prefix the field names. All values will be saved and loaded with the name prefix
main_button_.
Name: main_button
Display: group
Prefix Names: yes
Fields: A field group called “Button”, as described above
Using the “Group” display setting will allow ACF to load the cloned field values as an array, like so:
Sub fields
Clone fields may also be used within a Repeater or Flexible Content field. This example shows the same “main_button” Clone field from the previous example, but this time used within a Repeater field.
Limitations
The Clone field has a few limitations. These limitations are found in edge cases when using Clone fields within Repeater or Flexible Content fields.
Multiple cloned sub fields
A cloned sub field may not be able to save its value if it exists alongside another instance of itself. For example, imagine a Repeater field called “Row” containing 2 Clone fields, both cloning in the same field, called “Cell”. Even if both Clone fields use the “Prefix Name” setting to make each “Cell” have a unique name, they both use the same
field_key, so they will override each other during save.
Using the have_rows() function with a nested Clone field
The have_rows() function will return false when loading a cloned sub field using the “Group” display setting and layout set to “Block”. Please note that using the “Seamless” display setting will allow sub
have_rows() loops to work as expected.
Notes
Data structure
The Clone field does not change the data structure when saving values to the database. The only change comes from the “Prefix Field Names” setting. Values are not saved as an array, but are saved as normal individual field values. This means that meta queries are possible as usual.
Data conflicts
It is possible to create data conflicts by cloning a field with a name already used in the group. This is the same issue as creating 2 fields using the same name. Please use the “Prefix Field Names” setting when appropriate to avoid this.
A good rule of thumb is to use the “Prefix Field Names” setting when choosing the “Group” display setting, and the opposite when using the “Seamless” display setting.
Disabled field groups
It is possible to clone a field group that is set to “Disabled”. Disabling a field group prevents it from being loaded on a post edit page, which is a good idea when making module groups.
Cloning a clone
It is possible to clone a Clone field. This may sound extreme, but it can be a useful feature in specific scenarios. For example, you may be creating a page builder with the Flexible Content field and find that each layout contains the same “settings” fields. Instead of duplicating these fields in each layout (and the headache of maintaining changes to these fields across multiple layouts), you could define all “settings” fields in the first layout only. The second layout could use a Clone field to clone these “settings” fields. The third layout could use a Clone field to clone the one defined in the second layout.
The benefit of this is that if you add a new “setting” to the first layout, you only need to update the Clone field in your second layout. All other Clone fields (in layout 3, 4, etc.) will mimic this and show the new “settings” field!
Code Examples
Display a field
Retrieving a field as a variable
Using conditional statements
get_field returns false if (value == “” || value == null || value == false)
' . get_field('field_name') . '';
}
?>
Working with Array values
checkbox, select, relationship, repeater
';
foreach($values as $value)
{
echo '
' . $value . '
';
}
echo '';
}
// always good to see exactly what you are working with
var_dump($values);
?>
Working with Images – URL
Working with Images – ID
By using the ID, you can retrieve any crop size of the image and even get the name of the file!
Working with the Repeater Field
repeater can be accessed by get_field or the_repeater_field / the_sub_field
sub_field_1 = , sub_field_2 = , etc
Randomly select a repeater field row
Getting values from another page
sub_field_1 = , sub_field_2 = , etc
Query posts with ACF values
Example of finding Events (post type) where location (custom field – select) equals Melbourne (value).
Lots to read here: http://codex.wordpress.org/Template_Tags/get_posts.
-1,
'post_type' => 'event',
'meta_key' => 'location',
'meta_value' => 'melbourne'
));
if($posts)
{
echo '
';
}
?>
Color Picker
Description
The Color Picker field provides an interactive way to select a hex color string using Iris.
Screenshots
The Color Picker editor field interface
The Color Picker editor field settings
Settings
Default Value
The default value initially loaded into the Color Picker when first editing the field’s value.
Enable Transparency
Enable transparency control on the color picker. If enabled the Return format options switch to RGBA string or RGBA array.
Custom Palette
Define the available colors shown with the field. It accepts a comma-separated list of hex codes. Each hex code will be a default color shown in the palette. This setting can be found under the “Presentation” tab for the field settings.
Use colors from theme.json
If your theme contains a theme.json file, the colors defined there can be used as the color palette. To use this option, enable “Custom Palette”, ensure you have a supported theme, and choose “Use colors from theme.json”
Show Color Wheel
Set whether the Color Wheel should be shown or hidden. When hidden, only the color palette will be shown, along with the text field where the actual value is defined. This setting can be found under the “Presentation” tab for the field settings.
Template usage
The Color Picker field will return a string value containing the HEX color value including the prefix ‘#’. Below are examples using a Color Picker field named “color”.
Display value within inline styles
This example demonstrates how to generate an inline style using a Color Picker value.
Display value within style tags
This example demonstrates how to generate a CSS class using a Color Picker value.
Notes
Customization
The Color picker field modal can be customized via the JS filter color_picker_args.
Compiling Multiple ACF Blocks With Scripts
Introduction
The WordPress block editor has revolutionized the way we can create content in WordPress. Whether you’re developing a custom ACF Block, a theme, or a plugin, effective tooling can help make your development workflows faster.
While ACF Blocks do not require any tooling or building, the default
create-blockpackage uses
@wordpress/scripts to handle compilation of scripts and styles. But when you have multiple blocks, it makes more sense to create a custom workflow to compile all your blocks at once. Also, more modern features like the WordPress Interactivity API do require you to include a module and have a build script for your block.
In this tutorial, we’ll delve into the essential
@wordpress/scripts package, before showing how to create a multiple ACF Blocks workflow. We focus on three key commands from
@wordpress/scripts:
build,
start, and
build:copy-php. These commands are the foundation of your block editor project’s development workflow using ACF Blocks.
Understanding @wordpress/scripts
The
@wordpress/scripts package streamlines the development process, simplifying setup and management of build configurations for your ACF Blocks.
We’ll look at some of the most basic commands you can take advantage of, and then show how to utilize
@wordpress/scripts for a multiple ACF Block project.
To utilize
@wordpress/scripts, you must have the package installed as a dependency in your project:
npm install @wordpress/scripts --save-dev
Installing
@wordpress/scripts will add a
package.json file to the root of the directory if one does not already exist. Once the file has been created, commands can be added in the scripts definitions. This is where you will add the
build and
start commands:
{
"scripts": {
"build": "wp-scripts build",
"start": "wp-scripts start"
}
}
Let’s take a look at what each of these does.
The Build Command
npm run build
Once the build command completes, your project’s production-ready assets will be available in the
build directory. This creates a production build with compressed code that’s faster to download and can include third party modules for you to use, but the resulting files are harder to read and debug.
The Start Command
npm run start
The start command sets up a local development environment with hot module replacement (HMR) for real-time changes. Once the start command has been executed successfully, your project is now served locally, and any changes you make will trigger HMR, providing a seamless and efficient development experience.
You can use either of these commands to start your project. In many cases, you’ll want to use
npm run start during development to watch for changes, and
npm run build when it’s production ready.
Multiple ACF Block Implementation
Now that we have a foundational understanding of some of the basic script commands that
@wordpress/scripts has to offer, let’s build off these by creating a multiple ACF Block plugin project.
First, we need to add some new file structure to our WordPress plugin. The following screenshot shows the directory structure we will create.
├── MULTIPLE-ACF-BLOCKS-TOOLING
├── blocks
├── bar
├── blocks.json
├── index.js
├── render.php
└── styles.scss
├── foo
├── blocks.json
├── index.js
├── render.php
└── styles.scss
├── node_modules
├── multiple-acf-block.php
├── package_lock.json
└── package.json
To get started, first create the root directory in your plugins folder with a
blocks directory inside. After you create the two directories, run
npm install @wordpress/scripts --save-dev from the root directory of the plugin to install the needed packages and initialize your
package.json file.
There will need to be two directories under
blocks, named
bar and
foo. These are the blocks we’ll create, and each will need the following files to register and render the block:
blocks.json
index.js
render.php
styles.scss
You can run
touch blocks/foo/ to create the blank files as placeholders. Do this for all the needed files.
Adding Scripts to package.json
Now that we have our new file structure in place, let’s configure our
package.json file.
In the scripts property inside your
package.json, add the
build and
start commands. Your
package.json should look like the following:
{
"devDependencies": {
"@wordpress/scripts": "^28"
},
"scripts": {
"build": "wp-scripts build --webpack-src-dir=blocks --webpack-copy-php",
"start": "wp-scripts start --webpack-src-dir=blocks --webpack-copy-php"
}
}
The
--webpack-src-dir=blocks tag tells webpack to find the entry point for your project by scanning all script fields in
block.json files in the
./blocks directory. The fallback entry point is
src/index.js (other supported extensions: .jsx, .ts, and .tsx) if no
block.json file is found.
The
--webpack-copy-php part of the script tells webpack to copy over PHP files it finds to our
build output folder. This enables copying all PHP files from the source directory and its subfolders to the output directory.
Adding Configuration to Block Files
The next step is to add our configuration to the
block.json file in
bar, which sets up where to look for our script file,
file:./index.js. We’ll also configure
index.js to import our SCSS file,
styles.scss. All this is done by
wp-scripts default webpack configuration.
Add the following to the
bar folder’s
block.json file:
{
"apiVersion": 2,
"name": "mutiple-acf-blocks/bar",
"version": "0.1.0",
"title": "Bar",
"description": "A test acf block bar",
"script": "file:./index.js",
"acf": {
"mode": "preview",
"renderTemplate": "render.php"
}
}
Add the following to your
index.js in the
bar folder:
import './styles.scss';
console.log(Hello from Bar's JavaScript);
Because
wp-scripts uses webpack and supports CSS, it will automatically create the correctly compiled
style.css file for us if we import a Sass file in our JavaScript.
Finally, let’s add some styling to our
styles.scss file:
.bar {
color: red;
}
Let’s try running the build command and see what output we get within our build directory, and then we’ll discuss how this all gets wired up.
npm run build
If the command completed successfully, you should see the following in your
build directory :
├── build
├── bar
├── blocks.json
├── index.asset.php
├── index.css
├── index.js
└── render.php
Repeat the process for the
foo block, then run
npm run build. You should now see in the build folder both a
foo and
bar directory with the same files inside.
Registering your built blocks
Your last step is adding the following PHP in the
multiple-acf-block.php file at the root of your plugin to utilize the
register_block_type() function to register the blocks in your build directory.
My custom field:
Settings
The acf_form() function accepts an array of settings to customize the form element. Such settings include the ability to create a new post, edit a specific post, select which field groups to show, and customize HTML elements. Please read the complete acf_form() documentation to learn more about available settings.
Create Your First ACF Block
ACF Blocks give you the power to create virtually any block you could desire, with the same features found in WordPress core blocks, such as InnerBlocks, Variations, and Styles. In this tutorial, we’ll show you how to create a testimonial block using ACF Blocks, including registering the required ACF fields.
The blocks you create with ACF Blocks are a custom type of block, similar to native dynamic blocks, building their structure and content on the spot from a PHP template while ACF handles the rendering for you.
Below is a screenshot of what our final testimonial block will look like.
Ready to skip the step-by-step instructions?
You can dive right in by downloading the tt3child.zip! Be sure to have the TwentyTwentyThree theme installed as well as ACF PRO.
Parts of a Block
There are a few critical things to consider whenever you’re getting ready to create a new block. What information will editors need to control and update? What information might be statically rendered (PHP, HTML) and does the block require its own CSS? Your block may also contain custom JavaScript to power interactivity, but our first block here won’t require any.
Before creating a block, we need to think about the features required to power it.
You may want to consider creating a standalone prototype of the final component using only HTML and CSS. This will help solidify your plans, indicate which ACF fields will be required, and it may even help you determine which fields will empower your editors to intuitively manage their data. Planning becomes quicker and easier the more blocks you build.
We focus on a basic testimonial block in this tutorial, as it helps introduce the fundamental planning that you will utilize to create more complex blocks in the future.
Getting Started and Requirements
This tutorial uses a WordPress Child Theme to organize our ACF Blocks. However, you could just as easily organize your blocks within a custom WordPress plugin. We’ll demonstrate how to organize blocks in a plugin in future tutorials.
There are only three things that are necessary to follow this tutorial:
ACF PRO. ACF Blocks is a premium feature and is not available in the free version of ACF.
A self-hosted WordPress site where you have access to the
wp-content directory. We highly recommend spinning up a sandbox site in Local.
The default Twenty Twenty-Three theme installed and activated, so you can create a child theme to organize your customizations.
With that said, creating new ACF Blocks will require some working knowledge of PHP and CSS to create the templates and stylesheets. It’s also handy to have access to a code editor like Visual Studio Code, but it’s not technically required.
Create a Child Theme
For this tutorial, we’ll use the Create Block Theme plugin from WordPress.org to generate our child theme. After installing and activating the plugin, be sure you have the Twenty Twenty-Three theme installed and activated, and then click Create Block Theme under “Appearance” in the WordPress admin. This opens a list of options based on the current theme.
We select Create child of…” to proceed, give our child theme a name: “TT3 Child”, and click Generate. You should be prompted to download and save a
.zip of your new child theme.
Child themes should be placed alongside their parent theme found in
wp-content/themes. This structure ensures WordPress will look for template files in the child theme first, then check the parent theme if it doesn’t find the right template. This is what your final theme directory should look like after you unzip and place your child theme alongside the parent Twenty Twenty-Three theme:
wp-content/themes/twentytwentythree [parent theme]
wp-content/themes/tt3child [child theme]
Be sure to activate your new child theme once you’ve added it. Also, feel free to deactivate the Create Block Theme plugin, as it is no longer needed.
Create functions.php
The next step is to create a
functions.php file and save it in our child theme’s directory. Here is what the final code will look like in our new
functions.php.
Location Rules” while editing the field group. Once we’ve added our testimonial block’s
block.json, it should show up if we choose “Show this field group if: Block is equal to Testimonial.
Finally, we click Save Changes, which will automatically save a
group_xxxxxx.json file within our child theme. Remember when we created the
acf-json directory in the previous section? This is where our “Block: Testimonial” field group information is saved.
Every time we update our “Block: Testimonial” field group and click Save Changes, it will overwrite the existing
group_xxxxxx.json file with the latest information. The JSON sync feature is handy for working collaboratively, and it can even be version controlled.
Create the Template and Stylesheet
With our field group saved, the next step is to create the
testimonial.css and
testimonial.php files referenced in
block.json, and save them in the
testimonial subdirectory, relative to the testimonial block’s
block.json file. Afterwards you should have the following organization:
wp-content/themes/tt3child/blocks/testimonial/block.json
wp-content/themes/tt3child/blocks/testimonial/testimonial.css
wp-content/themes/tt3child/blocks/testimonial/testimonial.php
Having these critical files co-located is part of the convenience of leveraging ACF Blocks for creating your custom blocks.
Inside
testimonial.php
Here is what our entire
testimonial.php file will look like when we’re done. We’ll go over some of the relevant sections below.
';
$quote_attribution .= '' . $author . '';
if ( $author_role ) {
$quote_attribution .= '' . $author_role . '';
}
$quote_attribution .= '';
}
// Support custom "anchor" values.
$anchor = '';
if ( ! empty( $block['anchor'] ) ) {
$anchor = 'id="' . esc_attr( $block['anchor'] ) . '" ';
}
// Create class attribute allowing for custom "className" and "align" values.
$class_name = 'testimonial';
if ( ! empty( $block['className'] ) ) {
$class_name .= ' ' . $block['className'];
}
if ( ! empty( $block['align'] ) ) {
$class_name .= ' align' . $block['align'];
}
if ( $background_color || $text_color ) {
$class_name .= ' has-custom-acf-color';
}
// Build a valid style attribute for background and text colors.
$styles = array( 'background-color: ' . $background_color, 'color: ' . $text_color );
$style = implode( '; ', $styles );
?>
class="" style="">
'testimonial__img' ) ); ?>
Let’s break down some of what’s in our
testimonial.php. First, we have a PHP DocBlock with commented code, highlighting the parameters passed down through
$block.
';
$quote_attribution .= '' . $author . '';
if ( $author_role ) {
$quote_attribution .= '' . $author_role . '';
}
$quote_attribution .= '';
}
We’re doing some logic for
quote_attribution to make sure the content editor has provided this information. We can give them some smart fallbacks here, and set them up for success.
Next, we pass down the anchor ID that editors are allowed to enter on a per block basis in the block editor.
$anchor = '';
if ( ! empty( $block['anchor'] ) ) {
$anchor = 'id="' . esc_attr( $block['anchor'] ) . '" ';
}
We also want to pass all our unique classes down. Keep in mind that editors can also add special classes on a per-block basis in the block editor. That is why we first check for
if ( ! empty( $block[‘className’]).
Then we check for any special alignment classes that are enabled by default and inherited from WordPress core’s Block Supports APIs. Also, we’ll pass down our custom background color and text color.
// Create class attribute allowing for custom "className" and "align" values.
$class_name = 'testimonial';
if ( ! empty( $block['className'] ) ) {
$class_name .= ' ' . $block['className'];
}
if ( ! empty( $block['align'] ) ) {
$class_name .= ' align' . $block['align'];
}
if ( $background_color || $text_color ) {
$class_name .= ' has-custom-acf-color';
}
Finally, we have the heart of the output logic. In this section, we pass through the styling for our background, text colors, etc.:
$styles = array( 'background-color: ' . $background_color, 'color: ' . $text_color );
$style = implode( '; ', $styles );
… and last but not least, the data from our ACF fields:
class="" style="">
'testimonial__img' ) ); ?>
Using get_block_wrapper_attributes()
Including the
get_block_wrapper_attributes() function in your template allows you to use WordPress native
supports for blocks, such as colors and spacing. The function will automatically output a complete style attribute in the wrapper WordPress adds around your block, but it needs to be used in conjunction with ACF’s
is_preview variable for ACF Blocks to render correctly.
Inside testimonial.css
There are practically no limitations on how you style your blocks. The one used to style our example testimonial block is reproduced below for convenience. We’ve made certain choices here in regards to
box-sizing,
display, etc., but ultimately how you style your blocks is up to you.
.testimonial {
--testimonial-font-family: Baskerville,Baskerville Old Face,Hoefler Text,Garamond,Times New Roman,serif;
--testimonial-font-size: 1.5rem;
--testimonial-spacing: 0.5rem;
}
.testimonial {
align-items: center;
box-sizing: border-box;
display: flex;
flex-wrap: wrap;
}
.testimonial > * {
box-sizing: border-box;
flex-grow: 1;
min-width: 0;
overflow-wrap: break-word;
width: 100%;
word-break: break-word;
}
.testimonial__blockquote {
align-self: center;
font-family: var(--testimonial-font-family);
font-size: var(--testimonial-font-size);
line-height: 1.18;
padding: calc(4 * var(--testimonial-spacing)) calc(4.5 * var(--testimonial-spacing)) calc(2.5 * var(--testimonial-spacing));
position: relative;
}
.testimonial__blockquote::before {
color: currentColor;
content: "“";
display: block;
font-family: var(--testimonial-font-family);
font-size: calc(8 * var(--testimonial-spacing));
position: absolute;
top: calc(-1.25 * var(--testimonial-spacing));
}
.testimonial__attribution {
font-family: var(--wp--preset--font-family--system-font);
font-size: calc(0.6 * var(--testimonial-font-size));
line-height: 1.5;
margin-top: calc(2 * var(--testimonial-spacing));
}
.testimonial__author {
font-style: normal;
font-weight: 700;
}
.testimonial__role {
display: block;
}
.testimonial__image {
box-sizing: border-box;
height: 100%;
line-height: 0;
margin-bottom: 0;
}
.testimonial__image img {
height: 100%;
}
.testimonial__img {
box-sizing: border-box;
max-width: 100%;
object-fit: cover;
}
@media (min-width: 600px) {
.testimonial {
flex-wrap: nowrap;
}
.testimonial__col:first-of-type {
flex-basis: 64%;
}
.testimonial__col:last-of-type {
flex-basis: 38%;
}
}
Testing the Block
Now that we have the necessary files in place defining our block, template, and stylesheet, it’s time to take our testimonial block for a test drive.
We create a new post and select Testimonial from the block inserter. Next, we fill in all the fields, including the image. We can choose to alter the background and text color here as well if desired, but the block will simply use the theme colors if we don’t change them. When you’ve filled in all the fields, click Publish, and the testimonial we’ve created is visible on the frontend of our site. You can see the whole process in the video below.
https://www.advancedcustomfields.com/wp-content/uploads/2023/05/testimonial-block-demonstration.mp4
Conclusion
Following this tutorial will result in the creation of a basic testimonial block, but ACF Blocks has much more potential. ACF Blocks provides most of the features available when building WordPress blocks with React, but in a PHP-based framework.
There are numerous ways to improve the basic testimonial block we’ve created here. In the next tutorials, we show how you can use WordPress core’s
InnerBlocks component with ACF Blocks to pass an array of core blocks and pre-populate the nested block data with
, and then use
templateLock="all" to lock them down and set our content editors up for success.
We can go still further and extend our use of
InnerBlocks to include Styles and allow for the addition of a class to our final output, which we can target with specific stylistic appearances.
Adding
InnerBlocks to our testimonial block would also give us access to Variations. This goes far beyond appearance, allowing for different versions of blocks that retain some of the same functionality.
Once you understand how they work, ACF Blocks open a world of limitless possibilities. With this tutorial under your belt, we’re excited to see what you build.
Creating a Custom Post Type with ACF
WordPress is a powerful CMS, but out-of-the-box it can lack flexibility when handling content types beyond standard posts and pages. While the default post types work well for typical blog content and static pages, you might need custom post types to organize more complex information. In this video, we’ll show how to use the Advanced Custom Fields (ACF) plugin to create a custom post type called “Cars” and associate additional data with it.
Why Create a Custom Post Type?
The default WordPress post types like Posts and Pages work well for simple content structures. However, they’re limited when managing posts with more complex data needs, such as products, events, portfolio items, or staff and team member listings. Custom post types provide flexibility, allowing you to structure and display complex information tailored to your website’s needs.
In this guide, we’ll create a “Car” custom post type that can handle specific car data, including details like price, mileage, and miles per gallon (MPG).
Step 1: Register a Custom Post Type for Cars
Our first step is to register a new post type called “Car” in the ACF plugin. Follow these steps:
In the WordPress admin, go to ACF > Post Types and select Add New.
Fill in essential details:
Plural Label: Cars
Singular Label: Car
ACF will automatically generate the post type key for you, but you can modify this if you wish. In the Advanced Configuration section, you can optionally add an icon representing the “Car” post type in the WordPress admin menu.
Click Save Changes to save your custom post type.
For more details and advanced options including visibility, URLs, permissions, and REST API settings, please see ACF’s guide on registering custom post types.
Step 2: Add Your First Car Post
Once the “Car” post type is registered, you can add your first post:
In the Cars section of the WordPress admin, click Add Car.
Enter the post’s title, add a description, and assign a featured image.
Save your post.
At this point, the post displays basic information, but doesn’t show the specific car details we want to include. To get those, we’ll need to create a child theme and then add ACF custom fields.
Step 3: Create a Child Theme to Customize Display
To customize how the custom post type displays, you’ll need to create a child theme. This allows you to add custom templates without modifying the original theme.
Create a new folder in your
wp-content/themes directory named “ACF Demo.”
Inside the folder, create two files:
functions.php and
style.css.
After activating your child theme in the WordPress admin, you’ll have a dedicated space for customizations.
Step 4: Register Custom Fields for the Custom Post Type
Now that you have your Car post type and child theme, it’s time to register custom fields for your car-specific information.
Navigate to ACF > Field Groups and choose Add New.
Name the field group “Vehicle details.”
Under Location Rules, set the group to appear only when the “Post Type” is equal to “Car”.
Add the following fields:
Price: Use a Text field. Click on the Presentation tab and enter “$” in the “Prepend” section.
Mileage: Use a Number field, and click the Presentation tab. Enter miles in the “Append” section to make it clear for editors.
Miles Per Gallon (MPG): Use a Group field, and create sub fields for City MPG and Highway MPG using Text fields.
After configuring the fields and location rules, be sure to save your field group.
Step 5: Output Custom Field Data in the Theme
With your fields ready, the next step is to display this information on your WordPress site. The steps below outline the process for how to do this.
Copy the
single.php file from the original theme and paste it into your child theme folder.
Rename it to
single-car.php to tailor it specifically to “Car” posts.
In
single-car.php, Remove any unnecessary logic and instead reference the custom field values for Price, Mileage, and MPG.
Consider using HTML and CSS in
single-car.php to further customize how this information appears.
For a more in-depth view on the exact modifications made, please make sure to check out the full codebase on GitHub, and experiment with adding and removing your own field types.
Final Thoughts
With these steps, you’ve successfully created a custom post type, added specialized fields, and customized how the content is displayed. ACF provides highly tailored data management with over 30 custom fields and custom post type creation directly in the plugin’s UI.
ACF also lets you register and manage custom taxonomies in WordPress, allowing for more precise and flexible content organization, enhancing user experience, search engine optimization, and content management by providing tailored categorization beyond the default categories and tags. The next video shows to create custom taxonomies with ACF and add them to custom post types.
Creating a Custom Taxonomy with ACF
Overview
Taxonomies in WordPress allow for the classification and organization of structured data. WordPress comes with the “Posts” post type, which already has two default taxonomies: Categories and Tags.
Categories allow for hierarchical organization with parent-child relationships.
Tags are non-hierarchical and do not have parent-child relationships.
But what if you need a custom taxonomy unique to your data structure? In this video, we show how to use ACF to register and associate custom taxonomies with a custom post type. Following this tutorial, you’ll extend the “Car” post type we registered in Creating a Custom Post Type with ACF and assign two new taxonomies: “Manufacturer” and “Make.” You’ll also see how to create manufacturers and output all the information in our Twenty Nineteen child theme.
Step 1: Registering Custom Taxonomies
The step-by-step instructions below illustrate how to create two custom taxonomies and then use them in the “Car” custom post type we created in our previous video.
First, we’ll use ACF to create a custom taxonomy for “Manufacturers.” In the WordPress admin, navigate to ACF > Taxonomies and click Add New.
Start by creating the “Manufacturers” taxonomy. Enter the following into the required fields:
Plural Label: Manufacturers
Singular Label: Manufacturer
Taxonomy Key: manufacturer
Post Types: Car
You can enter multiple “Post Types” if you’d like the custom taxonomy to be available for more than one.
Check the Hierarchical toggle to ensure the taxonomy allows for nested parent-child relationships. This will allow content editors to enter the manufacturer with the specific vehicle brand nested within it, such as “Kia – Seltos” or “Ford – Focus”.
Toggling on “Advanced Configuration” will show many more options you can use for your custom taxonomy. These options are covered in our documentation on Registering a Custom Taxonomy.
Click Save Changes to save your custom taxonomy.
The next step is create the “Make” taxonomy. Repeat the process outlined above, but use the following information for our required fields:
Plural Label: Makes
Singular Label: Make
Taxonomy Key: make
Post Type: Car
We want our editors to assign freeform tags for this taxonomy, so we won’t enable the “Hierarchical” toggle.
Click Save Changes to save the “Makes” custom taxonomy.
Step 2: Assigning Custom Taxonomies to Posts
Now that you’ve registered your two new custom taxonomies and assigned them to the post type, when you edit a “Car” post, you should see the additional options for your taxonomies in the sidebar. This is where you’ll assign each car’s Manufacturer and Make.
Next, we’ll discover how to display these taxonomies in our child theme.
Step 3: Displaying Custom Taxonomies
With custom taxonomies registered and assigned to the post type, the next step is to create custom template logic to display this new information in the child theme.
The ACF demo child theme demonstrates the necessary template files and logic for displaying your custom post type. The demo theme will automatically register the “Car” post type, the vehicle details fields group, and the “Manufacturer” and “Make” taxonomies. There is even a full XML import that allows you to replicate a fully functioning car dealership site.
Conclusion
If you’ve followed along with the tutorials, you should have a custom post type registered with custom fields and taxonomies. We hope you’re starting to see the flexibility and simplicity of using ACF to create custom data structures. Be sure to check out all of our videos and we encourage you to experiment with the final demo code.
Creating a Field Group
ACF uses field groups to attach fields to posts. Each field group contains a title, fields, location rules, and visual settings. To create a field group, hover over ACF in your WordPress admin and select Field Group from the menu. You will see a welcome screen like this:
Creating a New Field Group
Click the Add Field Group or Add New buttons to create your first field group. Next, give the field group a relevant and descriptive title, such as “Home Page” or “Event.” This title is shown in the metabox handle on the edit screen. The “Save Changes” button will not activate until you have given the field group a title.
Clicking the Add Field button on the top bar will create a new field and add it to the bottom of the list. You can reorder your fields at any time by dragging the order number as a handle.
Fields
Field groups start with a single field. This defaults to a Text field on creation. Click the menu under “Field Type” to search or scroll through the available fields.
Click on Browse Fields for an alternative field selection method. This opens a modal with fields sorted into tabs. Clicking on any field in the modal will bring up a short description, graphical representation, and links to documentation.
All fields must have a “Field Label” and “Field Name.”
Field Label: Visible when entering content but is not used by the API. Use capitals and spaces for human-friendly field text.
Field Name: This is autogenerated from the field label. Used in the API and templates to retrieve content and data. This should be lower case, and have no spaces or special characters.
Other settings change based on the type of field. These are usually optional, such as “Default Value.”
Hovering over any part of the field will reveal action buttons similar to any other WordPress table list screen. These actions allow you to edit (open/close), duplicate, or delete the field.
Settings
The settings panel is located beneath the field group editor. Tabs allow you to set location rules, alter how the field will look to content editors, and adjust group settings.
Location
The location box allows you to create rules that determine when and where these fields are added to the edit screen or post object. The example location rules shown below will make this field group appear only on pages using the “Sidebar Template”. Location rules can be grouped together to create any combination of
and and
or statements.
Presentation
The Presentation tab provides options to help customize the edit screen where this field group appears.
You can also set the “Order No.” on this tab, indicating the order in which field groups and their options should be loaded. Field groups are loaded and displayed by “Order No.”, with 0 as the first. If you have multiple field groups appearing on a page, only the options from the first field group will be used.
Group Settings
You can deactivate your field group on this tab by means of the “Active” toggle. This defaults to on, with all field groups active on your site once they’re created. Another toggle allows you to make the field group visible in the REST API. This defaults to off.
The “Description” field allows you to enter a description that will be displayed in the field group list. Finally, the “Display Title” setting allows you to display a different field group title for content editors while retaining the original title in the ACF admin screens.
Creating a new field type
The Advanced Custom Fields plugin is packed with loads of useful field types such as text, image and WYSIWYG. However, when working on a project, it may be necessary to create a new type of field to save & load unique data.
This guide will demonstrate how to create a new field type for the ACF plugin.
Download
To make life easier, we put together a comprehensive template for creating an ACF field type, complete with an NPM script that get you up and running even faster.
[
ACF Example Field Type template on Github
Please download or clone the ACF Example Field Type repository. Alternatively, you can click the green “Use this template” button to create a new repository based on this template.
https://github.com/AdvancedCustomFields/acf-example-field-type](https://github.com/AdvancedCustomFields/acf-example-field-type)
Once you’ve downloaded the template, follow the steps in the README to get started on your custom field type.
Customization
All logic for your field’s appearance and functionality is defined in the
acf-FIELD-NAME/class-PREFIX-acf-field-FIELD-NAME.php file. This class extends the
acf_field class, which is packed full of powerful functions which allow you to customize how data is saved and displayed! Each function is documented with internal comments, so it is best to open up the file and read it over top to bottom.
Here is a quick overview of the functions:
Name
Description
__construct
Initialize function which sets the field’s data such as name, label, category and defaults
render_field_settings
Create extra settings for your field. These are visible when editing a field
render_field
Create the HTML interface for your field
input_admin_enqueue_scripts
Enqueue CSS + JavaScript to assist your render_field() function
input_admin_head
Add inline CSS and JavaScript to assist your render_field() function
input_form_data
Add hidden inline HTML
input_admin_footer
Add inline CSS and JavaScript to assist your render_field() function
load_value
This filter is applied to the $value after it is loaded from the db
update_value
This filter is applied to the $value before it is saved in the db
format_value
This filter is applied to the $value before being returned to template API
validate_value
This filter is used to perform validation on the value prior to saving
delete_value
This action is fired after a value has been deleted from the db
The above are only some of the functions available in the acf_field class. Please read over the extended comments found above each function to learn more.
HTML Escaping
Some field types may output potentially unsafe HTML directly, such as iframes or script tags.
Starting from ACF 6.2.5, where these would automatically be removed when using the ACF shortcode or
the_field(), ACF supports field types escaping their own HTML when requested. This is done by a second parameter being passed into the
format_value method, if this value is true, we require a HTML safe version of the output.
In this instance, your field type should ensure there is no way for malicious HTML to be rendered on the front-end by a malicious user modifying the raw value in the database. For example, the core WYSIWYG field handles this by running
acf_esc_html on the value before running
the_content filter to handle any embeds in the field.
Once your field type is ready to handle its own HTML, you can mark the field as compatible by adding
’escaping_html’ => true to the new
supports class property:
$this->supports = array(
'escaping_html' => true,
);
Creating a WP archive with custom field filter
This video tutorial will cover the basics of creating a WP archive that displays posts filtered by a checkbox custom field. Please watch the video first, and use the code below to kick start your project!
Usage
This snippet of code is placed within the functions.php file and modifies the WP_Query args based on the available
$_GET params.
functions.php
// array of filters (field key => field name)
$GLOBALS['my_query_filters'] = array(
'field_1' => 'city',
'field_2' => 'bedrooms'
);
// action
add_action('pre_get_posts', 'my_pre_get_posts', 10, 1);
function my_pre_get_posts( $query ) {
// bail early if is in admin
if( is_admin() ) return;
// bail early if not main query
// - allows custom code / plugins to continue working
if( !$query->is_main_query() ) return;
// get meta query
$meta_query = $query->get('meta_query');
// loop over filters
foreach( $GLOBALS['my_query_filters'] as $key => $name ) {
// continue if not found in url
if( empty($_GET[ $name ]) ) {
continue;
}
// get the value for this filter
// eg: http://www.website.com/events?city=melbourne,sydney
$value = explode(',', $_GET[ $name ]);
// append meta query
$meta_query[] = array(
'key' => $name,
'value' => $value,
'compare' => 'IN',
);
}
// update meta query
$query->set('meta_query', $meta_query);
}
This snippet of code is used within a template file that is shown on the archive page for your post type.
archive-property.php
$name ):
// get the field's settings without attempting to load a value
$field = get_field_object($key, false, false);
// set value if available
if( isset($_GET[ $name ]) ) {
$field['value'] = explode(',', $_GET[ $name ]);
}
// create filter
?>
Custom location rules
Each field group contains a set of location rules. These rules are used to decide where to show the field group throughout the WP admin. It is possible to create your own location rules, or even modify existing rules using the following filters.
Change Log
5.8.0 – Added
$field_group parameter to
'acf/location/match_rule' filter.
5.3.5 – Added
'acf/location/screen' filter.
Adding a new rule
Adding a custom location rule consists of 4 simple steps. 3 of these are to define the rule settings and the last is to use these settings to match the rule to the edit screen.
1. Adding a custom rule type
When editing a field group, the ‘types’ drop down is the first dropdown in the location rule row.
Note that the list is broken into groups. This is important to keep in mind when editing the choices for this dropdown. Use the ‘acf/location/rule_types’ filter to customize this list. Here is an example of adding “user” to the ‘Basic’ group in the dropdown choices:
add_filter('acf/location/rule_types', 'acf_location_rules_types');
function acf_location_rules_types( $choices ) {
$choices['Basic']['user'] = 'User';
return $choices;
}
Tip: use a print_r or var_dump to get a better idea of the $choices array.
2. Add custom rule operators
This step is optional and not required for your custom location rule to work. When editing a field group, the ‘operators’ drop down is the second dropdown in the location rule row.
By default, this list has ‘==’ and ‘!=’ operators. This can also be customized with the ‘acf/location/rule_operators’ filter. To add in ‘<‘ and ‘>’ operators, you could use something like this:
add_filter('acf/location/rule_operators', 'acf_location_rules_operators');
function acf_location_rules_operators( $choices ) {
$choices['<'] = 'is less than';
$choices['>'] = 'is greater than';
return $choices;
}
3. Add custom rule values
When editing a field group, the ‘values’ drop down is the third dropdown in the location rule row. This list is dynamically updated based on the ‘type’.
This list must have a choice to select from. To populate this list, use the ‘acf/location/rule_values/$type’ filter. Please note that the variable $type in the filter name should match the ‘type’ value.
This code will populate the list with all the available users. The list will save the user_id but display the user display_name:
add_filter('acf/location/rule_values/user', 'acf_location_rule_values_user');
function acf_location_rule_values_user( $choices ) {
$users = get_users();
if( $users ) {
foreach( $users as $user ) {
$choices[ $user->data->ID ] = $user->data->display_name;
}
}
return $choices;
}
4. Matching the rule
After following the above steps, you should now have a custom location rule applied to your field group. The last step is to create a function for matching this rule to an edit screen.
When viewing an edit screen (page / post / user / taxonomy / attachment / etc), ACF will find all available field groups and run matching functions on the field group’s location rules. These matching functions will return either true or false and determine if a field group gets shown or not.
To create a location rule_match function for your custom location rule, use the ‘acf/location/rule_match/$type’ filter. Please note that the variable $type in the filter name should match the ‘type’ value.
This filter accepts 3 parameters:
$match – the true / false variable which must be returned
$rule – the current rule that you are matching against. This is an array with keys for ‘param’, ‘operator’, ‘value’.
$options – an array of data about the current edit screen (post_id, page_template, post_type, etc). This array will also include any data posted in an ajax call (ajax calls are made on a post / page when you change the category, page_template, etc)
The following code will create a rule_match for ‘user’ where if the current_user is equal to the user selected (in the field group’s rule) the field group will be shown (unless another rule did not match)
add_filter('acf/location/rule_match/user', 'acf_location_rule_match_user', 10, 4);
function acf_location_rule_match_user( $match, $rule, $options, $field_group )
{
$current_user = wp_get_current_user();
$selected_user = (int) $rule['value'];
if($rule['operator'] == "==")
{
$match = ( $current_user->ID == $selected_user );
}
elseif($rule['operator'] == "!=")
{
$match = ( $current_user->ID != $selected_user );
}
return $match;
}
Modifying the rule_match options
The above
rule_match filter contains a parameter called
$options. This parameter contains an array of information about the current edit screen such as post_id, post_parent, etc.
It is possible to modify this array by hooking into the filter
acf/location/screen and either edit or append screen data.
add_filter('acf/location/screen', 'acf_location_screen_options', 10, 1);
function acf_location_screen_options( $options ) {
$options['foo'] = 'bar';
return $options;
}
Wrapping up
The above filters give you the ability to create custom location rules for you custom field groups. Honestly, the possibilities are endless in terms of what you can compare.
These filters could also be used in a plugin. Such as creating location rules for the post_template plugin!
Custom location rules
Introduction
Location rules are used to determine which field groups appear on which admin screen. They are defined when editing a Field Group and consist of a location type, a comparison operator, and a value.
One example of a location rule would be "Post Type == Post".
The Field Group Locations metabox
A diverse set of location types are included within the Advanced Custom Fields plugin to satisfy the needs of most websites. In addition to these, extra location types may be defined to provide bespoke logic for the location of a Field Group.
This guide will walk through the process of creating and registering a custom location type.
Requirements
The
ACF_Location class mentioned in this guide requires version 5.9.0 or above. If not already, please consider updating to take advantage of this great feature!
For those using a previous version, please checkout this guide instead.
Getting Started
To create a custom location type, simply extend the
ACF_Location class and some of its methods. Then register it with the
acf_register_location_type() function.
The following is a simplified example demonstrating a custom location type that when selected would randomly show the Field Group 50% of the time.
class My_Location extends ACF_Location {
function initialize() {
$this->name = '50_50';
$this->label = __( 'Fifty Fifty' );
}
function match() {
return rand( 0, 1 );
}
}
acf_register_location_type( 'My_Location' );
ACF_Location
The
ACF_Location class contains multiple properties and methods, not all of which need to be customized. Before jumping into the working example, please familiarize yourself with the available properties and methods listed below.
Properties
name
(String) A unique name that identifies the location type. For example ‘post_author’.
A location type name may only contain lowercase alphanumeric characters and underscores.
$this->name = 'post_author';
label
(String) The display label for your location type shown when editing a Field Group. For example ‘Post Author’.
$this->label = __('Post Author');
category
(String) (Optional) The group where this location type appears in the location type dropdown.
Accepts "post", "page", "user", "forms" or a custom label. Defaults to "post".
$this->category = 'post';
public
(Bool) (Optional) Whether or not the location rule is publicly selectable. Defaults to true.
$this->public = true;
object_type
(String) (Optional) The object type related to this location.
Accepts an object type discoverable by
acf_get_object_type() such as "post", "user", "block", etc. Defining this property allows ACF to display an icon in the Field Groups admin table column. Defaults to an empty string that represents "Various".
$this->object_type = 'post';
Methods
initialize
Called during registration to initialize properties.
public function initialize() {
$this->name = 'post_author';
// Define all other properties here.
}
match
Compares the provided location rule against the current screen args and returns true for a positive match.
Returning true will allow the Field Group to appear on the current screen. Returning false will prevent the Field Group from appearing on the current screen.
public function match( $rule, $screen, $field_group ) {
return false;
}
get_operators
(Optional) Returns an array of operators to choose from when editing a rule.
If omitted, the default "is equal to" and "is not equal to" operators will be used.
public function get_operators( $rule ) {
return array(
'==' => __( "is equal to" ),
'!=' => __( "is not equal to" )
);
}
get_values
(Optional) Returns an array of possible values to choose from when editing a rule.
public function get_values( $rule ) {
return array(
'foo' => 'Foo',
'bar' => 'Bar'
);
}
get_object_subtype
(Optional) Similar the the object_type property, this method allows ACF to display a more accurate icon in the Field Groups admin table column.
Returns one or more subtypes that are related to this location.
Valid object subtypes include post types and taxonomies. Defaults to an empty string.
public function get_object_subtype( $rule ) {
return 'category';
}
Example
Let’s put some of these properties and methods to good use and create a custom location type called "Post Author". This location type will allow a Field Group to appear when editing a Post based on the Post’s Author attribute.
1. Setup
Our first task is to define a new
ACF_Location class, using the
initialize() method to setup the location type’s properties. In this example, we will work within the theme file includes/class-my-acf-location-post-author.php.
includes/class-my-acf-location-post-author.php
name = 'post_author';
$this->label = __( "Post Author", 'acf' );
$this->category = 'post';
$this->object_type = 'post';
}
}
Next, let’s include and register this location type from the
functions.php file.
functions.php
add_action('acf/init', 'my_acf_init_location_types');
function my_acf_init_location_types() {
// Check function exists, then include and register the custom location type class.
if( function_exists('acf_register_location_type') ) {
include_once( 'includes/class-my-acf-location-post-author.php' );
acf_register_location_type( 'My_ACF_Location_Post_Author' );
}
}
Presto 🎉. We can edit a Field Group and select the new location type.
Selecting the “Post Author” location rule type
2. Customizing drop-downs
With our custom location type registered, we can now turn our focus to customizing the operator and value drop-downs – the two settings that appear next to the selected location type.
In this example, we will leave the operator drop-down as-is which will show the default "is equal to" (==) and "is not equal to" (!=) choices. We will, however, customize the value drop-down to display a list of all possible users.
WordPress’ get_users() function makes this task quite simple. The following snippet will populate an array of choices using the user’s ID as the option value, and the user’s Display Name as the option label.
includes/class-my-acf-location-post-author.php
public function get_values( $rule ) {
$choices = array();
// Load all users, loop over them and append to chcoices.
$users = get_users();
if( $users ) {
foreach( $users as $user ) {
$choices[ $user->ID ] = $user->display_name;
}
}
return $choices;
}
Our custom location type is starting to take shape! It is now possible to create a Location Rule that reads "Post Author == Elliot" 🙌.
Selecting the “Post Author” location rule value
Lastly, we need to define the logic that compares a rule (such as "Post Author == Elliot") to the current screen.
3. Calculating a match
When viewing a WordPress edit screen, Advanced Custom Fields will calculate which Field Groups appear based on their location rules. Each location rule’s type is consulted to determine whether or not the rule matches the current screen args.
The logic for this "matching" is defined in the
match() method. This method accepts 3 parameters including the rule conditions, the current screen arguments and also the Field Group who’s visibility is being calculated. All that is required from this method is to return a boolean value reflecting the matching result.
In this example, we will compare the selected rule value (a user ID) to the Post’s author attribute. We also need to remember that this location type is only relevant when editing a Post, and not a User, Term, Widget, etc.
includes/class-my-acf-location-post-author.php
public function match( $rule, $screen, $field_group ) {
// Check screen args for "post_id" which will exist when editing a post.
// Return false for all other edit screens.
if( isset($screen['post_id']) ) {
$post_id = $screen['post_id'];
} else {
return false;
}
// Load the post object for this edit screen.
$post = get_post( $post_id );
if( !$post ) {
return false;
}
// Compare the Post's author attribute to rule value.
$result = ( $post->post_author == $rule['value'] );
// Return result taking into account the operator type.
if( $rule['operator'] == '!=' ) {
return !$result;
}
return $result;
}
Congratulations 🎉 The Post Author location type is now complete! A Field Group using this location type will display only when editing a Post where the Post’s Author is "Eliot".
The “Post Author” location type matching correctly for the rule “Post Author == Elliot”
Complete code
For reference, here is the complete code written for the custom "Post Author" location type.
includes/class-my-acf-location-post-author.php
name = 'post_author';
$this->label = __( "Post Author", 'acf' );
$this->category = 'post';
$this->object_type = 'post';
}
public function get_values( $rule ) {
$choices = array();
// Load all users, loop over them and append to chcoices.
$users = get_users();
if( $users ) {
foreach( $users as $user ) {
$choices[ $user->ID ] = $user->display_name;
}
}
return $choices;
}
public function match( $rule, $screen, $field_group ) {
// Check screen args for "post_id" which will exist when editing a post.
// Return false for all other edit screens.
if( isset($screen['post_id']) ) {
$post_id = $screen['post_id'];
} else {
return false;
}
// Load the post object for this edit screen.
$post = get_post( $post_id );
if( !$post ) {
return false;
}
// Compare the Post's author attribute to rule value.
$result = ( $post->post_author == $rule['value'] );
// Return result taking into account the operator type.
if( $rule['operator'] == '!=' ) {
return !$result;
}
return $result;
}
}
functions.php
add_action('acf/init', 'my_acf_init_location_types');
function my_acf_init_location_types() {
// Check function exists, then include and register the custom location type class.
if( function_exists('acf_register_location_type') ) {
include_once( 'includes/class-my-acf-location-post-author.php' );
acf_register_location_type( 'My_ACF_Location_Post_Author' );
}
}
Wrapping Up
The
ACF_Location class makes light work of creating custom location rules. In only a few lines of code we have been able to:
Register a new location type that can be selected within a Field Group’s location rules.
Customize the values displayed in the location rule value dropdown.
Calculate whether or not a rule matches the current edit screen.
Customize the WYSIWYG toolbars
Description
The WYSIWYG field contains an option to define the toolbar (buttons) which are rendered onto the tinyMCE object.
By default, you can select ‘Full’ or ‘Basic’, however, it is possible to extend these toolbars to create your own, edit existing and even remove the existing choices.
Requirements
ACF version 3.5.8 or above
The Filter
The filter to modify the toolbars is: acf/fields/wysiwyg/toolbars
The WYSIWYG field uses an array (which can be modified as shown below) to hold a list of toolbars. Each toolbar comprises of a name and up to 4 rows of buttons. With this filter, you can add, edit and remove toolbars. This filter allows you to modify this very array.
Once a new toolbar is added to the list, it will then appear in the WYSIWYG field’s options when editing the field group. Once selected, the field will use the available rows to output the desired buttons
Usage
';
print_r($toolbars);
echo '< /pre >';
die;
*/
// Add a new toolbar called "Very Simple"
// - this toolbar has only 1 row of buttons
$toolbars['Very Simple' ] = array();
$toolbars['Very Simple' ][1] = array('bold' , 'italic' , 'underline' );
// Edit the "Full" toolbar and remove 'code'
// - delet from array code from http://stackoverflow.com/questions/7225070/php-array-delete-by-value-not-key
if( ($key = array_search('code' , $toolbars['Full' ][2])) !== false )
{
unset( $toolbars['Full' ][2][$key] );
}
// remove the 'Basic' toolbar completely
unset( $toolbars['Basic' ] );
// return $toolbars - IMPORTANT!
return $toolbars;
}
?>
Use this filter in your functions.php file
Customizing the Inline Editing Experience
Customizing the Inline Editing Experience
Inline Editing is a new feature of ACF Blocks that allows authors to edit block data directly within the block preview area, offering a more native Gutenberg-like experience without extra code.
Text and Toolbar editing
The helper functions for inline text and toolbar editing have various arguments you can use to customize the experience.
Check out the documentation for each function:
acf_inline_text_editing_attrs()
acf_inline_toolbar_editing_attrs()
Custom Icons
When adding custom icons using SVGs, we recommend taking from the native WordPress block editor iconset.
Add ACF Fields To Primary Block Toolbar
You can also add ACF fields to the Primary Block Toolbar, which allows you to bring ACF fields to the preview area for things which aren’t visual or clickable. This might be something like a background color or image.
To add ACF fields to the primary block toolbar, use the
acf/blocks/top_toolbar_fields filter. For example:
function my_block_top_toolbar_fields($block_top_toolbar_field_names, $block) {
// If the block in question is our block.
if ( 'acf/my-acf-block' === $block['name'] ) {
// Make some acf fields show in the primary block toolbar.
return array( 'my_background_image_field', 'my_background_color_field');
}
// If the block in question is not our block, just pass the variable as is.
return $block_top_toolbar_field_names;
}
add_filter( 'acf/blocks/top_toolbar_fields', 'my_block_top_toolbar_fields', 10, 2 );
Custom Icons
Just like with the other helper functions, you can customize the icons used for each ACF field placed into the main block toolbar as well, by passing an array instead of just the field name as a string. For example:
function my_block_top_toolbar_fields($block_top_toolbar_field_names, $block) {
// If the block in question is our block.
if ( 'acf/my-acf-block' === $block['name'] ) {
// Make some ACF fields show in the primary block toolbar.
return array(
'my_background_image_field',
array(
'field_name' => 'my_background_color_field',
'field_icon' => 'your svg html text here',
'field_label' => 'My custom field label'
)
);
}
// If the block in question is not our block, just pass the variable as is.
return $block_top_toolbar_field_names;
}
add_filter( 'acf/blocks/top_toolbar_fields', 'my_block_top_toolbar_fields', 10, 2 );
Date Picker
Description
The Date Picker field provides a jQuery date selection popup.
Screenshots
Creating a Date Picker Field in an ACF field group.
The Date Picker field from the point of view of a content editor.
Clicking on the field opens a calendar, allowing the content editor to easily choose the correct date.
Settings
Display Format
The date format that is displayed when selecting a date.
Return Format
The date format that is returned when loading the value. Please note that the value is always saved as
Ymd (YYYYMMDD) in the database.
Week Starts On
Specifies the day to start the week on. Defaults to Monday.
Required
Found on the Validation tab, this prevents the field from accepting empty values. Defaults to off.
Instructions
Shows instructions when submitting data.
Template usage
The Date Picker field returns a date string using the Return Format setting.
Display value
This example demonstrates how to display a date value.
Event Date:
Modify value
This example demonstrates how to convert a string date value into a DateTime object.
Event start date: format( 'j M Y' ); ?>
modify( '+1 day' );
?>
Event end date: format( 'j M Y' ); ?>
Query posts sorted in order
This example demonstrates how you can query posts sorted in order of a custom field value.
'event',
'meta_key' => 'date',
'orderby' => 'meta_value_num',
'order' => 'ASC',
));
if( $posts ) {
foreach( $posts as $post ) {
// Do something.
}
}
Query posts within date range
This example demonstrates how you can query posts to find events happening today.
'event',
'meta_query' => array(
array(
'key' => 'start_date',
'compare' => '>=',
'value' => $today,
),
array(
'key' => 'end_date',
'compare' => '<=',
'value' => $today,
)
),
));
if( $posts ) {
foreach( $posts as $post ) {
// Do something.
}
}
Notes
Database format
The value selected can be returned and displayed in different formats but will be saved to the database as ‘Ymd’. If you are updating this value manually, you must use the
Ymd format. This format is used throughout the WordPress database tables and will allow for straight-foward database querying.
Date format strings
To customize the Display Format and Return Format settings further, refer to the full list of date format strings within the DateTime::createFromFormat() documentation.
Date formats in JavaScript
Some JavaScript libraries might format PHP date strings differently. For example, the following date function in PHP:
echo date( 'F j, Y @ g:i a' );
Will output something like:
November 19, 2021 @ 1:49 pm
However, if you pass this value to something like the jQuery UI DatePicker Widget, it will see the
@ as a special character to be formatted with the Unix timestamp, which is not ideal.
Use the
acf/settings/php_to_js_date_formats filter to fix this, as it will convert any instance of the
@ symbol to
'@'. This will ensure it’s treated as a string in JavaScript instead of a character to be replaced.
add_filter( 'acf/settings/php_to_js_date_formats', 'support_at_symbol_in_date_format', 10, 1 );
function support_at_symbol_in_date_format( $formats ) {
$formats['@'] = "'@'";
return $formats;
}
Translations
If you require the date to be displayed in a non-English language, WordPress contains a function called date_i18n() which will perform the translation for you.
Event starts:
Query posts sorted in order
This example demonstrates how you can query posts sorted in order of a custom field value.
-1,
'post_type' => 'event',
'order' => 'ASC',
'orderby' => 'meta_value',
'meta_key' => 'start_date',
'meta_type' => 'DATETIME',
));
if( $posts ) {
foreach( $posts as $post ) {
// Do something.
}
}
Query posts within date range
This example demonstrates how you can query posts to find events that are currently happening today.
'event',
'meta_query' => array(
array(
'key' => 'start_date',
'compare' => '<=',
'value' => $date_now,
'type' => 'DATETIME',
),
array(
'key' => 'end_date',
'compare' => '>=',
'value' => $date_now,
'type' => 'DATETIME',
)
),
));
if( $posts ) {
foreach( $posts as $post ) {
// Do something.
}
}
Query upcoming posts
This example demonstrates how to query and loop over upcoming events (in the next 7 days) ordered by a custom date time field value.
-1,
'post_type' => 'event',
'meta_query' => array(
array(
'key' => 'start_date',
'compare' => 'BETWEEN',
'value' => array( $date_now, $date_next_week ),
'type' => 'DATETIME'
)
),
'order' => 'ASC',
'orderby' => 'meta_value',
'meta_key' => 'start_date',
'meta_type' => 'DATETIME'
));
if( $posts ) {
foreach( $posts as $post ) {
// Do something.
}
}
Save as unix timestamp
This example demonstrates how to change the value saved from the standard ‘Y-m-d H:i:s’ string to a unix timestamp number. This may be necessary to maintain compatibility with third party date time picker fields.
';
var_dump( $image );
echo '';
?>
Please note that the above code also makes use of the
pre tag to correctly render the line breaks and display an array or object in a more humanly readable format.
Now that you can see the data that your theme is interacting with, you may be able to spot where the problem lies. Perhaps you expected the value of
$image to be a string containing the url, but upon inspection the value is an array containing lots of data.
JavaScript issues
Much of the ACF plugin uses JS to add interaction to form elements. For example, clicking on an image field ‘Select Image’ button will launch a popup. If an element seems unresponsive, it is most likely that a JS error exists on the page and is preventing the ACF JS from running.
Debugging JS is quite easy. Simply open the console log (via your browser’s inspector tool) and reload the page. With the console log open, look for any errors that may appear on page load or when interacting with the problem element. If an error appears, this is very useful information to include in your support ticket.
You may find that the JS error points to ‘line 1’ of a minified JS file. It is much more helpful to get the error line of an un-minified JS file. To do this, simply add the following code to your
wp-config.php file:
define('SCRIPT_DEBUG', true);
This line of code will notify WP to load in the full versions of each JS script allowing more detailed JS error reporting.
Solving
Now that you can see the data, take a look at the code that is interacting with it. If the solution is not apparent at first, please spend a few minutes to research the issue by searching for the variable type (array, object, etc), the functions you are using and the issue you are experiencing. You may also find the solution over on the FAQ or Support pages.
If no solution can be found from the above, please contact our support team via the help desk on the support page and be sure to include any debugging information you have performed as this will greatly reduce the response time!
delete_field()
Description
Deletes the value of a specific field.
Parameters
delete_field($selector, [$post_id]);
$selector (string) (Required) The field name or field key.
$post_id (mixed) (Optional) The post ID where the value is saved. Defaults to the current post.
Return
(bool) True on successful delete, false on failure.
Examples
Delete via field name
This example shows how to delete the value of a field called ‘test’ on the current post being viewed.
// Delete value.
delete_field('test');
Delete via field key
This example shows how to achieve the same as above using the field’s key instead of its name.
// Delete value.
delete_field('field_123456');
Delete a value from different objects
This example shows a variety of $post_id values to delete a value from a post, user, term and option.
$post_id = false; // current post
$post_id = 1; // post ID = 1
$post_id = "user_2"; // user ID = 2
$post_id = "category_3"; // category term ID = 3
$post_id = "event_4"; // event (custom taxonomy) term ID = 4
$post_id = "option"; // options page
$post_id = "options"; // same as above
delete_field( 'my_field', $post_id );
Delete from multiple posts
This example shows how load all posts that contain a custom field (called ‘color’) and then delete those values from each post. Note that the foreach loop uses a variable called $p instead of $post to avoid any collisions with the global $post object.
// Query posts.
$posts = get_posts(array(
'post_type' => 'post',
'posts_per_page' => -1,
'meta_key' => 'color'
));
// Loop over results and delete.
if( $posts ) {
foreach( $posts as $p ) {
delete_field('color', $p->ID);
}
}
delete_row()
Deletes a row of data from an existing Repeater or Flexible Content field value.
Parameters
delete_row($selector, $row, [$post_id])
$selector (string) (Required) The field name or field key.
$row (int) (Required) The row number to update.
$post_id (mixed) (Optional) The post ID where the value is saved. Defaults to the current post.
Return
(bool) True on successful update, false on failure.
Change Log
Added in version 5.3.2
Examples
Delete via field name
This example shows how to delete a row of data from a field called ‘images’ on the current post being viewed.
// Delete the first row of data.
delete_row('images', 1);
Delete via field key
This example shows how to achieve the same as above using the field’s key instead of its name.
// Delete the first row of data.
delete_row('field_123456', 1);
Notes
Index offset
When targeting a specific row number, please note that row numbers begin from 1 and not 0. This means that the first row has an index of 1, the second row has an index of 2, and so on.
To begin indexes from 0, please use the row_index_offset setting like so.
functions.php
add_filter('acf/settings/row_index_offset', '__return_zero');
Usage inside loops
When you use
delete_row(), it will update the database and reindex the array of repeater or flexible field items. Therefore, you should not use this function inside a
have_rows loop to avoid inconsistent data.
delete_sub_field()
Description
Deletes the value of a specific sub field.
This function can be used inside or outside of a
have_rows() loop. When used inside, the current row will be used to delete the sub field value. When used outside, the rows and parents must be specified to target the correct value place.
Parameters
delete_sub_field($selector, [$post_id]);
$selector (string|array) (Required) The sub field name or key, or an array of ancestors and row numbers.
$post_id (mixed) (Optional) The post ID where the value is saved. Defaults to the current post.
Return
(bool) True on successful deletion, false on failure.
Change Log
Added in version 5.0.0
Examples
Delete a sub field inside of a have_rows() loop
This example shows how to loop through a Repeater field and delete one of its sub field values from each row.
if( have_rows('repeater') ) {
while( have_rows('repeater') ) {
the_row();
delete_sub_field('caption');
}
}
Delete a sub field outside of a have_rows() loop
This example shows how to delete a sub field value outside of a
have_rows() loop. Here, the
$selector parameter is provided an array containing a mixture of field names and row numbers. This array should read from left to right, the parents to children relationship separated by the row number.
Please see notes regarding index offset.
// Delete "caption" within the first row of "repeater".
delete_sub_field( array('repeater', 1, 'caption') );
Delete a nested sub field
The
delete_sub_field() function can also be used to target a nested sub field both inside and outside of a
have_rows() loop. This example shows how to delete a nested sub field function using both methods.
// Loop over parent rows.
if( have_rows('repeater') ) {
while( have_rows('repeater') ) {
the_row();
// Loop over child rows.
if( have_rows('sub_repeater') ) {
while( have_rows('sub_repeater') ) {
the_row();
// Delete nested sub field value.
delete_sub_field('sub_sub_field');
}
}
}
}
// target a nested sub field directly.
delete_sub_field( array('repeater', 1, 'sub_repeater', 2, 'sub_sub_field') );
Notes
Index offset
When targeting a sub field using a specific row number, please note that row numbers begin from 1 and not 0. This means that the first row has an index of 1, the second row has an index of 2, and so on.
To begin indexes from 0, please use the row_index_offset setting like so.
functions.php
add_filter('acf/settings/row_index_offset', '__return_zero');
delete_sub_row()
Deletes a row of data from an existing Repeater or Flexible Content sub field value.
This function can be used inside or outside of a
have_rows() loop. When used inside, the current row will be used to update the sub field value. When used outside, the rows and parents must be specified to target the correct value place.
Please note this function is used to modify a sub field value. To modify a parent field value, please use the delete_row() function.
Parameters
delete_sub_row($selector, $row, [$post_id])
$selector (string|array) (Required) The sub field name or key, or an array of ancestors and row numbers.
$row (int) (Required) The row number to update.
$post_id (mixed) (Optional) The post ID where the value is saved. Defaults to the current post.
Return
(bool) True on successful update, false on failure.
Change Log
Added in version 5.4.7
Delete a sub row inside of a have_rows() loop
This example shows how to delete a row of data from an existing nested repeater field called ‘images’. This nested repeater field contains 3 sub fields (‘image’, ‘alt’, ‘link’).
// Loop over all staff members.
if( have_rows('staff_members') ) {
while( have_rows('staff_members') ) {
the_row();
// Delete this staff member's first image.
delete_sub_row('images', 1);
}
}
Delete a sub row outside of a have_rows() loop
This example shows how to delete a row of data outside of a
have_rows() loop. Here, the
$selector parameter is provided an array containing a mixture of field names and row numbers. This array should read from left to right, the parents to children relationship separated by the row number.
Please see notes regarding index offset.
// Delete the first staff member's first image.
delete_sub_row( array('staff_members', 1, 'images'), 1 );
// Update the first staff member's second image.
delete_sub_row( array('staff_members', 1, 'images'), 2 );
Notes
Index offset
When targeting a sub field using a specific row number, please note that row numbers begin from 1 and not 0. This means that the first row has an index of 1, the second row has an index of 2, and so on.
To begin indexes from 0, please use the row_index_offset setting like so.
functions.php
add_filter('acf/settings/row_index_offset', '__return_zero');
Disable Field Validation in ACF Blocks
Field validation is enabled by default for all ACF Blocks. Existing posts with ACF Blocks are validated the next time the post is edited. If any fields fail validation, the post cannot be saved until those issues are resolved. In some cases, you may wish to disable field validation for a particular ACF Block. This doc shows how to disable field validation by adding the
validate: false attribute to the ACF key section of the
block.json file.
Validation for fields contained in ACF Blocks was introduced in ACF PRO 6.3. The fields in ACF Blocks can have any of the same validation rules applied to them as any custom field, such as being required, minimum and maximum values, and so on. This works the same way as validation for field groups assigned to posts, pages, or other data objects.
Usage
The validation attribute for ACF Blocks defaults to
true, so you will have to make adjustments to the
block.json file to prevent this behavior for an individual block. The
validate: false attribute is added to the ACF key section of your
block.json file:
{
"name": "acf/testimonial",
"title": "Testimonial",
"description": "A custom testimonial block that uses ACF fields.",
"style": [ "file:./testimonial.css" ],
"category": "formatting",
"icon": "admin-comments",
"keywords": ["testimonial", "quote"],
"acf": {
"mode": "preview",
"renderTemplate": "testimonial.php",
"validate": false
},
"supports": {
"anchor": true
}
}
Displaying Values in Your Theme
The Advanced Custom Field’s API makes it very easy to display field data in your theme. There are many functions available and all are well documented on the resources page.
The Basics
Once you have created a field group and input some data, you can now load and display the data in your theme.
All values are saved as native post_meta (when saved to a post) and although you can use the native WP function
get_post_meta(), it is better practice to use the relevant ACF function such as
get_field(). Why? Because ACF will format the value depending on the field type and make development quicker and easier!
To retrieve a field value as a variable, use the get_field() function. This is the most versatile function which will always return a value for any type of field.
To display a field, use the the_field() in a similar fashion.
Here’s a basic usage example, and please be sure to view the code example page for more.
Does ACF have a Shortcode?
Yes, you can use it in the same way as the the_field() function. It looks something like this:
[acf field="{$field_name}"]
You can also specify the $post_id to fetch the value from.
[acf field="{$field_name}" post_id="{$post_id}"]
Dynamically Populate a Select Field’s Choices
Need to dynamically populate a field’s choices? This tutorial shows how to take a value saved to an options page and use it to override the
choices array for a Select field.
The ‘choices’ array attribute is also used with the Radio Button and Checkbox fields. Most of this tutorial applies to any of these fields, but the AJAX example can only be used with the Select field.
Requirements
This tutorial requires the use of the acf/load_field filter, in conjunction with the
name modifier to apply the filter to all fields of a specific
name. The
name attribute is how the field is stored and referred to in the WordPress database.
Populating Choices From a Text Area Field
In this example, we will load a Text Area field called
my_select_values from an options page, and use the text on each line as an option for the Select field’s choices. The Select field’s
name in this example is
color.
functions.php
function acf_load_color_field_choices( $field ) {
// Reset choices
$field['choices'] = array();
// Get the Text Area values from the options page without any formatting
$choices = get_field('my_select_values', 'option', false);
// Explode the value so each line is a new element in the array
$choices = explode("\n", $choices);
// Remove unwanted white space
$choices = array_map('trim', $choices);
// Loop through the array and add to field 'choices'
if( is_array($choices) ) {
foreach( $choices as $choice ) {
$field['choices'][ $choice ] = $choice;
}
}
// Return the field
return $field;
}
add_filter('acf/load_field/name=color', 'acf_load_color_field_choices');
Populating Choices From a Repeater Field
In this example, we will load a Repeater field called
my_select_values from the options page, and use the subfields
value and
label as the options for the Select field’s choices.
functions.php
function acf_load_color_field_choices( $field ) {
// Reset choices
$field['choices'] = array();
// Check to see if Repeater has rows of data to loop over
if( have_rows('my_select_values', 'option') ) {
// Execute repeatedly as long as the below statement is true
while( have_rows('my_select_values', 'option') ) {
// Return an array with all values after the loop is complete
the_row();
// Variables
$value = get_sub_field('value');
$label = get_sub_field('label');
// Append to choices
$field['choices'][ $value ] = $label;
}
}
// Return the field
return $field;
}
add_filter('acf/load_field/name=color', 'acf_load_color_field_choices');
Populating a Select Field With AJAX
Unlike the Radio Button and Checkbox fields, the Select field can be populated via AJAX. This can help speed up page load times when using the
acf/load_field filter to populate the Select field’s choices. The Select field must have “Stylized UI” and “Use AJAX to lazy load choices” turned on for this filter to work. The “Use AJAX to lazy load choices” option is hidden until “Stylized UI” is turned on in the Select field’s settings.
function filter_field( array $field ) : array {
if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
$field['choices'] = time_consuming_call_to_get_choices();
}
return $field;
}
add_filter( "acf/load_field/key=$key", 'filter_field', 10, 1 );
Email
Description
The Email field creates an email input, used for storing email address values.
Screenshots
Creating an Email field within an ACF field group.
The Presentation tab allows you to control how your Email field will appear.
How the email field appears to content editors. You can see how settings in the Presentation layer control what is displayed to editors.
Settings
Default Value
The default value shown when creating a new post.
Required
Found on the Validation tab, this requires a valid email be provided as the input and prevents the field from accepting empty values. Defaults to off.
Instructions
Shows instructions when submitting data.
Placeholder Text
Appears within input when no value exists.
Prepend
Adds a visual text element before the input.
Append
Adds a visual text element after the input.
Character Limit
Limits the number of characters allowed.
Template usage
Display value
This example demonstrates how to display an Email field named “contact_email” within a
tag.
However, we don’t recommend outputting any ACF value without any sort of protection or escaping. We’ll cover how to protect the address from spam bots in the section below.
Load value
This example demonstrates how to load the value of an Email field named “contact_email” and use it in a
mailto: contact link, where the email is protected from spam bots using the WordPress
antispambot() function.
email us at
Enabling Inline Editing
Enabling Inline Editing
Inline Editing is a new feature of ACF Blocks that allows authors to edit block data directly within the block preview area, offering a more native Gutenberg-like experience without extra code.
In order to use the Inline Editing feature, blocks must be running version 3 of ACF Blocks.
Learn how to upgrade to v3.
Automatic Inline Editing
The simplest way to experience inline editing in your ACF block is to set
autoInlineEditing set to
true in your
block.json file. This requires no additional coding to get inline editing working.
Note that
autoInlineEditing is designed for simple blocks without conditional logic. If your block uses any conditional logic in the PHP code, we recommend keeping
autoInlineEditing off, and using the inline editing helper functions instead (See “Manually Controlled Inline Editing” in the section below).
Block.json Example
{
"name": "acf/testimonial",
"title": "Testimonial",
"description": "A custom testimonial block that uses ACF fields which are inline editable.",
"style": [ "file:./testimonial.css" ],
"category": "formatting",
"icon": "admin-comments",
"keywords": ["testimonial", "quote"],
"acf": {
"blockVersion": 3,
"renderTemplate": "testimonial.php",
"autoInlineEditing": true
},
"supports": {
"align": false
}
}
With that enabled, ACF will automatically apply inline editing functionality to any HTML elements where an ACF field’s value is the only thing within it.
For example, if you have a paragraph tag with only an ACF field value in it, it will be editable automatically.
The same goes for HTML attributes. For example, if an img tag’s
src attribute has a value that comes directly from an ACF field, it will automatically be editable.
Limitations
The Repeater and Flexible Content fields are the only ones which will not be automatically editable, but they can be manually set to be editable, just like any HTML element. Just note that this supports editing the top-level repeater field as a whole, not the individual sub-fields.
It’s worth noting that if you use a field type that returns an array (like the Image field type does by default), autoInlineEditing won’t make that field editable inline.
For example, if using an image field, you’ll either want to make the field’s return format be “url”, or use one of the helper functions to make the field editable (see “Manually Controlled Editing” below).
Manually Controlled Inline Editing
There are 2 helper functions which can be used in your block render template to make any HTML element editable inline.
Text Editable
The
acf_inline_text_editing_attrs() helper function can be used to make it so that you can type directly into an HTML element as if it were a text field.
For example, to make it so you can type directly into an h3 tag:
>
Note
It is not recommended to use a
paragraph tag as a text editable element wrapper. This is because when a user types “enter” to make a new line, browsers add a
tag, and div tags are not allowed as children for a paragraph tag.
Toolbar Editable
The
acf_inline_toolbar_editing_attrs() helper function will make any HTML element pop-up a toolbar of ACF fields when clicked or focused.
For example, to make an image tag editable:
/>
This will make it so that a pop-up toolbar appears when the element is clicked, where each field in the array is a button in the toolbar, allowing it to be edited.
Mix and Match
While you can mix both auto and manual fields in your render template, if you wish to completely control which elements are inline editable manually, in your
block.json file set
autoInlineEditing to false, and use
acf_inline_toolbar_editing_attrs and
acf_inline_text_editing_attrs on your desired HTML elements, as described above.
Next Steps
Next, we’ll look at how to fully customize the experience for content editors by making use of the helper functions for inline editing..
Next: Customizing the Inline Editing Experience
Extending ACF Blocks With Block Supports
Overview
The WordPress Block Supports API offers plenty of features to extend your ACF Blocks. Additional attributes are passed to your block when you opt in to these features. Often, these features enable different parts of the block editor’s user interface and allow your clients to customize corresponding properties like spacing, alignment, or color.
This tutorial shows you how to utilize Block Supports with ACF Blocks to give your clients a consistent and easy-to-use experience for managing block settings and styles. We’ll explore how to add Block Support properties, and then show how to ensure your block’s assigned properties are properly output in the final markup.
This tutorial will modify the custom Author Info block used in previous tutorials. However, you should be able to add the code to any ACF Block and obtain similar results. You can download the current version of the Author Info block here: author-info-block-v2.zip
Be sure to check out the previous tutorials:
Using InnerBlocks and Parent/Child Relationships With ACF Blocks
Locking Down Your ACF Blocks With Block Locking
Declaring Block Supports in ACF Blocks
The entry point for declaring your Block Supports is your ACF Blocks
block.json. Let’s look at a simple ACF Block example:
{
"name": "acf/author-info",
"title": "Author Info",
"description": "Display an author's info and picture.",
"icon": "id",
"acf": {
"mode": "preview",
"renderTemplate": "template.php"
},
"supports": {
"align": true,
"html": false,
"jsx": true,
"mode": true
}
}
Most of the
block.json example above should already look familiar. The
"supports" key is where we want to focus. Here, we’re declaring our support for certain features. Two features are unique to ACF Blocks and not part of WordPress:
jsx and
mode.
jsx: JSX refers to how ACF renders your block. This property is true by default in ACF Blocks v2, and is required to use features like
and will be required for upcoming features. When enabled, ACF processes your rendered PHP template in JavaScript first, allowing the use of React implemented features.
mode: Adding support for
mode allows users to toggle between edit and preview modes via a button. This property defaults to
true.
By declaring
"align": true, we’re enabling our clients to set this block’s alignment to center, left, right, full, or wide.
We can limit the options for alignment by passing in specific attributes.
...
"supports": {
// Declare support for specific alignment options.
"align": ["left", "right", "full" ]
}
You can go even further, using the
attributes key to pass a default value for many Block Supports.
...
"supports": {
// Enable all alignment options.
"align": true
},
"attributes": {
"align": {
"type": "string",
"default": "right"
}
}
Whenever a client adds this block to the editor, it will automatically be aligned right.
Alternatively, you can disable the alignment controls and still force a non-default alignment attribute. Set
"align": false, and then pass in an attribute with a new default alignment:
...
"supports": {
// Disable alignment controls.
"align": false
},
"attributes": {
"align": {
"type": "string",
"default": "wide"
}
}
Spacing is another Block Support attribute that we can explore as an example. Spacing can include
margin,
padding, and
blockGap, and each exists as sub-properties of
spacing.
...
"supports": {
"spacing": {
"margin": true, // Enable margin UI control.
"padding": true, // Enable padding UI control.
"blockGap": true // Enables block spacing UI control for blocks that use layout.
}
}
The example above enables all three spacing properties. Of course, we can be more specific on what we want to allow.
...
"supports": {
"spacing": {
"margin": ["bottom", "top"], // Enable margin for arbitrary sides.
"padding": true, // Enable padding for all sides.
"blockGap": ["horizontal", "vertical"] // Enables axial (column/row) block spacing controls.
}
}
Again, we can also provide default values for specific properties that we support with the
attributes definition. When we opt into specific spacing properties, the definition of the attributes includes the
style attribute.
...
"supports": {
"spacing": {
"margin": ["bottom", "top"], // Enable margin for arbitrary sides.
"padding": true, // Enable padding for all sides.
"blockGap": ["horizontal", "vertical"] // Enables axial (column/row) block spacing controls.
}
},
"attributes": {
"style": {
"type": "object",
"default": {
"spacing": {
"margin": {
"bottom": "2rem",
"top": "2rem"
},
"padding": "2rem" // Assign default value for all sides
}
}
}
}
Above, we’re opting into specific spacing properties in our
"supports" definition. In our
"attributes" definition, we’re passing default values to each of our properties. There are a lot of Block Support properties, and we encourage you to experiment with them to turn key features of your ACF Blocks on or off. If you use ACF Blocks v2 and define your blocks with
block.json, any new supports added by WordPress in future versions are likely to work without any other changes.
Also, remember that declaring support in your
block.json will not automatically apply the final properties to your final saved block markup. Once your blocks have attributes assigned, you will want to apply them programmatically to your blocks. We’ll cover how to do this next.
Applying Block Supports to ACF Blocks
Defining Block Support in your ACF Block’s
block.json file was the first step. Next, we need to ensure all of the properties our block supports can be output in the final block markup.
This is where the convenience of ACF PRO’s
"renderTemplate" definition comes in handy.
In your
block.json, you can pass the PHP file you want to call for your block’s template:
"acf": {
"renderTemplate": "template.php"
}
Once we step into our
template.php, we’re passed in several helpful parameters to utilize:
$block – (array) The block’s attributes.
$content – (string) The block’s content as a parse string.
$is_preview – (boolean) Check whether or not the block is currently in the editing view.
$post_id – (int) The current post being edited or viewed.
$wp_block – (WP_Block) The block instance.
$context – (array) Any block context information.
WordPress provides us with the handy
get_block_wrapper_attributes() function, which we can use to assign our attributes. However, we must be mindful to not try and use this function when ACF Blocks are in preview in the editor, as your blocks will automatically get a wrapper provided by the block editor which could duplicate your attributes. We can use
$is_preview to check when we’re in preview mode and avoid confusion.
Let’s look at a specific example. Here is our ACF Block’s
block.json definition:
{
"name": "acf/author-info",
"title": "Author Info",
"description": "Display an author's info and picture.",
"icon": "id",
"acf": {
"mode": "preview",
"renderTemplate": "template.php"
},
"attributes": {
"style": {
"type": "object",
"default": {
"spacing": {
"margin": {
"bottom": "2rem",
"top": "2rem"
},
"padding": "1rem"
}
}
}
},
"supports": {
"color": true,
"multiple": false,
"spacing": {
"margin": ["bottom", "top"],
"padding": true
}
}
}
Enabling
"color": true automatically opts us into some of color’s sub-properties, like
"background" and
"text". These will allow editors to choose a background color and text color.
We’re passing in a new definition for
"multiple": false, which makes sure that this block can only be inserted once in the editor. If an editor tried to insert another copy of our block in the same post, then they would see a grayed-out version of the block in the inserter.
Finally, we’re passing in some
"spacing" definitions and setting default values for the desired
margin and
padding in our
"attributes".
When we want to output all this for the final markup and leverage the convenience of
get_block_wrapper_attributes() in our
"renderTemplate": "template.php" file, we would put:
>
// Block content goes here.
When our editors leverage any of the customization options, they’ll be output in the final markup. It may be a class or style that is output, depending on which features we allow.
Tips for Block Supports and ACF Blocks
There are some special tips to keep in mind when working with Block Supports and ACF Blocks.
Adding, modifying, or removing an attribute from an existing block’s
block.json definition will not update the blocks that have already been inserted in your content. It will only impact future versions of the block, including if a user modifies an existing block entry. This is a limitation of how blocks work in WordPress.
ACF Blocks automatically passes a few default Block Supports behind the scenes:
array (
'align' => true, // Enables alignment
'html' => false, // Disables individual block editing in HTML view
'mode' => true,
'jsx' => true, // Allows ACF to parse JSX to HTML for InnerBlocks
)
This is really just the beginning of what you can do with Block Supports. Some more helpful Block Supports that we want to point out:
inserter (
boolean, default:
true)
By default, all blocks will appear in the inserter, block transforms menu, Style Book, etc. To hide a block from all parts of the user interface so that it can only be inserted programmatically, set
inserter to
false.
{
…
"supports": {
// Hides this block from the inserter.
"inserter": false
}
}
reusable (
boolean, default:
true)
By default, all blocks can be converted to reusable blocks, but you may want to disable this ability for certain blocks. If
"supports": reusable is set to
false, the option to convert the block into a reusable block will not appear.
{
…
"supports": {
// Do not allow the block to be converted into a reusable block.
"reusable": false
}
}
We’re still just scratching the surface, and WordPress offers a great deal of flexibility for styling and controlling your ACF Blocks with Block Supports. Be sure to check out the full list of Block Supports for more features you can add to your ACF Blocks.
Field Settings
Each field contains settings to determine where and how data is loaded and saved. These settings can be customized when editing a field group. All fields share some common settings, but also offer unique settings per field type. These unique settings can be found by reading more about the field type. Below is a screenshot showing the available field settings for a text field.
Common Settings
Name
Description
Field Label
This is the label which appears on the edit page when entering a value. Required.
Field Name
This is the name used to save and load data from the database. This name must be a single word, no spaces, underscores and dashes allowed. Required.
Field Type
The type of field will change the settings available, the interface when entering data, and the value returned from the database. Required.
Instructions
This text appears on the edit page when entering a value.
Required
Required fields will cause validation to run when saving a post. When attempting to save an empty value to a required field, an error message will display.
Conditional Logic
Once enabled, more settings will appear to customize the logic which determines if the current field should be visible or not. Groups of conditional logic can be created to allow for multiple and/or statements. The available ‘toggle’ fields are limited to those which are of the type select, checkbox, true/false, radio.
Wrapper Attributes
These attributes will be used to create the wrapping DOM element for the field. Added in v5.0.0
Customization
Outside of the “Edit field group” UI, it is possible to modify a field’s settings via the acf/load_field filter. This filter exposes the
$field settings array for each field and allows customization to all settings.
This example shows how to modify a specific field (called ‘events’) via this filter to customize settings unavailable to the UI.
functions.php
';
// customize wrapper element
$field['wrapper']['id'] = 'my-custom-id';
$field['wrapper']['data-jsify'] = '123';
$field['wrapper']['title'] = 'Text here';
// return
return $field;
}
add_filter('acf/load_field/name=event', 'my_acf_load_field');
?>
...
Save
Save
Save
Save
Save
Save
File
Description
The File field allows a file to be uploaded and selected by using the native WP media popup.
Screenshots
The File field interface
The File field settings
Changelog
Added
minimum setting in version 5.1.9.
Added
maximum setting in version 5.1.9.
Added
allowed file types setting in version 5.1.9.
Settings
Return value
Specifies the format of the returned data. Choose from File Array (array), File URL (string), or File ID (integer).
Library
Limits file selection to only those that have been uploaded to this post, or the entire library.
Minimum
Adds upload validation for minimum filesize in MB (integer). The filesize may also be entered as a string containing the unit. eg. ’400 KB’.
Maximum
Adds upload validation for maximum filesize.
Allowed file types
Adds upload validation for specific file types. Enter a comma separated list to specify which file types are allowed or leave blank for all types.
Template usage
The File field will return either an array, a string or an integer value depending on the Return Value set. Below are some examples of how you can use this data.
Basic display (array)
This example demonstrates how to display the selected file when using the
array return type. This return type allows us to easily access data such as
url and
filename.
Advanced display (array)
This example demonstrates how to display a custom link when using the
array return type. This return type allows us to easily access data such as
url,
title,
type and more.
Basic display (ID)
This example demonstrates how to display the selected file when using the
ID return type.
Download File
Basic display (URL)
This example demonstrates how to display the selected file when using the
URL return type.
Download File
Flexible Content
Description
The Flexible Content field provides a simple, structured, block-based editor.
Using layouts and sub fields to design the available blocks, this field type acts as a blank canvas to which you can define, create and manage content with total control.
Screenshots
The Flexible Content field interface
The Flexible Content field settings
Settings
Layouts
Defines the layouts available when editing content. Each layout contains Label, Name, Limit, Display and Field settings.
Button Label
The text shown in the ‘Add Row’ button.
Minimum Layouts
Sets a limit on how many layouts are required.
Maximum Layouts
Sets a limit on how many layouts are allowed.
Template usage
The Flexible Content field returns a multi-dimensional array containing the layouts and their sub field values.
Accessing the value is done via the have_rows, the_row, get_sub_field, and the_sub_field functions.
Loop example
This example demonstrates how to loop over a Flexible Content field value and access sub fields from different layouts.
Frequently Asked Questions
General Questions
What is a custom field?
Straight out of the box, WordPress comes with two post types: Posts and Pages. These allow you to write content in the administration area (sometimes called the back end), and have that content displayed on the public facing side of your website (the front end).
But what if you wanted to store and retrieve more information on each page (or post) than just the content?
To help out with this, WordPress provides the ability to associate ‘post meta’ data with your pages or posts. This means you can add information like a start date to an event post, or a price to a product post, and then display that information to your website’s users using built-in WordPress functionality.
WordPress calls these ‘custom fields’, and provides a very basic form on the post and page editing screen to create and update these values.
What is ACF?
ACF helps you, as a developer, to take advantage of these custom fields. It gives your users a sleek user interface to manage their custom field information, and you a suite of powerful functions to retrieve and present it to your site’s visitors.
Practically, this means you can add custom data to not only Posts and Pages, but also Categories, Taxonomies, Custom Posts, Custom Taxonomies, Users, Attachments, Comments, Menus, Widgets and Options, all in just a few clicks, and without writing any code. There are currently over 30 different field types ranging from simple text fields through media and maps, to more complex groups of fields and relationships.
ACF also provides a series of PHP functions that developers can use to display the information stored in these fields in their front-end templates, and an ever-expanding suite of actions and filters that make customizing both the plugin, and the data it produces, a breeze.
What is ACF PRO?
ACF PRO is an extension of the latest version of our free plugin. It includes numerous premium features:
Repeater field
Gallery field
Flexible Content field
Clone field
Options pages
ACF Blocks
Why use ACF?
At the time of writing, it is estimated that 40% of the planet’s websites run on WordPress. And one of the keys to WordPress’s success is its flexibility and extensibility: it has evolved from a simple blogging platform to a sophisticated Content Management System capable of managing and displaying any sort of information.
ACF handles the nuts and bolts of adding the most common types of information to WordPress. If you’d like to add a PDF to your page for your users to download, the File Field will upload, store and retrieve that PDF for you. You’ll just need to add one line of code to your template.
Like WordPress itself, ACF is also under constant, active development. That means that as the framework evolves, you’ll be able to utilize the improvements introduced without major disruptions to your site and your development processes.
Is ACF for me?
While ACF is designed to be as easy to use as possible, it is a tool created specifically for WordPress developers.
You will need an understanding of how PHP code works, and a decent grounding in the basic concepts of WordPress (such as ‘The Loop’) to get the most value out of the plugin.
What kind of support do you offer?
We are fanatically committed to providing users of ACF great support.
We are constantly working to expand and improve the plugin’s documentation.
If you can’t find an answer there, the folks on our email help desk will do their very best to help you out.
There is also a very active community of users on our Community Forums who are both very knowledgeable and friendly!
You can find out more about support at our dedicated Support FAQ.
Pre-Purchase Questions
How much does ACF cost?
ACF comes in two versions: free and PRO. The free version is fully featured, and contains most of the types of fields you’re likely to need while building an average website.
If you’d really like to level up, and gain access to more complex features such as ACF Blocks and Options Pages, as well as feature rich field types such as Galleries, Repeaters, Flexible Content Layouts, and Clones, you’ll need to purchase the PRO version.
ACF PRO licenses are available for purchase as yearly subscriptions. Prices shown are in USD excluding any taxes which may be added during checkout depending on your billing location. For available pricing, please see our PRO page.
Do I need to renew my license?
Yes. Licenses are renewed automatically each year to give you continued access to updates and PRO features. You may also opt-out from auto renewals in favor of manual control from your online account.
What payment methods do you accept?
You can safely purchase ACF PRO with your credit card through Stripe’s secure payment gateway.
Are you registered for tax?
ACF is tax registered in the US and Canada. Your tax will be calculated at checkout.
If you require a ‘Tax residency certificate’ we have one available, please contact support.
What do I get with my purchase?
Your purchase provides you access to your own store account page on our site. From here you can:
– Download the latest version of ACF PRO (and access previous versions too).
– View and upgrade your license keys.
– View and manage your license activations.
– View and print invoices for all your orders.
– Manage your contact and billing details.
– View and create support tickets.
Where can I download my purchase?
Your ACF PRO download is always available at your store account page on our site.
Is ACF compatible with (insert theme or plugin here)?
ACF PRO has been built with WordPress best practices in mind. We have designed the plugin to be as efficient and unobtrusive as possible, to allow you to build great websites without getting in your way.
But, with over 50,000 plugins available in the WordPress directory, and probably at least as many themes available, some conflicts may arise. In the unusual circumstance that such an issue occurs, we will always do our utmost to try and resolve those conflicts through our friendly support folks.
What kind of support do you offer?
We are fanatical about support, and want you to get the best out of your website with ACF. If you run into any difficulties, there are several places you can find help:
Our extensive documentation contains references and guides for most situations you may encounter.
We have an active and friendly community on our Community Forums who may be able to help you figure out the ‘how-tos’ of the ACF world.
The support professionals on our Help Desk will assist with your more in-depth technical challenges
The WordPress professionals at Codeable can provide coding support if you’re starting to feel out of your depth.
Find out more about our support here.
Do you offer refunds?
We really want you to be happy with your purchase, and we’ll try really hard to make that happen. But, if for any reason you’re not completely happy, we do offer a 30 day money back guarantee. Please get in touch.
Account Questions
What types of accounts are there?
There are currently two different types of accounts:
Accounts – at www.advancedcustomfields.com/my-account/, and
Support – at support.advancedcustomfields.com
You can create a support account at any time, but you need to have purchased ACF PRO to access the Accounts area.
I’m having troubles logging in
There are currently two different logins in the world of ACF:
Accounts – at www.advancedcustomfields.com/my-account/, and
Support – at support.advancedcustomfields.com
If you are having trouble logging in, you may be using the credentials from one side to try and login to the other. Try checking this first.
If you’re still having trouble, try resetting your password.
Password reset not working
If you’re running into difficulties trying to reset your password, please get in touch.
What can I do with my account?
With your account you can:
Download the latest version of ACF PRO (and all previous versions, if you wish)
View and upgrade your licenses
View and print invoices for all your previous orders
Edit your contact and billing details
View and add new support tickets
Transferring ownership
Transferring ownership of an ACF PRO license is as simple as updating the account details at your store account page. If you’ve lost your account information, or are having troubles making this happen, please let us know
Can I delete my account?
Absolutely, although this is not possible through the website. Please get in touch.
Installation Questions
What are the requirements to run ACF?
Take a look at our doc that outlines the minimum requirements of WordPress and PHP, as well as our recommended versions to run ACF.
How do I install ACF?
Users who are installing ACF for the first time on a site should follow these steps:
Download the latest zip of the plugin
Log in to your site
Navigate to Plugins > Add new
Upload the zip file
Click ‘Activate Plugin’
ACF is successfully installed and activated if your Administration menu has an entry called ACF.
For a step by step guide to installation, click here.
How do I install ACF PRO?
ACF PRO is only available for download from the downloads section of your ACF store account.
ACF PRO can be installed via your WordPress site’s admin dashboard. Navigate to Plugins > Add New Plugin and click Upload Plugin. Select the ACF PRO zip file downloaded from your account. Once installed, click Activate.
It can also be installed via FTP. Unzip the file you have downloaded, and upload the folder called ‘advanced-custom-fields-pro’ to your wp-content/plugins directory. Once ACF PRO is uploaded, you will need to activate it by finding it in the list on the Plugins page in your site’s Administration area, and clicking on the Activate link.
ACF PRO can also be installed with Composer.
To enable your automatic updates and PRO features, you’ll need to enter your license key under “ACF” > “Updates”, and click ‘Activate’.
Can I uninstall?
We can’t imagine why you’d want to, but you most certainly can uninstall ACF.
The first step will be to locate any ACF specific code in both your theme’s
functions.php file or its template files. For your reference, you can find a list of ACF specific functions, filters, and actions in the documentation.
You’ll need to deactivate ACF by clicking on the Deactivate link on the Plugins page, followed by the Delete link.
This will remove all of the plugin’s files from the WordPress plugins directory.
Is it safe to uninstall?
Simply deactivating or uninstalling ACF will not affect any of the data you’ve created while using the plugin.
This means that the data will continue to be available throughout your site even if the plugin is no longer functioning.
Please note, however, if you are using ACF specific functions such as the_field() or get_field() to access this data in your plugin or template files, these functions will no longer exist, and your website will no longer function as expected.
Is it safe to re-install?
Because your field data remains intact after deactivation, you should be able to reinstall ACF or ACF PRO and pick up where you left off.
Simply follow the steps outlined above.
If you run into any troubles, please get in touch with support.
What’s next?
With ACF or ACF PRO successfully installed, you should probably get started!
Getting Started Questions
Before you start
If you’re planning on using ACF to extend the capabilities of an existing website, please back up your database and theme files before beginning. That way, you can always return your site to its original state if things don’t go as expected.
If you’re using a pre-built theme, make sure you create a child theme, as you will almost certainly be modifying template files to display your custom field data on the front end of your site. Having a child theme means that your changes won’t be overwritten when your theme is next updated.
Now might also be a good time to make sure you’re familiar with concepts like ‘The Loop’, and the WordPress template hierarchy. You’ll need to understand how WordPress uses theme files to output HTML to get the most out of the plugin.
Getting around ACF
If you’ve installed and activated ACF successfully, a new menu item titled ACF will appear in the WP-Admin menu. This is your gateway into the wonderful world of ACF.
To create a new set of custom fields (or field group), choose ACF> Field Groups > Add New from this menu system. To edit an existing field group, choose ACF > Field Groups, and then select the group you want to edit from the list on that page.
The Tools page ( ACF > Tools ), provides a way to import or export some or all of the field groups you’ve already created. These plain text JSON exports are an easy way to move your favourite field groups from site to site, or to backup a field group before making changes. You can also generate PHP code here to construct your custom fields from within your theme’s code. Using this option can speed up your website by reducing the number of calls made to the database.
You can enter your ACF PRO license key on the Updates page ( ACF > Updates ). This will enable automatic updates and keep your plugin up to date with all the newest features.
What is an ACF field group?
In ACF world, a field group is a collection of custom fields that will be displayed together on a WP-Admin editing screen. Behind the scenes, a field group is a type of custom post, which means they can be found in the Posts table of your WordPress database. A field group is broken up into 3 main sections:
The collection of fields
The location settings
The general settings for the group
What is a Field?
A custom field is the basic building block of ACF. Its main purpose is to streamline the process of adding and pulling extra information to and from built-in WordPress objects such as Posts, Taxonomies, and Users.
In a field group editing screen, you are able to specify settings for each individual field, such as labels and instructions, placeholder text and default values, whether or not a value is required, as well as attributes for the field such as CSS classes and an ID. You can also set up conditional logic for the field (which will control whether or not it is displayed) based on values entered into another field.
More complex field types can even include their own sub fields, and can provide the ability to create quite complex structures without needing to write large amounts of code.
What kind of fields can I make?
ACF currently provides over 30 different field types ranging from simple text fields through media and maps, to more complex groups of fields and relationships. You can view the full list in our documentation.
How many fields can I make?
There is no real limit to the number of fields you can create using the plugin. If you have room on your database server, you can keep on creating fields.
But as a general rule, and to help both your website and your site’s administration area to maintain decent performance, we wouldn’t recommend adding more than fifty fields to a field group. If you think you need more than that, it might be worth reconsidering how you’re structuring your data.
Naming your fields
Just like in most programming and development, it’s good practice to make your field names both readable and descriptive. This will help you keep track of what each field is for when you’re using them in your templates later on.
For example, rather than naming a date field just ‘date’, perhaps you could name it ‘start_date’, which would allow for an ‘end_date’ at some point in the future.
Readable and descriptive field names will also help those coming after you by helping them understand what you were intending when you created those fields. Consider the example below:
versus
Obviously the second example will give you a lot more context when you or your workmates return to this code in 6 months to update it!
How do I make my fields appear when I’m editing?
ACF uses ‘location rules’ to determine when and where to display the field froups you create. You can specify these rules in the “Location Rules” section of the field group editing page.
Location rules allow you to choose to show a field group based on whether or not a post is of a specific post type, uses a specific template, or belongs to a specific category. You can also show field groups for users, taxonomies, attachments, menus, and much more. You can even specify your own custom location rules.
See this guide for more information.
How do I make my fields appear on my website?
You will need to edit your theme’s PHP template files to show the information entered into your fields on your site’s front end.
ACF provides a suite of functions to assist with retrieving your fields’ values from the database and displaying them in a template.
The documentation for each field type generally has code examples showing how to edit your template file to make the data returned by that field type display properly on the front end. Below is a simple example of using the_field() to make a field in a basic template:
Can I customize my fields?
Each field has a group of settings that provide the ability to change labels, placeholder, default values, instructions, and more. There are also settings available that are specific to each field type, such as ‘options’ for a dropdown field.
If the provided settings are not configurable enough for you, you can also explore the filters that are available for different field types.
Where can I find out more?
If you have more specific questions about how ACF works, please have a look through our extensive documentation.
If you would like to access our support system, please check out our Support FAQ. You can also access help through the support section of our website.
Updates Questions
Are updates free?
No, you will need an active subscription of ACF PRO to receive updates to the plugin.
Lifetime license holders will continue to receive updates.
How do I update ACF?
ACF can be updated either via one-click update or manually. When an update becomes available, you will receive a notification on your Plugins page.
To apply the update via one-click update, simply click ‘update now’ in the notification on the Plugins page.
To update manually, you can download the new version of the plugin here. You can then safely delete the plugin directory on your server, and upload the new version via FTP.
For more details, please see our guide: How to update.
How do I update ACF PRO?
ACF PRO can also be updated via one-click update or manually. When an update becomes available, you will receive a notification on your Plugins page.
You need to activate a valid license in the plugin’s ‘Updates’ page to enable automatic updates. To apply the update via one-click update, simply click ‘update now’ in the notification on the Plugins page.
If you want to update manually, you’ll need to download the latest version from your store account.
For more details, please see our guide: How to update.
Can I upgrade to ACF v6 from ACF v5?
The upgrade from ACF 5 to ACF 6 will be seamless for the majority of users. There are a couple of areas of backwards compatibility that may need some extra work:
If you have customized the settings for a field type.
If you have used ACF Blocks and rely on a unique block ID in your templates or you use
parse_blocks() and require a block ID.
I upgraded from v4 to v5 and my fields disappeared!
If you’ve upgraded from version 4 to version 5 of ACF and you can’t see your fields, first of all, don’t panic! Version 5 uses a different data structure so they might not be visible, but your fields and their values are still there.
You should see a database upgrade prompt at the top of the page on your WordPress dashboard. All you need to do is click the button to run the database upgrade process. Your fields should reappear once that process has been completed
If you’re still having difficulties, please get in touch.
I upgraded from v4 to v5 and the database upgrade prompt didn’t appear
For some reason, the database upgrade process may not have triggered as expected when the new version was installed. To make this happen again, please ensure version 5 is activated and follow this procedure:
Back up your database.
In your wp_options table, please set the acf_version value back to the latest version you had installed ( something like 4.4.11 ).
Reload the wp-admin dashboard.
Click the database upgrade button that appears.
If you’re still having troubles, please contact support.
I can’t seem to connect to the update server
In some hosting environments, communication may not be possible between your server and the WordPress update server. If this happens to you, please note any error messages you find, and contact support.
How do I downgrade ACF?
If you’d like to go back to an earlier version of ACF, we’d recommend using this rollback plugin, which is available from the WordPress repository.
Although we’re not associated with this plugin in any way, we have had reports of ACF users employing it successfully.
How do I downgrade ACF PRO?
All the previous versions of ACF PRO are available for download from the downloads section of your ACF store account. To start rolling back, you’ll need to log in, download, and unzip the version you’d like to rollback to.
Then, on your website, you’ll need to deactivate and delete the version you’re currently running on the Plugins page.
Finally, you’ll need to upload the older version to your
wp-content/plugins directory. Once the older version of ACF PRO is uploaded, you will need to activate again it by finding it in the list on the Plugins page in your site’s Administration area, and clicking on the Activate link.
License Questions
What is a license?
License keys are used to activate the plugin via the ‘Updates’ ACF admin page. Activating the license key on a site enables automatic plugin updates and gives access to ACF PRO premium features.
Until a valid license key has been activated for the site, it won’t be possible to create new or edit existing PRO fields (Gallery, Repeater, Flexible Content, or Clone), or use the premium features such as Options Pages and ACF Blocks.
If you previously activated a license and the subscription has expired, you will not be able to create new PRO fields, but you will be able to edit existing PRO field definitions.
The editing and display of field data will be unaffected by the status of the licenses.
Learn more about license activations.
After purchasing an ACF PRO license, you will receive a unique license key and access to download plugin files via our members area.
After installing and activating the ACF PRO plugin, you may then activate your license key from the “ACF > Updates” admin screen to register that website for plugin updates.
Can I upgrade/downgrade my license?
Yes. You can upgrade or downgrade your license at any time. Simply log in to your account area and navigate to the Subscriptions page. Once viewing your subscription, please use the “Upgrade or Downgrade” button shown next to the Product title and follow the prompts to sign-up to a new tier and complete the checkout.
If this button does not appear, the problem may be due to a related API issue. To solve this limitation, please use the Change payment button to first enter a valid credit card via the Stripe payment gateway.
License upgrade costs are prorated. The calculated amount will take into account the current subscription length and the difference in price between tiers. For example, Jane subscribed to a Personal license ($49 USD yearly) and then decided to upgrade to the Freelancer tier ($149 USD yearly) after exactly 3 months. The initial “upgrade fee” will be calculated as
($149 - $49) / 12 * 9 = $75 USD with a then ongoing yearly subscription fee of $149 USD.
License downgrades are free, however, we encourage you to contact support and ask if a partial refund can be applied.
Can I opt out of yearly subscriptions?
Yes. By default, your subscription will be set up to auto-renew 12 months after sign-up. To opt out, simply login to your account area and navigate to the Subscriptions page. Once viewing your subscription, please toggle the Auto renew switch to the off position.
With auto renewals disabled, your subscription will end at the end of the 12 month period and you will lose access to plugin updates and ACF PRO features in the plugin. However, it will still be possible to manually renew or enable auto updates again to continue receiving access to the latest plugin releases.
How do I activate my license key?
To activate your ACF PRO license, you need to paste your license key into the available space on the page at “ACF > Updates”. Then click the Activate License button.
You can find this key on your store account page.
For a more detailed guide, please see How to activate.
What data is recorded upon activation?
Each time an ACF PRO license key is activated, the following data is sent to the ACF website and saved to later validate activations and download updates:
ACF license key
ACF installed version
WP site name
WP site url
WP installed version
WP is multisite
WP language
WP timezone
PHP version
Count of ACF Blocks
No personal data such as usernames, emails, or IP addresses are recorded.
If you’d like to find out more about our approach to data and privacy, please read our Privacy Policy
How many times can I activate my license?
The maximum number of “active” activations is limited by the license tier. Currently, we offer three tiers with increasing limits:
– Personal: 1 website.
– Freelancer: 10 websites.
– Agency: Unlimited websites.
In addition, we allow unlimited activations for “development + staging” websites.
To better understand how we determine if a website is considered a production, staging or development environment, please consult the following ruleset:
Dev: Is URL a single segment? (localhost)
Dev: Is URL an IP address? (192.168.0.1)
Dev: Does the URL contain a dev related segment? (dev.website.com, website.dev.cc)
Dev: Does the URL contain a dev-related subdomain? (test., testing., sandbox., dev., local.)
Dev: Does the URL contain a dev-related TLD? (.local, .loc, .localhost, .test)
Stage: Does the URL contain a stage-related subdomain? (stage., staging.)
Stage: Does the URL contain a stage-related parent? (sitename.wpengine.com, sitename.wpenginepowered.com, staging-sitename.kinsta.cloud, sitename.flywheelstaging.com)
Prod: All other URLs.
Remember you can upgrade or downgrade your license at any time, and our support team is always here to help answer your questions!
Which license do I need for WordPress multisite?
ACF PRO is used at a site level, not a network level, so you need to activate the plugin on every subsite where it’s required. Therefore, you need a license that can be activated on those subsites.
For example, if you have a multisite network and want to use ACF PRO on 8 of the subsites, you would need the Freelancer license, which has a 10 site activation limit. If you have a large multisite network and want to network activate the plugin so it can be used on all subsites, we recommend you purchase the Agency license which has unlimited site activations.
If you purchased a license before 1st Feb 2024, you do not need to activate the license key on individual subsites, just the main site of the network. The updates page will not be visible on any subsites.
Support Questions
What kind of support do you provide?
We are fanatical about support, and want you to get the best out of your website with ACF. If you run into any difficulties, there are several places you can find help:
Our extensive documentation contains references and guides for most situations you may encounter.
We have an active and friendly community on our Community Forums who may be able to help you figure out the ‘how-tos’ of the ACF world.
The support professionals on our Help Desk will assist with your more in-depth, technical challenges.
The WordPress professionals at Codeable can provide coding support if you’re starting to feel out of your depth.
Who can access support?
Support is provided for free to everyone, without any bias to customers or beginners. Because this support service is provided for free, please take this into consideration when creating a ticket and waiting for a reply.
Please research your issue and read the relevant documentation before asking a question. This will help free up our support team and allow for faster development on the plugin which we all love.
When should I use the documentation?
If you have a question about ACF, our collection of documentation articles should always be your first stop.
We are constantly updating and expanding the documentation, based on your feedback, to try and anticipate any questions or difficulties you may have.
The documentation contains detailed technical descriptions and code examples for:
* Field types,
* Functions,
* Actions, and
* Filters
The documentation also contains dozens of friendly guides and tutorials, covering topics from Getting Started to how to debug your code.
When should I use the Community Forums?
If you’ve been through the documentation, and you’re looking for advice on how to use ACF to accomplish a specific task, our Community Forums would be a great next stop.
The chances are that if you’re looking to do something with ACF, someone before you has probably faced a similar challenge, and their solution may already be in the forums.
If there isn’t already a thread containing an answer to your question, you can create a new one, and one of the friendly fellow developers who hang around the forum will probably be able to point you in the right direction.
You can also use the forums to throw around new ideas, discuss ACF related plugins, and earn some good karma by sharing your knowledge with the community.
When should I use the Help Desk?
If you run into a problem, and can’t find a solution in the documentation, or the Community Forums, please get in touch with our email help desk.
The friendly folks on the help desk will do their utmost to help you solve any problems that are ACF related, but please note, we may not always be able to help with issues that are caused by custom theme code, or conflicts and incompatibilities with other plugins.
We aim to answer your questions within 24 hours, with the exception of weekends and holidays.
When should I use Codeable?
If you’re looking for a developer to help you write some custom code that involves ACF, we’ve been pretty impressed with the folks from Codeable. They have a roster of vetted developers who have specific expertise in WordPress and ACF.
Plus, they’re giving ACF users a USD$60 voucher (worth an hour of coding) if you get in touch through us.
Gallery
Description
The Gallery field provides an interactive interface for managing a collection of attachments.
Screenshots
The Gallery field interface
The Gallery field settings
Changelog
Added
Minimum setting in version 5.1.9.
Added
Maximum setting in version 5.1.9.
Added
Allowed File Types setting in version 5.1.9.
Settings
Return Format
Specifies the format of the returned data. Choose from Array (array), URL (string), or ID (integer).
Preview Size
The WordPress image size displayed when editing.
Insert
Specifies where new attachments are added. Chose from either Beginning or End.
Library
Limits file selection to only those that have been uploaded to this post, or the entire library.
Minimum Selection
The minimum number of attachments required for field validation.
Maximum Selection
The maximum number of attachments allowed for field validation.
Minimum
Adds upload validation for minimum width in pixels (integer), height in pixels (integer) and filesize in MB (integer). The filesize may also be entered as a string containing the unit. eg.
’400 KB’.
Maxiumum
Adds upload validation for maximum width, height and filesize.
Allowed File Types
Adds upload validation for specific file types. Enter a comma separated list to specify which file types are allowed or leave blank to accept all types.
Template usage
The Gallery field will return an array of attachments where each attachment is either an array, a string or an integer value depending on the Return Format set.
Display list of images
This example demonstrates how to loop over a Gallery field value and display a list of images. It uses the wp_get_attachment_image() function to generate the image HTML. The field in this example uses
ID as the Return Format.
This function also generates the srcset attribute allowing for responsive images!
Display list of images with custom HTML
This example also demonstrates how to loop over a Gallery field value and display a list of images. The field in this example uses
Array as the Return Format.
Display images in a slider
This example demonstrates how to display the images from a Gallery field in the correct markup required for a WooThemes Flexslider to work. The field in this example uses
Array as the Return Format.
Create a WordPress Gallery
This example demonstrates how to display the images from a Gallery field in a WordPress gallery by generating and rendering a gallery shortcode. The field in this example uses
ID as the Return Format.
comment_ID}"
Requirements
Custom fields for comments requires at least ACF version 5
Examples
Basic parameter use
This example shows how the second parameter is used to target the specific comment.
Custom comment list
This example shows how to create a custom comment list callback and display some custom fields.
single.php
comments.php
'my_comment_template'
));
?>
functions.php
Get values from an options page
All the template functions (get_field, the_field, etc) can be used to load values from an options page, however, a second parameter is required to target the options page. This is similar to passing through a
$post_id parameter to target a specific post object.
The
$post_id parameter needed is a string containing the word ‘option’ or ‘options’.
Please note that although it is possible to create multiple options pages, all values are saved and loaded using ‘option’ as the
$post_id.
Examples
Display a field
Retrieve a field
Display a sub field
Note that when inside of a
have_rows loop, you do not need to use the
$post_id parameter for any sub field functions (get_sub_field, the_sub_field)
Get values from a widget
All the template functions (get_field, the_field, etc) can be used to load values from a widget, however, a second parameter is required to target the term. This is similar to passing through a
$post_id parameter to target a specific post object.
The
$post_id parameter needed is a string containing the the word ‘widget_’ and the widget’s ID in the following format;
"widget_{$widget_id}"
To display custom field values within a widget, you will need to use a filter to modify the HTML arguments. If the widget is custom made, you can also customize the HTML output within the
widget function in your widget class.
Requirements
Custom fields for comments requires at least ACF version 5
Examples
Basic parameter use
This example shows how the second parameter is used to target the specific comment.
Basic widget customization
This example shows how to customize the ‘Text’ widget to display with a background color and show an image. Because widgets do not yet contain actions or callbacks to add extra HTML, we must use a filter (
dynamic_sidebar_params) to modify the
before_widget and
after_widget HTML.
The following code is placed in the functions.php file.
add_filter('dynamic_sidebar_params', 'my_dynamic_sidebar_params');
function my_dynamic_sidebar_params( $params ) {
// get widget vars
$widget_name = $params[0]['widget_name'];
$widget_id = $params[0]['widget_id'];
// bail early if this widget is not a Text widget
if( $widget_name != 'Text' ) {
return $params;
}
// add color style to before_widget
$color = get_field('color', 'widget_' . $widget_id);
if( $color ) {
$params[0]['before_widget'] .= '';
}
// add image to after_widget
$image = get_field('image', 'widget_' . $widget_id);
if( $image ) {
$params[0]['after_widget'] = '' . $params[0]['after_widget'];
}
// return
return $params;
}
get_field()
Description
Returns the value of a specific field.
Intuitive and powerful (much like ACF itself ?), this function can be used to load the value of any field from any location. Please note that each field type returns different forms of data (string, int, array, etc).
Any returned values should be escaped using an appropriate escaping function before they are output.
Parameters
get_field($selector, [$post_id = false], [$format_value = true], [$escape_html = false]);
$selector (string) (Required) The field name or field key.
$post_id (mixed) (Optional) The post ID where the value is saved. Defaults to false, which will use the current post.
$format_value (bool) (Optional) Whether to apply formatting logic. Defaults to true.
$escape_html (bool) (Optional) Since 6.2.6 – return an escaped HTML safe version of the field value. Requires $format_value to be true. Defaults to false.
Return
(mixed) The field value.
Examples
Get a value from the current post
This example shows how to load the value of field ‘text_field’ from the current post.
$value = get_field( "text_field" );
Get a value from a specific post
This example shows how to load the value of field ‘text_field’ from the post with ID = 123.
$value = get_field( "text_field", 123 );
Check if value exists
This example shows how to check if a value exists for a field.
$value = get_field( "text_field" );
if( $value ) {
echo wp_kses_post( $value );
} else {
echo 'empty';
}
Get a value from different objects
This example shows a variety of $post_id values to get a value from a post, user, term and option.
$post_id = false; // current post
$post_id = 1; // post ID = 1
$post_id = "user_2"; // user ID = 2
$post_id = "category_3"; // category term ID = 3
$post_id = "event_4"; // event (custom taxonomy) term ID = 4
$post_id = "option"; // options page
$post_id = "options"; // same as above
$value = get_field( 'my_field', $post_id );
Get a value without formatting
In this example, the field “image” is an image field which would normally return an Image object.
However, by passing false as a 3rd parameter to the get_field function, the value is never formatted and returned as is from the Database.
Please note the second parameter is set to false to target the current post.
$image = get_field('image', false, false);
Get an escaped (HTML safe) field value (since ACF 6.2.6)
In this example, the field “wysiwyg” is a wysiwyg field which returns a string containing the contents of the WYSIWYG field.
However, by passing true as the fourth parameter, we’ll ask the field to make sure it’s escaped. In the case of the WYSIWYG field, this escaping happens before filters are run on the field, so shortcodes will still work, but any
Render a single marker onto a map
This example demonstrates how to display a Google Map field value on a map. Note the aforementioned Helper code is required to convert the HTML into an interactive map.
Render multiple markers onto a map
This example demonstrates how to display multiple Google Map field values on the same map. In this example, a Repeater field is used to define a Title, Description and Location. Note the aforementioned Helper code is required to convert the HTML into an interactive map.
Display location address details
New This example demonstrates how to display location address details. These details can be found in a value saved since version 5.6.8.
$k ) {
if( isset( $location[ $k ] ) ) {
$address .= sprintf( '%s, ', $k, $location[ $k ] );
}
}
// Trim trailing comma.
$address = trim( $address, ', ' );
// Display HTML.
echo '
' . $address . '.
';
}
123, Foo Bar Street, Melbourne, Victoria, 3000, Australia.
Notes
Rendering a hidden map
Initializing a Google Map on a hidden element can lead to unexpected results when shown. To solve this problem, trigger a “resize” event on the map variable after the map element is visible.
google.maps.event.trigger(map, 'resize');
Group
Description
The Group field provides a way to structure fields into groups. It assists in better organizing the edit screen UI as well as the data.
The Group field uses both the parent and child field names when saving and loading values. For example, a Group field named ‘hero’ with a sub field named ‘image’ will be saved to the database using the meta name ‘hero_image’.
Screenshots
The Group field interface
The Group field settings
Changelog
Added in version 5.6.0.
Settings
Sub Fields
Defines the sub fields which will appear within this group.
Layout
Defines the layout style used to render the field interface.
Block: Sub fields are displayed in blocks, one after the other.
Table: Sub fields are displayed in a single row table. Labels will appear in the table header.
Row: Sub fields are displayed in a two column table. Labels will appear in the first column.
Template Usage
The Group field field returns an array containing each sub field’s value in a
name => value format.
Display contents
This example demonstrates how to display the contents of a Group field.
Loop example
This example demonstrates how to display the same group using the have_rows() function. While similar to looping over a Repeater field value, there is only a single row in this value.
has_sub_field()
Description
This function is deprecated. Please use the have_rows() function instead.
This function is used within a while-loop to loop through each row of a Repeater or Flexible Content field.
Unlike
have_rows(), this function will take a step through the available rows each time it is called, causing undesired results when also used within an if-statment.
Parameters
has_sub_field( $field_name, $post_id );
$field_name (string) (Required) The name of the Repeater or Flexible Content field to be retrieved. e.g. ‘gallery_images’
$post_id (mixed) (Optional) The post ID where the value is saved. Defaults to the current post.
Return
(bool) True if a row exists.
Change Log
Deprecated in version 4.3.0
Examples
Loop through Repeater field
This example demonstrates how to loop through a repeater field called “gallery_images”.
Loop through nested Repeater fields
This example demonstrates how to loop through nested Repeater fields and display the sub field data.
Display layouts.
This example shows how to loop through a Flexible Content field and generate HTML for different layouts.
Nested loops
This example shows how to loop through a nested Repeater field.
Notes
Infinite Loops
Because the
have_rows() function does not step through each row by itself, using this function without
the_row() will create an infinite loop resulting in a white screen.
Scope
The scope of a
have_rows() loop is limited to the current row. This means that any sub field function such as
get_sub_field() or
the_sub_field() will only find data from the current row, not from parent or child rows.
Hiding empty fields
Overview
It is a common task to hide empty field values from your template. This can be achieved by using conditional statements to check the value before rending it.
The basics to conditional a statement is to use an if statement. You can read more about this core PHP function here: http://php.net/manual/en/control-structures.if.php
Examples
Example 1: Basic
This example shows how to check for a value before displaying it. Please note the use of both get_field() and the_field().
My field value:
Example 2: Loop
This example shows how the above methodology can be used within a loop. Please note the use of get_field_objects() to load the array.
:
How to Activate ACF PRO
This guide shows how to activate ACF PRO and your license key. Without a valid license key on the WordPress site where it is installed, ACF PRO will not be able to receive plugin updates, or access premium features and field types.
Until a valid license key has been activated for the site, it won’t be possible to create new or edit existing PRO fields—Gallery, Repeater, Flexible Content, or Clone—or use the premium features such as Options Pages, and ACF Blocks.
If you previously activated a license and the subscription has expired, you will not be able to create new PRO fields, but you will be able to edit existing PRO field definitions. Content editors will still be able to use any existing PRO fields, ACF Blocks, and options pages, but new ones cannot be created.
The editing and display of field data will be unaffected by the status of the licenses.
Learn more about license activation restrictions.
Installation & Activation
Follow these steps to activate ACF PRO:
Download the plugin zip from the Licenses page in your account.
Install and activate the plugin on your WordPress site.
Copy your license key from the Licenses page.
Navigate to ACF > Updates , enter your license key, and click Activate License.
The free ACF plugin is automatically deactivated when you activate ACF PRO on your WordPress Plugins page. Fields, post types, and data created with the free version of ACF will continue to be used by the PRO plugin. You can safely delete the free plugin after installing ACF PRO.
Finding Your License Key
Each ACF PRO order generates a unique license key associated with an ACF account. Log in to your ACF account and click Licenses to view available licenses and license keys.
You can also view and manage your activations from the Licenses page, and access instructions on how to install ACF PRO with Composer.
Activating Your ACF PRO License Key
You can activate your license through the WordPress dashboard, or by defining your license key in your
wp-config.php file.
WordPress Dashboard Activation
To activate your license, log in to your WordPress admin and navigate to the ACF > Updates page.
Enter your license key into the input field and click Activate. Once the page reloads, you will be met with a notification that the website will now receive ACF PRO plugin updates.
In the case of an error, please contact support and provide the error message displayed (along with your info).
Note: If ACF > Updates is not available, navigate to Plugins in the WordPress Admin and make sure the ACF PRO plugin is installed and activated, and the free version is deactivated. Please contact support if the correct plugin is activated and you are still unable to navigate to ACF > Updates.
Activating ACF PRO in wp-config.php
To activate your license via your
wp-config.php file, add the following line to the file, replacing
[key] with your license key:
define( 'ACF_PRO_LICENSE', '[key]' );
Notes
When copying and pasting your license key, please make sure to copy all characters. License keys do not contain spaces, but contain both lowercase and uppercase letters, numbers and special characters.
How to Create an Options Page
Options pages are setting pages in the WordPress admin area containing fields with the ability to control global options. This allows builders or clients to make one change and update content that appears in many places throughout the site: contact information, calls-to-action, or notifications about sales and special events.
A more advanced options page could even allow clients to switch between entirely different site designs with just a few clicks. The biggest challenge with options pages is coding them, as it’s often time consuming and tedious.
The Options Page feature released in ACF PRO 6.2 gives you a way to register new options pages in the WordPress admin without breaking your workflow or writing a single line of code. This is an extremely powerful tool with almost limitless applications, but it’s important to understand the basics first. In this tutorial, we’ll show you how to use ACF PRO to create an options page that functions as a sitewide notification bar.
The notification bar will be displayed across the top of the entire site, so it’s an ideal example of something you’d want controlled from a custom “Site Settings” page. We’ll include features to allow our editors to toggle the bar on or off, as well as add a custom message.
Here is a breakdown of the steps to set up our sitewide notification bar:
Create a new options page
Create a new field group
Verify the field group is assigned to the options page
Add code to handle display logic (shown if active and hidden if inactive)
The video below will give you a look at the steps we’ll take and the final outcome.
https://www.advancedcustomfields.com/wp-content/uploads/2023/08/ACF-Options-Pages-tutorial-optimized.mp4
Create a New Options Page
First, we need to create a new options page called “Site Settings”. Under ACF’s menu, choose Options Pages, and then click Add New to create a new options page. Click under Page Title and use the default “Site Settings”. Next, click under Menu Slug, and again use the default “site-settings”.
Leave “Parent Page” set to “No Parent” for now. We’ll look at how to create a child options page in a later section. Be sure to save your changes.
Stay in the flow! Saving a new Options Page for the first time prompts you with a notification along the top to either “Add fields” or “Link existing field groups”. This allows you to stay in the flow when you’re creating new options pages, field groups, post types, and taxonomies.
Create a New Field Group
Now that we have our Site Settings options page, we need to assign some fields. We’ll start with a Group field, and then add a True/False field and a Text Area field under the Group field’s “Sub Fields” setting. Here is what our field group setup will look like for our notification bar:
Group field to organize our other fields.
Field Label: Notification Bar
Field Name:
notification_bar
The “Layout” setting (along the bottom) controls how the Group field displays the fields within it. In this case, we’ll choose Row.- True/False field for toggling the notification bar on and off.
Field Label: Notification On/Off
Field Name:
notification_onoff
Under the “Presentation” tab, enable Stylized UI, and then set the text to “On” and “Off”.
Text Area field to allow editors to add a custom message when the notification bar is displayed.
Field Label: Notification Message
Field Name:
notification_message
Click the Conditional Logic tab and toggle it on. Set the values for ”Show this field if” to Notification On/Off, Value is equal to, and Checked. This will make the Text Area visible to editors only when the notification bar is toggled on.
Save your changes and proceed to the next step.
Set the Location Rules for an Options Page
You can associate any field group with an options page on the “Location Rules” tab, located under “Settings” at the bottom of the field group editor. Under “Show this field group if”, select Options Page, is equal to, and then the page you would like your field group to be associated with.
Lucky for us, we used ACF’s seamless fields flow to automatically associate our field group on creation, directly after initializing our new Site Settings options page. This automatically creates a rule to only show the field group on our Site Settings page. You can create additional rules using the “and” and “or” buttons to finetune the conditions under which your field group will display.
Be sure to save your changes. Now, when you click on your new Site Settings page in the WordPress admin, you should see your notification bar field group.
Add Display Logic Code
We’ll utilize WordPress’s handy wp_body_open action to hook up and display our notification bar at the top of our page. Here are the few lines of code we need:
Retrieving a field
This example will retrieve a field value from a user with an ID of 1.
Working with the Repeater Field
Note that when inside of a
have_rows loop, you do not need to use the
$post_id parameter for any sub field functions (get_sub_field, the_sub_field)
Author
This example will find the author for the current post, and display custom field data from that user.
Get values from another post
All the template functions (get_field, the_field, etc) can be used to load values from another post, however, a second parameter is required to target the post.
Each post has a unique ID which can be found in the URL when editing, or found via code such as
$post->ID.
Examples
Display a field
This example will display a field value from the post with an ID of 123.
Retrieving a field
This example will retrieve a field value from the post with an ID of 123.
Retrieving a field from post object
This example will retrieve a field value from a previously found
$post object.
ID);
// do something with $variable
?>
Working with the Repeater Field
Note that when inside of a
have_rows loop, you do not need to use the
$post_id parameter for any sub field functions (get_sub_field, the_sub_field)
How to help translate ACF into other languages
ACF 6.0 introduces a new way of collecting translations from our contributors.
For all the strings contained in the free version of ACF, these are now collected from translate.wordpress.org.
Many of you have submitted translations for numerous languages on WordPress.org since that translation functionality was introduced, but until this release they were never included or loaded into ACF. We’ve imported all the contributions we’ve received directly from our users into translate.wordpress.org for languages which weren’t already complete.
The existing languages we bundled in ACF have been trimmed where they are already complete and approved on translate.wordpress.org to only include the pro strings, but where a language is not complete, we’ve kept all the free strings included too, to avoid losing data while we wait for approval.
If you’d like to help us translate ACF to your language, or help verify translations for your language, you can do so on translate.wordpress.org. WordPress’s Translation Handbook has everything you need to get started. Once complete, you can request WordPress’s translation editors review your submissions as detailed there, or you can request to become a Project Translation Editor, where you can take control over ACF’s translations for your language.
For strings specific to the PRO version of ACF, we’ve updated our
.pot file generation to only include PRO strings, and you’ll find these files inside a new folder on our GitHub repository. Users can submit pull requests to update or add new files to that folder to be included in the next release.
To avoid ACF Free and ACF PRO having divergent translations, updates from translate.wordpress.org will not take effect in either version until each ACF release going forward.
Disable Custom Fields Editing on a Live Site
Overview
When delivering a website to a client, it may be beneficial to hide the “ACF” menu item. This prevents your client from changing or deleting fields and keeps the site running smoothly.
This doc details three methods for hiding the ACF menu:
Hiding the menu for all users on every site.
Hiding the menu for specific users on every site.
Hiding the menu on a live site while retaining functionality on the staging site.
This last option is likely the most common use case, as it allows you to continue editing fields when needed while ensuring clients can’t make any unauthorized changes.
Hide for All Users
The ACF menu item can be hidden for all users by adding the following code to the
functions.php file of the active theme. However, we recommend putting the code in an mu-plugin instead, ensuring it isn’t lost when switching themes. Please note that
__return_false is a WordPress function which simply returns false.
add_filter('acf/settings/show_admin', '__return_false');
Hide for Specific Users
The code above can be enhanced to only return false for specific users. The following code uses the WordPress function
current_user_can() to return true or false depending on the current user’s capability. Please note that
manage_options is a capability that only admins (and super admins) have by default.
add_filter('acf/settings/show_admin', 'my_acf_show_admin');
function my_acf_show_admin( $show ) {
return current_user_can('manage_options');
}
Hide on Live Site Only
Adding the code below to your
functions.php file hides the ACF menu on a live site, while retaining it on a staging or local development site.
if ( wp_get_environment_type() === 'production' ) {
// Only allow fields to be edited on development
add_filter( 'acf/settings/show_admin', '__return_false' );
}
How to Include ACF PRO in a Plugin or Theme
To include ACF PRO within your plugin or theme, first make sure you are following the rules and conditions, and then download the appropriate ACF plugin files and copy them into your plugin or theme.
We recommend using the folder
includes/acf within your codebase.
Next, use the following code as a starter to customize and include the ACF plugin in your plugin or theme.
Detecting if the ACF PRO Plugin Is Installed
A user of your plugin or theme might also be using ACF PRO for their site build. In that case, you should not proceed with bundling ACF PRO if the plugin is detected.
Use the following code to check if ACF or ACF PRO is installed:
if ( ! function_exists( 'is_plugin_active' ) ) {
include_once ABSPATH . 'wp-admin/includes/plugin.php';
}
// Check if ACF PRO is active
if ( is_plugin_active( 'advanced-custom-fields-pro/acf.php' ) ) {
// Abort all bundling, ACF PRO plugin takes priority
return;
}
If the ACF PRO plugin is detected, you should not proceed with the following instructions.
Bootstrap the Bundled ACF
First you should check if another plugin or theme active on the site is also bundling ACF PRO, if so then you shouldn’t bundle.
// Check if another plugin or theme has bundled ACF
if ( defined( 'MY_ACF_PATH' ) ) {
return;
}
Then you will need to tell your plugin or theme to load the ACF files from where they are stored in your codebase:
For a theme:
// Define path and URL to the ACF plugin.
define( 'MY_ACF_PATH', get_stylesheet_directory() . '/includes/acf/' );
define( 'MY_ACF_URL', get_stylesheet_directory_uri() . '/includes/acf/' );
For a plugin
define( 'MY_ACF_PATH', __DIR__ . '/acf/' );
define( 'MY_ACF_URL', plugin_dir_url( __FILE__ ) . 'acf/' );
Then you will need to tell ACF that the codebase lives somewhere else:
// Include the ACF plugin.
include_once( MY_ACF_PATH . 'acf.php' );
// Customize the URL setting to fix incorrect asset URLs.
add_filter('acf/settings/url', 'my_acf_settings_url');
function my_acf_settings_url( $url ) {
return MY_ACF_URL;
}
Detecting if the free ACF Plugin Is Installed
If the free ACF plugin is installed on the site, as users often want to use ACF themselves without realizing another plugin has bundled ACF PRO, we need to ensure they can still use it.
This involves checking if the plugin is activated, and then deactivating ACF free and showing a notice to the user that your product and ACF free can’t be active at the same time.
The ACF plugin cannot be activated at the same time as Third-Party Product and has been deactivated. Please keep ACF installed to allow you to use ACF functionality.
Advanced
This example uses the acf/load_value filter to reorder the repeater field when it is loaded from the database. This allows the value to be modified for both the front and backend and also allows the get_sub_field and the_sub_field functions to work.
Please note that during this filter, the repeater field $value does not contain nice field names but instead uses the sub field’s key. This is visible when populating the $row variable.
functions.php
function my_acf_load_value( $value, $post_id, $field ) {
// vars
$order = array();
// bail early if no value
if( empty($value) ) {
return $value;
}
// populate order
foreach( $value as $i => $row ) {
$order[ $i ] = $row['field_55121d86dd2f6'];
}
// multisort
array_multisort( $order, SORT_DESC, $value );
// return
return $value;
}
add_filter('acf/load_value/name=scores', 'my_acf_load_value', 10, 3);
.
How it works
The array_multisort function uses a “snapshot” array (
$row in above examples) to compare and reorder the
$value array. This function is not limited to 1 “snapshot” array. In fact, you can use multiple $column variables to sort the data.
Therefore, it is possible to order by one sub field and then by another (ID and Name).
There are a few options for the sorting direction, these are:
SORT_ASC,
SORT_DESC,
SORT_REGULAR,
SORT_NUMERIC,
SORT_STRING.
Please read more about this function here: http://php.net/manual/en/function.array-multisort.php
Sort a Repeater Field
This article will cover how to sort a repeater field based on it’s sub field values using a function called array_multisort().
Getting started
The following examples assume a repeater field exists containing 2 sub field; ID (number field) and Name (text field). This repeater field is illustrated below. For the purpose of these examples, we will sort the repeater rows based on the ID, however, the same code could be used in a more ‘real’ situation such as order by name, age, etc.
In both examples, the before and after $value will look the same.
#gallery-1 {
margin: auto;
}
#gallery-1 .gallery-item {
float: left;
margin-top: 10px;
text-align: center;
width: 50%;
}
#gallery-1 img {
border: 2px solid #cfcfcf;
}
#gallery-1 .gallery-caption {
margin-left: 0;
}
/* see gallery_shortcode() in wp-includes/media.php */
Field
Value
Examples
Basic
This example uses the get_field function to simply load an array of repeater field data, which is then sorted and looped through. Please note that the get_sub_field and the_sub_field functions will not work in this loop.
$row ) {
$order[ $i ] = $row['id'];
}
/*
$order should look like this:
Array (
[0] => 3
[1] => 2
[2] => 4
[3] => 1
)
*/
// multisort
array_multisort( $order, SORT_DESC, $repeater );
// loop through repeater
if( $repeater ): ?>
$row ): ?>
.
Advanced
This example uses the acf/load_value filter to reorder the repeater field when it is loaded from the database. This allows the value to be modified for both the front and backend and also allows the get_sub_field and the_sub_field functions to work.
Please note that during this filter, the repeater field $value does not contain nice field names but instead uses the sub field’s key. This is visible when populating the $row variable.
functions.php
function my_acf_load_value( $value, $post_id, $field ) {
// vars
$order = array();
// bail early if no value
if( empty($value) ) {
return $value;
}
// populate order
foreach( $value as $i => $row ) {
$order[ $i ] = $row['field_55121d86dd2f6'];
}
// multisort
array_multisort( $order, SORT_DESC, $value );
// return
return $value;
}
add_filter('acf/load_value/name=scores', 'my_acf_load_value', 10, 3);
.
How it works
The array_multisort function uses a “snapshot” array (
$row in above examples) to compare and reorder the
$value array. This function is not limited to 1 “snapshot” array. In fact, you can use multiple $column variables to sort the data.
Therefore, it is possible to order by one sub field and then by another (ID and Name).
There are a few options for the sorting direction, these are:
SORT_ASC,
SORT_DESC,
SORT_REGULAR,
SORT_NUMERIC,
SORT_STRING.
Please read more about this function here: http://php.net/manual/en/function.array-multisort.php
How to Update
This guide shows how to update the Advanced Custom Fields and Advanced Custom Fields PRO plugins on your website. Updates can be applied by either of the two methods shown below.
One Click Update
Versions of ACF 6.3.8 and later, and any version of ACF hosted on WP Engine or Flywheel, can be updated via the ‘Plugins’ page found in your WordPress website admin area. Updates will appear when available and can be applied by clicking the update now button.
Versions of ACF prior to 6.3.8 should be updated via a 1-time download to ensure you have the latest genuine version of the plugin. Once complete, plugin updates will appear in the WordPress admin as usual.
Updating ACF PRO
This method is also available for ACF PRO, but only when an active license is present. The license key can be entered on the ‘ACF -> Updates’ admin page.
If your license has not been activated and an update is available, you will be notified when viewing the ‘Plugins’ page. For more information, please see our guide to activating ACF PRO.
Manual Update
You may also apply plugin updates manually through the ‘Plugins’ page in the WordPress admin. Click Add New Plugin, and then Upload Plugin to start the process. The new version will overwrite the old, while leaving your fields and settings intact. Download the latest zip of the Advanced Custom Fields plugin files here, and the ACF PRO plugin files from your account.
Plugin updates can also be applied by copying and pasting the plugin files into your
'wp-content/plugins‘ folder. There is no loss or change to data whilst modifying the plugin’s files, making it safe to delete and re-upload the plugin folder.
Notes
Some updates may trigger a prompt to upgrade the database. The logic to check if a database upgrade is required runs in the admin area after a new version number is detected and is therefore fully compatible with both the update methods listed above.
Save
Including ACF Within a Plugin or Theme
Introduction
The Advanced Custom Fields plugin is a powerful tool for developing bespoke websites and web-apps. Although designed primarily for individual use, it may also be used as a framework by both plugin and theme authors to power their free and premium products.
This guide outlines the rules and terms for including ACF within your plugin or theme.
Rules
We do not allow bundling ACF or ACF PRO inside your own product as is, so ACF can be used by your users. It is should only be used to allow you to create fields and other ACF features required for your product.
When talking about a WordPress product, we can consider it as either a plugin, theme, premium plugin, or premium theme.
Our rules differ based on if your product is considered free or premium, and not whether it is a plugin or theme.
Please see the following table of rules that govern the inclusion of our plugins.
ACF
ACF PRO
Include in a free plugin
✅
❌
Include in a free theme
✅
❌
Include in a premium plugin
✅
✉️
Include in a premium theme
✅
✉️
Include in an “ACF” plugin
❌
❌
Share license key information
❌
❌
Use as a selling point
❌
❌
If you would like to include ACF PRO in your premium theme or plugin, please contact us to discuss the right subscription for you.
Marketing
Although we love the idea of you empowering your customers with intuitive publishing controls, we don’t love the idea of you advertising this to boost sales.
When including ACF PRO within your premium theme or premium plugin, please do not advertise this in your marketing material. For example, stay away from messages like “This theme also includes ACF PRO – normally $$$ – for free!”
Fields
You should provide field definitions (PHP or JSON) inside your plugin and disable the ACF menu. Your users should not be able to create new field groups or fields.
Support
Your customers shouldn’t contact us directly for support. They should contact you, and then you can contact us for help if you find there’s a problem with ACF.
Notes about “ACF” plugins
We do not allow ACF or ACF PRO to be included in any type of “ACF” extension or plugin. For example, a plugin named “ACF PRO Kit” that extends the plugin with extra features may not include ACF PRO. In this case, the “ACF PRO Kit” plugin should require ACF PRO to be installed.
Learn how to include ACF or ACF PRO in a theme or plugin.
Inline Editing for ACF Blocks
ACF Inline Editing is a groundbreaking feature for ACF Blocks, allowing authors to edit block data by clicking directly on what they want to edit in the block preview area. This functionality requires no extra code or JavaScript from the block creator, making ACF Blocks much easier to edit and similar to native Gutenberg blocks.
Types of Inline Editing
There are two main kinds of inline editing:
Text Editable: Offers the most native-like feel, allowing editors to type directly into an element within the block preview area. This functionality is primarily available for Text and Text Area fields.
Toolbar Editable: Used for most other supported field types. When a field is clicked, a pop-up toolbar appears where the content can be edited using the familiar ACF field editing UI.
Field Type Support
Here’s a breakdown of what editing experiences are available for each field type. We plan to improve the inline editing experience for fields that have subfields like the Repeater. The Expanded Editing Panel was introduced in ACF 6.6 to replace ‘Edit’ mode for blocks and to improve on the sidebar editing experience.
Field Type
Text Editing
Toolbar Editing
Expanded Editing Panel
Text
✅
✅
✅
Text Area
✅
✅
✅
Number
❌
✅
✅
Range
❌
✅
✅
Email
❌
✅
✅
URL
❌
✅
✅
Password
❌
✅
✅
Image
❌
✅
✅
File
❌
✅
✅
WYSIWYG Editor
❌
✅
✅
oEmbed
❌
✅
✅
Gallery
❌
✅
✅
Select
❌
✅
✅
Checkbox
❌
✅
✅
Radio Button
❌
✅
✅
Button Group
❌
✅
✅
True/False
❌
✅
✅
Link
❌
✅
✅
Page Link
❌
✅
✅
Post Object
❌
✅
✅
Relationship
❌
✅
✅
Taxonomy
❌
✅
✅
User
❌
✅
✅
Google Map
❌
✅
✅
Date Picker
❌
✅
✅
Date Time Picker
❌
✅
✅
Time Picker
❌
✅
✅
Color Picker
❌
✅
✅
Message
❌
❌
✅
Accordion
❌
❌
✅
Tab
❌
❌
✅
Group
❌
✅
✅
Repeater
❌
❌
✅
Flexible Content
❌
❌
✅
Clone
❌
❌
✅
Note: Inline Editing is only available to ACF Blocks using version 3. Fields with sub-fields (Repeater, Flexible Content) are not directly editable inline, but the Expanded Editing Panel is always available.
Next Steps
Next, we’ll look at how to enable Inline Editing for your ACF Blocks, either automatically or customizing your block’s render PHP template.
Next: Enabling Inline Editing
Installing the Free ACF Plugin
For instructions on how to install the ACF PRO plugin, please see this guide.
The methods outlined below will work on any host. In addition, WordPress sites hosted on WP Engine or Flywheel can use the process outlined here.
Method 1: wp-admin upload
Download Advanced Custom Fields from https://advancedcustomfields.com/latest/.
Log in to your WP install.
From the Administration Screen, click on the Plugin menu.
Under Plugins, click the Add New Plugin sub menu.
Click Upload Plugin at the top of the page.
Click Choose File and select the file you downloaded earlier.
Click Install Now, and then Activate Plugin.
After installation, you will find a new menu item, “ACF”.
Method 2: FTP
Download the Advanced Custom Fields plugin.
Upload
advanced-custom-fields to the
/wp-content/plugins/ directory.
Activate the plugin through the “Plugins” menu in WordPress.
After installation, you will find a new menu item, “ACF”.
Method 3: WP-CLI
Open a terminal.
Navigate to the root of your WordPress install.
Use the
wp plugin command to install ACF.
Activate the plugin via WP-CLI or in the WordPress admin.
Make sure to use the commands to install from a local or remote zip file, rather than installing via the plugin’s slug. Installing via the plugin’s slug will not install ACF.
The command below will download the latest version of ACF from our servers and then activate it on your site. To install a local zip file, replace
https://advancedcustomfields.com/latest/ with the path to your file.
wp plugin install --activate https://advancedcustomfields.com/latest/
Method 4: Composer
Add the ACF repository to your
composer.json file.
"repositories": [
{
"type":"composer",
"url":"https://composer.advancedcustomfields.com"
}
]
From the CLI, require ACF using the following command:
composer require wpengine/advanced-custom-fields
The steps outlined above will install the free version of ACF with Composer. Please see Installing ACF With Composer for more information, including how to use version constraints, installing ACF as a must-use plugin, and customizing install locations.
ACF PRO can also be installed with Composer, as detailed in Installing ACF PRO with Composer.
Installing on WP Engine and Flywheel Hosted Websites
The above methods will work for all WordPress sites. The following steps will also work for WordPress sites hosted on WP Engine and Flywheel.
Log in to your WP install.
From the Administration ScreenPanels, click on the Plugins Menu.
Under Plugins, click the “Add New Plugin” sub menu.
Search for “Advanced Custom Fields”.
Find the Advanced Custom Fields plugin by WP Engine in the search results, and click Install.
Activate the plugin through the “‘Plugins”’ menu in WordPress.
After installation, you will find a new menu item, “ACF”.
Installing ACF and ACF PRO
Ready to take your WordPress sites to the next level? The ACF WordPress plugin gives you complete control over your edit screens, custom field data, and much more. In this video, we’ll guide you through the process of installing ACF and unlocking a world of possibilities for your WordPress websites.
The free version of ACF is a game changer for any WordPress developer. Over 30 field types are just the start. Directly from the plugin’s UI, you can create bidirectional relationships, set up conditional logic, and create custom post types and taxonomies. Power up your WordPress sites with developer-friendly functions, and further customize the experience with filters and actions.
Upgrading to ACF PRO
ACF PRO extends WordPress even further, offering advanced field types like Repeater, Flexible Content, Clone, and Gallery fields, with step-by-step tutorials to help you get started right away. ACF PRO also includes the Options Page UI, simplifying the creation of new admin pages that save data globally to display anywhere on the site, and ACF Blocks, giving you the power to create WordPress compatible blocks in a PHP framework.
Installing ACF and ACF PRO
Install ACF by downloading the latest zip of the plugin and navigating to “Plugins > Add New Plugin” in your WordPress admin. Click Upload Plugin, select the zip file, and then click Install Now. Finally, click Activate Plugin. After activation, click ACF in the admin menu and start building custom field groups.
The process to upgrade to ACF PRO takes just a few minutes, but many developers use it on every single build and find it less time consuming to install ACF PRO with Composer.
Install ACF Today
Ready to take the first step in unlocking the full potential of your WordPress site? Download ACF today and start building better, richer WordPress websites.
Next: Getting Started with ACF Custom Fields & Field Groups
Installing ACF PRO With Composer
ACF PRO can be installed using Composer. Please see Installing ACF With Composer for details on installing the free ACF plugin with Composer.
Generate API Credentials
Visit My Account, navigate to the Licenses tab, and then click Install using Composer for your license.
This will reveal a panel where you can generate an
auth.json credentials file to be used with Composer.
The
auth.json file is made up of a username and password field. The username and password are used by Composer to authenticate to our API with HTTP basic authentication.
The username is the ACF PRO license key, and the password is the site URL (including https:// or http://) that the license is active for.
{
"http-basic": {
"connect.advancedcustomfields.com": {
"username": "Dvl2P9fLovYy2oJkdYOPiCrHXcRgGrmk9WR62HdErPasPsV43COx0anwTizc9XFrY8qysqqZ",
"password": "https://mysite.com"
}
}
}
The password can be an existing site that is already active for the license key, and there’s a dropdown of already activated sites that can be selected and will automatically populate the ‘password’ field in the sample
auth.json code. Alternatively, you can enter a new site URL in the textbox on the right to populate the
auth.json. This site URL will be activated for the license in your account upon Composer installation. Any activation of a new URL will be subject to the activation limits for the license.
If you are using Composer to install your plugins in an automated way for new builds where you don’t know the final site URL, we recommend using an existing production URL that has been activated for the license key.
We also recommend that you define your license key in code. Otherwise, you’ll have to activate ACF PRO on each site by manually entering the license key in the ‘Updates’ page of ACF’s admin. You’ll be unable to use the PRO features of ACF until a license key has been entered, either programmatically or manually.
Using Version Control
If you are using a version control system for your site, we recommend you add the
auth.json file to your ignore file, e.g.,
.gitignore. This prevents the license key from being included in the repository.
Create the
.gitignore file in the root of your local Git, if you don’t already have one:
touch .gitignore
Next, add a rule to ignore the
auth.json file:
# Exclude auth.json from Git repo
auth.json
Make sure you create the
auth.json file on the live server when you deploy your site if you’ve included it in your
.gitignore.
Developers working with the site locally will also have to create the
auth.json file and add the license key to it before running the Composer install command.
Add Our Repository
Add our repository to your
composer.json file:
"repositories": [
{
"type":"composer",
"url":"https://connect.advancedcustomfields.com"
}
]
Install the Plugin
From the CLI, require ACF PRO using the following command:
composer require wpengine/advanced-custom-fields-pro
#composer-require:before {content: "$"; margin-right: 10px; }
Version Constraints
You can use any Composer version constraints, or specify the exact version of the plugin:
"require": {
"wpengine/advanced-custom-fields-pro": "6.3.1.2"
}
Customizing Install Locations
We use composer/installers to automatically install our plugin package to
wp-content/plugins/. However, you can customize the install location by adding the following to your
composer.json file:
"extra": {
"installer-paths": {
"wp-content/plugins/{$name}/": ["type:wordpress-plugin"]
}
}
Installing as an MU Plugin
If you prefer to install ACF PRO as a must use plugin (mu-plugin), to ensure it will always be loaded by WordPress and can’t be deactivated from the admin dashboard like a normal plugin, you can alter the install location by adding the following to your
composer.json file:
"extra": {
"installer-paths": {
"wp-content/mu-plugins/{$name}/": ["wpengine/advanced-custom-fields-pro"]
}
}
However, plugin directories inside the
mu-plugin directory will not be loaded automatically by WordPress, so you would need to require it manually with an
acf.php file in the
mu-plugin directory root:
'bar' )); function.
var postID = acf.get('post_id');
var acfVersion = acf.get('acf_version');
var foo = acf.get('bar');
set
acf.set(name, value)
Sets a value for later use with
acf.get(). Returns the acf object for chaining.
var value = 'bar';
acf.set('foo', value);
has
acf.has(name)
Returns true if data exists for the given name.
if( acf.has('foo') ) {
// do something
}
parseArgs
acf.parseArgs(args, defaults)
Similar to the WP function wp_parse_args(), this is a generic utility for merging together an object of arguments and an object of default values.
// var maybeArgs = { ... }
var args = acf.parseArgs(maybeArgs, {
foo: 'bar',
html: '',
});
// console.log( args.foo );
__
acf.__(text)
Returns the translation of text. If there is no translation, the original text is returned. Translation data is registered in PHP and passed to JS through an inline script in the head. You can register translations in PHP by using the
acf_localize_text() function.
acf_localize_text(array(
'Select thing' => __('Select thing', 'my-textdomain')
));
var text = acf.__('Select thing');
addAction
acf.addAction(action, callback, priority, context)
Similar to the WP function add_action(), this is used to listen for a specific action and register a callback function.
acf.addAction('new_field', function( field ){
field.$el.addClass('i-was-here');
});
addFilter
acf.addFilter(filter, callback, priority, context)
Similar to the WP function add_filter(), this is used to listen for a specific filter and register a callback function to modify the first argument.
acf.addFilter('select2_args', function( options, $select ){
options.foo = 'bar';
return options;
});
doAction
acf.doAction(action, [arg1, arg2, arg3, ...])
Similar to the WP function do_action(), this is used to trigger an action. Any callbacks registered for this action will be triggered.
acf.doAction('my_action', dataObject, someOtherVariable);
applyFilters
acf.applyFilters(filter, [arg1, arg2, arg3, ...])
Similar to the WP function apply_filters(), this is used to apply a filter. Any callbacks registered for this filter will be called to modify the first argument.
var foo = acf.applyFilters('my_filter', 'bar');
findField
acf.findField( key )
Returns a field jQuery object for a given field key.
var $field = acf.findField('field_123');
$field.addClass('my-class')
getField
acf.getField( key )
Returns a field instance for a given field key or jQuery element.
var field = acf.getField('field_123');
field.$el.addClass('my-class')
findFields
acf.findFields( args )
Returns a collection of jQuery objects for the given args.
// available args
var args = {
key: '', // The field key (field_123)
name: '', // The field name (my_field)
type: '', // The field type (image, text)
is: '', // jQuery selector (:visible)
parent: false, // jQuery element to search within
sibling: false, // jQuery element to search alongside
limit: false, // limit the number of jQuery elements returned
};
// example
var $fields = acf.findFields({
type: 'image'
});
getFields
acf.getFields( args )
Returns an array of field instances for the given args (see acf.findFields for list of args) or a collection of jQuery elements.
var fields = acf.getFields({
type: 'image'
});
Actions
Actions are called at specific times during a page to allow for customisation. Below is a list of available JS actions somewhat in order of execution that you can hook into using the
acf.addAction() function.
✋ If using the “pre 5.7” function acf.add_action(), please be aware that any field instance parameter documented bellow will appear as a jQuery element for compatibility. This change is discussed in more detail later in the Compatibility section.
prepare
Triggered from an inline script in the footer allowing you to perform customisation to the page as early as possible (before the
$(document).ready event).
acf.addAction('prepare', function(){
$('#my-element').hide();
});
ready
Triggered during the
$(document).ready() event.
acf.addAction('ready', function(){
$('#my-element').hide();
});
load
Triggered during the
$(window).load() event.
acf.addAction('load', function(){
$('#my-element').hide();
});
resize
Triggered during the
$(window).resize() event.
acf.addAction('resize', function(){
$('#my-element').resizeWidth();
});
unload
Triggered during the
$(window).unload() event.
acf.addAction('unload', function(){
$('#my-element').remove();
});
append
Triggered when new HTML is added to the page such as within a media modal popup. The jQuery element being appended is passed as a parameter.
acf.addAction('append', function( $el ){
$el.find('.my-element').hide();
});
remove
Triggered when HTML is removed from the page. For example, when removing a repeater row. The jQuery element being removed is passed as a parameter.
acf.addAction('remove', function( $el ){
$el.find('.my-element').doThing();
});
new_field
Triggered when a field is first initialised (either during “prepare” or “append”). This action is recommended over other ‘field’ actions if you wish to customize a field. This field action can also be targeted using a specific type, name or key.
var myCallback = function( field ){
// add class to this field
field.$el.addClass('my-class');
// add click event to this field's button
field.on('click', 'button', function( e ){
e.preventDefault();
alert('Special event');
});
};
acf.addAction('new_field', myCallback);
acf.addAction('new_field/type=image', myCallback); // image fields
acf.addAction('new_field/name=hero_image', myCallback); // fields named "hero_image"
acf.addAction('new_field/key=field_123456', myCallback); // field with key "field_123456"
prepare_field
Triggered during the “prepare” action for each field. This field action can also be targeted using a specific type, name or key.
acf.addAction('prepare_field', myCallback); // all fields
acf.addAction('prepare_field/type=image', myCallback); // image fields
acf.addAction('prepare_field/name=hero_image', myCallback); // fields named "hero_image"
acf.addAction('prepare_field/key=field_123456', myCallback); // field with key "field_123456"
ready_field
Triggered during the “ready” action for each field. This field action can also be targeted using a specific type, name or key.
acf.addAction('ready_field', myCallback); // all fields
acf.addAction('ready_field/type=image', myCallback); // image fields
acf.addAction('ready_field/name=hero_image', myCallback); // fields named "hero_image"
acf.addAction('ready_field/key=field_123456', myCallback); // field with key "field_123456"
load_field
Triggered during the “load” action for each field. This field action can also be targeted using a specific type, name or key.
acf.addAction('load_field', myCallback); // all fields
acf.addAction('load_field/type=image', myCallback); // image fields
acf.addAction('load_field/name=hero_image', myCallback); // fields named "hero_image"
acf.addAction('load_field/key=field_123456', myCallback); // field with key "field_123456"
append_field
Triggered during the “append” action for each field. This field action can also be targeted using a specific type, name or key.
acf.addAction('append_field', myCallback); // all fields
acf.addAction('append_field/type=image', myCallback); // image fields
acf.addAction('append_field/name=hero_image', myCallback); // fields named "hero_image"
acf.addAction('append_field/key=field_123456', myCallback); // field with key "field_123456"
remove_field
Triggered when a field is removed. This field action can also be targeted using a specific type, name or key.
acf.addAction('remove_field', myCallback); // all fields
acf.addAction('remove_field/type=image', myCallback); // image fields
acf.addAction('remove_field/name=hero_image', myCallback); // fields named "hero_image"
acf.addAction('remove_field/key=field_123456', myCallback); // field with key "field_123456"
hide_field
Triggered when a field is hidden. This field action can also be targeted using a specific type, name or key.
acf.addAction('hide_field', myCallback); // all fields
acf.addAction('hide_field/type=image', myCallback); // image fields
acf.addAction('hide_field/name=hero_image', myCallback); // fields named "hero_image"
acf.addAction('hide_field/key=field_123456', myCallback); // field with key "field_123456"
show_field
Triggered when a hidden field is shown. This field action can also be targeted using a specific type, name or key.
acf.addAction('show_field', myCallback); // all fields
acf.addAction('show_field/type=image', myCallback); // image fields
acf.addAction('show_field/name=hero_image', myCallback); // fields named "hero_image"
acf.addAction('show_field/key=field_123456', myCallback); // field with key "field_123456"
disable_field
Triggered when a field is disabled (conditional logic). This field action can also be targeted using a specific type, name or key.
acf.addAction('disable_field', myCallback); // all fields
acf.addAction('disable_field/type=image', myCallback); // image fields
acf.addAction('disable_field/name=hero_image', myCallback); // fields named "hero_image"
acf.addAction('disable_field/key=field_123456', myCallback); // field with key "field_123456"
enable_field
Triggered when a disabled field is enabled (conditional logic). This field action can also be targeted using a specific type, name or key.
acf.addAction('enable_field', myCallback); // all fields
acf.addAction('enable_field/type=image', myCallback); // image fields
acf.addAction('enable_field/name=hero_image', myCallback); // fields named "hero_image"
acf.addAction('enable_field/key=field_123456', myCallback); // field with key "field_123456"
invalid_field
Triggered when a field value fails validation. This field action can also be targeted using a specific type, name or key.
acf.addAction('invalid_field', myCallback); // all fields
acf.addAction('invalid_field/type=image', myCallback); // image fields
acf.addAction('invalid_field/name=hero_image', myCallback); // fields named "hero_image"
acf.addAction('invalid_field/key=field_123456', myCallback); // field with key "field_123456"
valid_field
Triggered when an invalid field value passes validation. This field action can also be targeted using a specific type, name or key.
acf.addAction('valid_field', myCallback); // all fields
acf.addAction('valid_field/type=image', myCallback); // image fields
acf.addAction('valid_field/name=hero_image', myCallback); // fields named "hero_image"
acf.addAction('valid_field/key=field_123456', myCallback); // field with key "field_123456"
date_picker_init
Called when a date picker has been initialized. Added in v5.5.8
acf.addAction('date_picker_init', function( $input, args, field ){
// $input (jQuery) text input element
// args (object) args given to the datepicker function
// field (object) field instance
});
date_time_picker_init
Called when a date time picker has been initialized. Added in v5.5.8
acf.addAction('date_time_picker_init', function( $input, args, field ){
// $input (jQuery) text input element
// args (object) args given to the datepicker function
// field (object) field instance
});
time_picker_init
Called when a time picker has been initialized. Added in v5.5.8
acf.addAction('time_picker_init', function( $input, args, field ){
// $input (jQuery) text input element
// args (object) args given to the datepicker function
// field (object) field instance
});
select2_init
Called when a Select2 element has been initialized. Added in v5.5.8
acf.addAction('select2_init', function( $select, args, settings, field ){
// $select (jQuery) select element
// args (object) args given to the select2 function
// settings (object) settings given to the acf.select2 function
// field (object) field instance
});
wysiwyg_tinymce_init
Called when a WYSIWYG tinymce element has been initialized. Added in v5.5.8
acf.addAction('wysiwyg_tinymce_init', function( ed, id, mceInit, field ){
// ed (object) tinymce object returned by the init function
// id (string) identifier for the tinymce instance
// mceInit (object) args given to the tinymce function
// field (object) field instance
});
wysiwyg_quicktags_init
Called when a WYSIWYG quickktags element has been initialized. Each tinymce instance can also contain a ‘text’ edit mode that shows basic ‘quicktag’ buttons. Added in v5.5.8
acf.addAction('wysiwyg_quicktags_init', function( qtag, id, qtInit, field ){
// qtag (object) quick tag object returned by the init function
// id (string) identifier for the qtag instance
// qtInit (object) args given to the quick tag function
// field (object) field instance
});
google_map_init
Called when a Google Map element has been initialized. Added in v5.5.11
acf.addAction('google_map_init', function( map, marker, field ){
// map (object) google map object returned by the google.maps.Map() function
// marker (object) marker object returned by the google.maps.Marker() function
// field (object) field instance
});
Filters
Filters are called at specific times to allow for customisation. Below is a list of available JS filters that you can hook into using the
acf.addFilter() function.
✋ If using the “pre 5.7” function acf.add_filter(), please be aware that any field instance parameter documented bellow will appear as a jQuery element for compatibility. This change is discussed in more detail later in the Compatibility section.
validation_complete
This filter allows the validation JSON response to be customized. Called after AJAX validation is complete but before errors are shown or the form is submitted.
acf.add_filter('validation_complete', function( json, $form ){
// check errors
if( json.errors ) {
// do something
}
// return
return json;
});
wysiwyg_tinymce_settings
This filter allows the tinyMCE settings to be customized for each WYSIWYG field. Called before the tinyMCE instance is created.
acf.add_filter('wysiwyg_tinymce_settings', function( mceInit, id, field ){
// do something to mceInit
// return
return mceInit;
});
wysiwyg_quicktags_settings
This filter allows the quicktags settings to be customized for each WYSIWYG field. Called before the text instance is created.
acf.add_filter('wysiwyg_quicktags_settings', function( qtInit, id, field ){
// do something to qtInit
// return
return qtInit;
});
date_picker_args
This filter allows the date picker settings to be customized for each date picker field. Called before the date picker instance is created. A full list of settings can be found here: https://api.jqueryui.com/datepicker/
acf.add_filter('date_picker_args', function( args, field ){
// do something to args
// return
return args;
});
date_time_picker_args
This filter allows the date time picker settings to be customized for each date time picker field. Called before the date time picker instance is created. A full list of settings can be found here: http://trentrichardson.com/examples/timepicker/
acf.add_filter('date_time_picker_args', function( args, field ){
// do something to args
// return
return args;
});
time_picker_args
This filter allows the time picker settings to be customized for each time picker field. Called before the time picker instance is created. A full list of settings can be found here: http://trentrichardson.com/examples/timepicker/
acf.add_filter('time_picker_args', function( args, field ){
// do something to args
// return
return args;
});
google_map_args
This filter allows the google maps settings to be customized for each google maps field. Called before the map instance is created.
acf.add_filter('google_map_args', function( args, field ){
// do something to args
// return
return args;
});
google_map_marker_args
This filter allows the google maps marker settings to be customized for each google maps field. Called before the map instance is created.
acf.add_filter('google_map_marker_args', function( args, field ){
// do something to args
// return
return args;
});
google_map_result
This filter allows the google maps field value to be modified after an API request has been made and a result has been returned.
acf.add_filter('google_map_result', function( result, geocoderResult, map, field ){
// do something to result
// return
return result;
});
select2_args
This filter allows the select2 settings to be customized for each select field before the select2 instance is created.
acf.add_filter('select2_args', function( args, $select, settings, field, instance ){
// do something to args
// return
return args;
});
select2_escape_markup
This filter allows the result of default HTML escaping for select2 templates and selections to be modified. Available since ACF 6.2.8.
acf.add_filter('select2_escape_markup', function( escaped_value, original_value, $select, settings, field, instance ){
// do something to the original_value to override the default escaping, then return it.
// this value should still have some kind of escaping for security, but you may wish to allow specific HTML.
if (field.data( 'name' ) == "select2_with_html") {
return my_custom_escaping_method( original_value );
}
// return
return escaped_value;
});
select2_ajax_data
This filter allows the data sent in an ajax request to be customized for each select field.
acf.add_filter('select2_ajax_data', function( data, args, $input, field, instance ){
// do something to data
// return
return data;
});
select2_ajax_results
This filter allows the data returned from an ajax request to be customized for each select field.
acf.add_filter('select2_ajax_results', function( json, params, instance ){
// do something to json
// return
return json;
});
color_picker_args
This filter allows the color picker (wpColorPicker) settings to be customized for each color picker field. This filter is called before the wpColorPicker instance is created. Added in v 5.3.6
acf.add_filter('color_picker_args', function( args, field ){
// do something to args
args.palettes = ['#5ee8bf', '#2f353e', '#f55e4f']
// return
return args;
});
Models
Models are the heart of ACF functionality. The acf.Model function provides convenient scaffolding for creating new instances to store data, add event listeners, and perform logic. A model can be created as a “once off” instance, or extended into a “class” for repeated use (such as the acf.Field class discussed later).
The following is a contrived example, but it demonstrates defining a model with a custom method, setting an attribute, and firing an event keyed to changes in that specific attribute.
var sidebar = new acf.Model({
wait: 'ready',
data: {
color: '#ffffff'
},
events: {
'click .select-color': 'onClick'
},
initialize: function(){
this.$el = $('#sidebar');
}
onClick: function( e, $el ){
// get color from data attribute on '.select-color' element
this.set('color', $el.data('color'));
// render
this.render();
},
render: function(){
this.$el.css('background-color', this.get('color'));
}
});
// interact directly with the sidebar variable
var color = sidebar.get('color');
All models and those that extend the base model have access to the following properties and functions.
cid
model.cid
A special property of models, the cid or “client id” is a unique identifier automatically assigned to all models when they’re first created.
var instance = new acf.Model();
var id = instance.cid; // acf-123
data
model.data
The data object used by get(), set() and has() to store data on the instance.
var instance = new acf.Model({
data: {
color: '#ffffff',
active: false
}
});
events
model.events
A list of “jQuery events” that will be bound to methods in the format {“event selector” : “callback”}.
The callback is scoped to the instance and the jQuery element is passed through as a second parameter.
var instance = new acf.Model({
events: {
'change': 'onChange',
'change input[type="text"]': 'onChangeText',
},
onChange: function(e, $el){
e.preventDefault();
var val = $el.val();
// do something
},
onChangeText: function(e, $el){
// do something for just text inputs and then call the normal change callback
this.onChange(e, $el);
}
});
actions
model.actions
A list of actions that will be bound to methods in the format {“name” : “callback”}.
var instance = new acf.Model({
actions: {
'append': 'onAppend',
},
onAppend: function($el){
// $el has been added to the DOM.
}
});
filters
model.filters
A list of filters that will be bound to methods in the format {“name” : “callback”}.
var instance = new acf.Model({
filters: {
'things': 'filterThings',
},
filterThings: function( things ){
things.push('zar');
return things;
}
});
var things = acf.applyFilters('things', ['foo', 'bar']);
priority
model.priority
The priority used for the above actions and filters. Defaults to 10.
var instance = new acf.Model({
actions: {
'ready': 'onReady',
},
priority: 99,
onReady: function(){
// runs after other 'ready' callbacks
}
});
wait
model.wait
Delays initialization until a specific action such as ‘ready’ or ‘load’.
var instance = new acf.Model({
wait: 'ready',
initialize: function(){
// runs during the 'ready' action when all elements have been rendered
this.$el = $('#some-element');
}
});
initialize
model.initialize()
The “constructor” function which is called when creating an instance of a model.
var instance = new acf.Model({
initialize: function(){
this.doSomething();
}
});
get
model.get(name)
Returns a value from the instance data.
var foo = instance.get('foo');
set
model.set(name, value)
Stores a value in the instance data.
var value = 'bar';
instance.set('foo', value);
has
model.has(name)
Returns true if data exists for the given name.
if( instance.has('foo') ) {
// do something
}
on
model.on(event, selector, callback) or model.on(event, callback)
Adds an event listener to the instance.
instance.on('change', 'input[type="text"]', function( e ){
// similar to jQuery, "this" is scoped to the DOM element.
// get input val
var val = $(this).val();
instance.doSomething( val );
});
$
model.$(selector)
Runs the jQuery.$ function scoped to model.$el
var $button = instance.$('.my-button');
$el
model.$el
The jQuery element for this instance used for adding events.
instance.$el.addClass('new-class');
extend
model.extend(args)
The acf.Model class can be extended to create your own class. Take the following example.
var Person = acf.Model.extend({
data: {
firstName: '',
lastName: ''
},
// the 'changed' and 'changed:name' events trigger when changing data
events: {
'changed': 'render'
},
setup: function( props ){
// store data
$.extend(this.data, props);
// create element
this.$el = $('');
},
initialize: function(){
this.show();
this.render();
},
show: function(){
$('body').append( this.$el );
},
hide: function(){
this.$el.remove();
},
render: function(){
this.$el.html( this.get('firstName') + ' ' + this.get('lastName') );
}
});
var person1 = new Person({ firstName: 'John', lastName: 'Smith' });
var person2 = new Person({ firstName: 'Jane', lastName: 'West' });
person2.set('lastName', 'Smith');
acf.Field
We use models to bring our fields to life. Each field is given an instance of the acf.Field model allowing a uniform way to interact with fields.
The acf.Field model extends from the acf.Model model meaning that it inherits all the properties and functions mentioned above.
The following is a contrived example, but it demonstrates how to interact with a field instance.
// get the field instance
var field = acf.getField('field_123456');
// show error if no value
if( !field.val() ) {
field.showError('Please add a value');
}
// add an event
field.on('click', '.disable-button', function( e ){
field.disable();
});
// add class
field.$el.addClass('my-field');
type
field.type
The field type name (“image”, “text”, etc).
val
field.val([value])
Returns the field’s value or sets a new value if one is given.
if( !field.val() ) {
field.val('Default value');
}
$control
field.$control()
Some fields (such as the image field) use a “control” element to wrap the “input” and pass data attributes. This function returns this “control” jQuery element.
field.$control().addClass('customized');
$input
field.$input()
Most fields (such as the text field) use an “input” element to collect and send values. This function returns this “input” jQuery element.
field.$input().focus();
disable
field.disable()
Disables the field’s input elements.
field.disable();
enable
field.enable()
Enables the field’s input elements.
field.enable();
hide
field.hide()
Hides the field element.
field.hide();
show
field.show()
Shows the field element.
field.show();
remove
field.remove()
Removes the field from the DOM and unregisters all assigned events, actions and filters.
field.remove();
parent
field.parent()
Returns the field’s parent instance or false if no parent.
var parent = field.parent();
if( parent ) {
parent.doSomething();
}
showNotice
field.showNotice( args )
Displays a text notice within the field.
field.showNotice({
text: "Please select at least one of these items",
type: '', // warning, error, success
dismiss: true, // allow notice to be dismissed
});
removeNotice
field.removeNotice()
Removes the field’s current notice.
Events
The acf.Field model triggers custom events which can be listened to just like a jQuery change event. These events are similar to the Field Actions but allow you to listen directly to a specific field instance.
Name
Description
removeField
Triggered when a field is removed.
hideField
Triggered when a field is hidden.
showField
Triggered when a hidden field is shown.
disableField
Triggered when a field is disabled.
enableField
Triggered when a disabled field is enabled.
invalidField
Triggered when a field value fails validation.
validField
Triggered when an invalid field value passes validation.
sortstartField
Triggered when a field is being moved in the DOM.
sortstopField
Triggered when a field has finished being moved in the DOM.
The following example shows how to listen to a field event.
// get the field instance
var field = acf.getField('field_123456');
// do something on show
field.on('showField', function(){
field.doSomething();
});
extend
field.extend( props )
The acf.Field model can be extended to create your own field type “class”. This makes developing custom field type easier than ever before.
Here is an example of the URL Field class taken from the ACF source code. Please note that the class is “registered” using the
acf.registerFieldType( Field ) function which is needed for ACF to correctly select this “class” during initialization.
(function($){
var Field = acf.Field.extend({
type: 'url',
events: {
'keyup input[type="url"]': 'onkeyup'
},
$control: function(){
return this.$('.acf-input-wrap');
},
$input: function(){
return this.$('input[type="url"]');
},
initialize: function(){
this.render();
},
isValid: function(){
// vars
var val = this.val();
// url
if( val.indexOf('://') !== -1 ) {
return true;
}
// protocol relative url
if( val.indexOf('//') === 0 ) {
return true;
}
// return
return false;
},
render: function(){
// add class
if( this.isValid() ) {
this.$control().addClass('-valid');
} else {
this.$control().removeClass('-valid');
}
},
onkeyup: function( e, $el ){
this.render();
}
});
acf.registerFieldType( Field );
})(jQuery);
acf.Condition
The acf.Condition model is used to define the different types of conditional logic available for use between fields. Similar to acf.Field, this model can be extended to create new condition types.
type
condition.type
The condition’s private ID used for storage/lookup. Must be unique like “hasValue”, “hasNoValue”, etc.
operator
condition.operator
The condition’s public ID used in HTML attributes. Should best match a programatic operator like “==”, “!=”, etc.
label
condition.label
The condition’s label visible in the dropdown when selecting a conditional rule.
fieldTypes
condition.fieldTypes
An array of field types that this condition applies to. Example [‘text’, ‘textarea’].
match
condition.match(rule, field)
This function is called to determine if the condition is true or false. Must return a boolean value. See the following example taken from the “Has any value” rule.
// taken from the "Has any value" rule
{
match: function( rule, field ){
// return true if field has any value
return (field.val() ? true : false);
}
}
choices
condition.choices(fieldObject)
This function is called to return the available choices for this condition. The selected “field object” is passed through as a parameter which can be used to lookup settings (the selectEqualTo model looks up the field’s “choices” textarea setting). The function can return either an array of choices (which will result in a dropdown being created) or custom HTML.
// taken from the "EqualTo" rule
{
choices: function( fieldObject ){
return '';
}
}
// taken from the "trueFalseEqualTo" rule
{
choices: function( fieldObject ){
return [
{
id: 1,
text: 'Checked'
}
];
}
}
extend
condition.extend( props )
The acf.Condition model can be extended to create your own condition type “class”. This makes developing custom conditions super easy.
Here is an example of the lessThan class taken from the ACF source code. Please note that the class is “registered” using the
acf.registerConditionType( Condition ) function which is needed for ACF to correctly select this “class” during initialization.
(function($){
var LessThan = GreaterThan.extend({
type: 'lessThan',
operator: '<',
label: __('Value is less than'),
match: function( rule, field ){
var val = field.val();
if( val instanceof Array ) {
val = val.length;
}
return isLessThan( val, rule.value );
},
choices: function( fieldObject ){
return '';
}
});
acf.registerConditionType( LessThan );
})(jQuery);
registerConditionForFieldType
acf.registerConditionForFieldType(conditionType, fieldType)
Connects an registered condition type to a registered field type. This can be used to add basic condition types to your own custom field type.
(function($){
var Field = acf.Field.extend({
type: 'my_custom_field',
// ...
});
acf.registerFieldType( Field );
acf.registerConditionForFieldType('hasValue', 'my_custom_field');
acf.registerConditionForFieldType('hasNoValue', 'my_custom_field');
})(jQuery);
Compatibility
The acf object extends a “compatibility layer” where we keep any deprecated or changed functions and properties. This allows our library to stay organised as well as provide compatibility with existing code. The biggest changes to our library that requires backwards compatibility are those to the “hook” functions
acf.add_action() and
acf.add_filter().
Prior to version 5.7, all callbacks for Field Actions or Field Filters would receive a jQuery element parameter. This has changed in version 5.7 as these same actions now receive a field instance.
To provide backwards compatibility, we didn’t change the hook names, but we did change the function names. This allows us to apply a “compatibility layer” to the parameters depending on which function you use. To better illustrate, please look at the following backwards compatible functions.
add_action
acf.add_action(action, callback, priority, context)
An alias of
acf.AddAction() with a twist. Any action that would normally receive a field instance will receive a jQuery element.
// old: acf.add_action
acf.add_action('ready_field', function( $field ){
$field.addClass('old-way');
});
// new: acf.addAction
acf.addAction('ready_field', function( field ){
field.$el.addClass('new-way');
});
add_filter
acf.add_filter(filter, callback, priority, context)
An alias of
acf.addFilter() with a twist. Any filter that would normally receive a field instance will receive a jQuery element.
// old: acf.add_filter
acf.add_filter('color_picker_args', function( args, $field ){
// do something to the field
$field.addClass('old-way');
// return
return args;
});
// new: acf.addAction
acf.addFilter('color_picker_args', function( args, field ){
// do something to the field
field.$el.addClass('new-way');
// return
return args;
});
Changelog
Rebuilt JS library in version 5.7
Further Reading
Believe it or not, this documentation only scrapes the surface of the ACF JavaScript API! If you are interested in learning more about a specific function, finding the full list of models or are in need of more code examples, please take a look at the
acf-input.js source code located in the plugin folder assets/js/acf-input.js.
Happy coding,
The ACF team.
Known Issues
Welcome to the known issues guide for the Advanced Custom Fields plugin. This guide contains information and solutions for common problems found in each release. If you are experiencing an issue with the ACF plugin, please continue reading and contact our support team with any questions.
Gutenberg Issues
Empty metaboxes are shown in Gutenberg*
*
All field groups created with the Advanced Custom Fields plugin are shown as empty visible metaboxes when editing a post irrelevant of those field group’s location rules.
This is due to a decision in Gutenberg to override the
display:none CSS that ACF adds to “placeholder” metaboxes – used to update metaboxes dynamically whilst editing the post.
Status: Resolved.
Metabox styling is broken in Gutenberg*
*
All field groups shown in the “content area” look awkward, detached and slightly broken.
More care should have gone into the styling of metaboxes to avoid such a disjointed UI and UX.
Status: This is also a known issue that has been bumped to WordPress 5.0.1.
Field validation does not work in Gutenberg*
*
Another highly used feature in ACF is our AJAX powered validation. This allows developers to highly customize the validation process via PHP whilst providing convenient feedback to the user when a field value does not meet its requirements.
Status: We’re continuing to work on bringing validation to AJAX blocks. We’ve been waiting for the Gutenberg team to provide custom validation hooks which would make this possible in a unified way, and hook into all the default page save logic.
ACF 5.7.11
Multisite issues*
*
A bug was reported where consecutive
get_field() calls would use the same cached value even if the site was switched via
switch_to_blog().
Status: Solved. Please re-download the ACF PRO plugin files.
Post template location rule issue*
*
A bug within the post_template location rule class caused incorrect choices to appear in the location rule dropdown. Choices were displayed as “Template Title” => “template-file-name.php” instead of “template-file-name.php” => “Template Title”.
Status: Solved. Please re-download the ACF PRO plugin files.
Text input maxlength issue*
*
A bug found in the text and textarea field validation function caused an incorrect character count when validating a value containing special characters.
Status: Solved. Please re-download the ACF PRO plugin files.
Field group metabox order issue*
*
A bug found in the “Local Fields” logic caused all metaboxes to appear in reverse order.
Status: Solved. Please re-download the ACF PRO plugin files.
Revision and preview issue*
*
A bug found in the
acf_get_meta() function caused issues when copying meta values for revisions and previews. This bug affected serialized array values and caused the flexible content field to appear empty when previewing or restoring a revision.
Status: Solved. Please re-download the ACF PRO plugin files.
get_field_object() issue*
*
A bug found in the
get_field_object() function prevented a field from being loaded by it’s key.
Status: Solved. Please re-download the ACF PRO plugin files.
get_sub_field() issue*
*
A bug found in the
get_sub_field() function caused incorrect values to be returned for some sub fields. This issue was seen most when a sub field existed with a “name” value equal to a “field type” such as “text” or “image”.
Status: Solved. Please re-download the ACF PRO plugin files.
Field group sync issue*
*
A bug found in the logic for syncing field groups (from Local JSON) caused the imported fields to lose their children.
Status: Solved. Please re-download the ACF PRO plugin files.
Values contain backslashes*
*
A bug found in
acf_update_metadata() function caused values from the Options Page to be incorrectly escaped causing multiple backslashes.
Status: Solved. Please re-download the ACF PRO plugin files.
Undefined function register_field_group()
The function
register_field_group() was accidentally removed.
Status: Solved. Please re-download the ACF PRO plugin files.
ACF 5.7.2
JS error Object.e.getPreference*
*
A bug was quickly reported and fixed that throws a JS error called
Object.e.getPreference. JS errors have a tendency to snowball into bigger problems such as unresponsive buttons and broken functionality. If you are experiencing any issues when editing a post, please re-download the ACF PRO plugin files to get the patched JS.
Tip: You can also trick ACF into re-updating itself by editing the main “acf.php” plugin file and changing the two references of “5.7.2” to “5.7.1”. This will allow WP to check for plugin updates and you can then re-update the plugin.
Status: Solved. Please re-download the ACF PRO plugin files.
ACF 5.7.0
Empty field returns Default Value*
*
A bug has been found where ACF is incorrectly returning the “default value” for fields that have no value. If you are experiencing any issues where ACF functions are returning undesired values, please edit the file ‘includes/api/api-field.php’ and change line 1083 to the following:
api-field.php
function acf_maybe_get_field( $selector, $post_id = false, $strict = true ) {
Status: Solved. Please re-download the ACF PRO plugin files.
ACF 5.6.6
Conditional logic issues*
*
A bug in conditional logic JS is causing validation issues for newly added flexible content layouts. If you are experiencing any incorrect validation errors, please re-download the plugin files and contact our support team if problems persist.
Status: Solved. Please re-download the ACF PRO plugin files.
ACF 5.6.3
Google Map API URL isues*
*
An over eager
esc_js() function is causing character issues with the acf.fields.google_map.url value. This may prevent the Google Map autocomplete feature from working. Please edit the file ‘includes/fields/class-acf-field-google-map.php’ and change line 300 to the following:
class-acf-field-google-map.php
if( acf ) acf.fields.google_map.url = '';
Status: Solved. Please re-download the ACF PRO plugin files.
ACF 5.6.2
Range field won't save decimal values*
*
This bug is caused by a missing step attribute on the number input. Please edit the file ‘includes/fields/class-acf-field-range.php’ and change line 101 to the following:
class-acf-field-range.php
$html .= acf_get_text_input(array(
'type' => 'number',
'id' => $atts['id'] . '-alt',
'value' => $atts['value'],
'step' => $atts['step']
));
Status: Solved for 5.6.3.
Clone field issues within a flexible content layout*
*
A bug in the Clone field is causing display problems when used as a sub field within a Flexible Content layout.
Status: Solved. Please re-download the ACF PRO plugin files.
ACF 5.6.0
Custom Fields metabox disappeared*
*
This is expected behavior added in v5.5.13 and enabled by default in 5.6.0. ACF now removes the default WP custom fields metabox in an attempt to speed up the load times of the post edit page. This feature can be disabled with the following code.
functions.php
add_filter('acf/settings/remove_wp_meta_box', '__return_false');
Post and Page location rules appearing everywhere*
*
A bug in the location rule logic is causing both the Post and Page rules to incorrectly match when using the != operator.
Status: Solved. Please re-download the ACF PRO plugin files.
User Role location rule not working*
*
A bug in this location rule is preventing the ‘all’ value from working as expected. Please note that ‘user_role = all’ can be achieved with the User Form location rule. Try changing the rule to ‘user_form = all’.
Status: Solved. Please re-download the ACF PRO plugin files.
Double fields*
*
Recent changes to the core
acf_field class have caused a conflict with some 3rd party field types (such as the image crop and component field types) that extend core ACF fields (such as the image and repeater field types) causing the core fields to render twice. Its most likely that the 3rd party plugin has released an update to solve this issue, but if not, please add an empty
initialize() to the 3rd party field class. More info can be found on this github issue.
function initialize() {
/* do nothing */
}
Issues modifying $_POST data and the acf/save_post action*
*
Recent changes to the ‘acf/save_post’ action are preventing any modifications to the
$_POST['acf'] data (during the ‘acf/save_post’ action) to be ignored. Also, any custom code triggering the ‘acf/save_post’ action will fail silently unless an array of values is defined as a second parameter.
Status: Solved. Please re-download the ACF PRO plugin files.
Basic uploaded not saving correctly in acf_form()
This problem is caused by the above Issues modifying $_POST data and the acf/save_post action issue and is preventing the basic uploader from saving the uploaded attachment ID.
Status: Solved. Please re-download the ACF PRO plugin files.
Multiple values (select, checkbox, etc) not saving to Menus or Menu Items*
*
This problem is being caused by some WP core code modifying the $_POST data during the menu save action. The intention of this WP code is to prevent PHP
max_input_vars limitations – which is great – but is preventing multiple ‘array type’ values form being saved.
We have opened a ticket with WP and found a neat fix for ACF PRO!
Status: Solved. Please re-download the ACF PRO plugin files.
WPML loading incorrect Options Page language*
*
This problem is being caused by a minor change to the options page logic and will affect those who register options pages directly in the functions.php file root (not within the ‘acf/init’ action).
Status: Solved. Please re-download the ACF PRO plugin files.
ACF 6.0.0
Repeater pagination not available in Flexible Content and Repeater subfields*
*
Currently you cannot enable pagination for Repeater fields if they are subfields of a Flexible Content or Repeater field. We will be introducing support for this in a later version.
ACF Blocks render templates cannot start with a html comment*
*
For ACF Blocks using
blockVersion: 2 and
jsx: true (both defaults for block.json blocks), your php template for the block cannot start with a HTML comment. If it does, your block will crash when injecting the preview from the server as React cannot add references to HTML comments, and ACF Blocks needs to attach one to the first element in your template.
License Activations
ACF PRO has always required a license to use PRO features and this will shortly be enforced in the plugin. Sites without an active license will display a warning in the ACF screens as of ACF 6.2.3, and will have the following restrictions in place starting with ACF 6.2.8.
Activating your ACF PRO license key on a site enables automatic plugin updates and gives access to the premium features.
How it Works
The editor experience for ACF fields, ACF Blocks, and Options Pages will not change, and your site editors will be able to use all features as they do now. The following restrictions will only apply to ACF’s admin screens for editing field groups.
Until a valid license key has been activated for the site, it won’t be possible to create new or edit existing PRO fields (Gallery, Repeater, Flexible Content, or Clone), or use the premium features such as Options Pages and ACF Blocks.
If you previously activated a license and the subscription has expired, you will not be able to create new PRO fields, but you will be able to edit existing PRO field definitions.
To be clear, the editing and display of field data anywhere outside of the ACF admin screens will be unaffected by the status of the license.
The use of ACF on a site is in 3 different areas, and to clarify how these changes affect those areas take a look at the following table:
ACF Admin
Editing Posts
Displaying Data
Where you create and edit field groups, fields, and Options Pages in the ACF admin screen using PRO field types
Where content editors enter field values and ACF Blocks when editing posts, pages & custom post types
How the field values are rendered on the front end of the site by the theme or a page builder
Valid license activated
🟢 No impact
🟢 No impact
🟢 No impact
Expired license activated
🟢 Can edit existing ACF PRO fields, ACF Blocks, and Options Pages 🟠 Cannot create new ACF PRO fields, ACF Blocks, and Options Pages
🟢 No impact
🟢 No impact
No license activated
🟠 Cannot edit existing ACF PRO fields, ACF Blocks, and Options Pages 🟠 Cannot create new ACF PRO fields, ACF Blocks, and Options Pages
🟢 No impact
🟢 No impact
Development & Staging Activations
ACF PRO licenses have a limit on the number of production sites they can be activated on. However, we allow unlimited activations on development and staging sites. We detect if a site is a development or staging site using the following ruleset:
Dev: Is URL a single segment? (localhost)
Dev: Is URL an IP address? (192.168.0.1)
Dev: Does the URL contain a dev-related subdomain? (test., testing., sandbox., dev., local.)
Dev: Does the URL contain a dev-related not publicly accessible TLD? (.local, .loc, .localhost, .test)
Stage: Does the URL contain a stage-related subdomain? (stage., staging.)
Stage: Does the URL contain a stage-related parent? (sitename.wpengine.com, sitename.wpenginepowered.com, staging-sitename.kinsta.cloud, sitename.flywheelstaging.com)
Prod: All other URLs
If your development or staging URL uses a different format then it will be classified as a production site and will count towards your license limit. To avoid that, please alter your URL or upgrade your subscription to a license with a larger site limit.
Any sites served in a subdirectory will be the root domain for its site type. For example, https://mysite.com/staging would be treated as a production URL.
Composer Installations
For users who install ACF via Composer, we recommend you define your license key in code.
ACF automatically activates your license when downloading the plugin via Composer for the site URL you provide in your
auth.json file, and this will now be checked by the plugin to ensure the URL you provided is correct for that site before you can use PRO features.
Alternatively, you’ll need to activate ACF as usual by entering a key manually in the ‘Updates’ page of ACF’s admin.
Multisite Installations
If you have purchased an ACF PRO license to use on a WordPress multisite network, you must ensure that you have activated your license key for the main site of the network to enable automatic updates of the plugin.
If you purchased a license on or after 1st Feb 2024, you are required to activate your license key on any subsite which has the ACF PRO activated and you intend to use it on. Therefore, your license needs to have enough activations available for the subsites you require. You’ll also need to activate ACF on the network’s main site in order to receive automatic updates.
If you purchased a license before 1st Feb 2024, you do not need to activate the license key on individual subsites, just the main site of the network. The updates page will not be visible on any subsites.
Bundling ACF PRO With Other Plugins
If you have bundled ACF PRO with your theme or plugin, you must ensure that the bundling has been done as the bundling documentation has always required so your users aren’t impacted by these restrictions.
The bundling should be done as follows:
The ‘ACF’ menu should be removed, so your users can’t create fields
The field groups, fields, and options pages for your theme or plugin should be defined using PHP or JSON
The ACF ‘Updates’ page where the license key can be activated should be hidden
If a later version of ACF PRO is installed on the site, the bundling code should not execute
Learn more about the way to bundle ACF PRO in a third-party plugin or theme.
Move Fields Between Field Groups
Once a field is created in one field group, it can be moved to another field group. This allows you to easily reorganize your fields when required, without direct database queries or the need to import a modified JSON file.
Moving Fields
To move a field, open the field group where it is located and click Move.
Next, you may choose to move the field to any existing field group by selecting it from the dropdown menu. Click Move Field to complete the operation.
Moving WP elements (such as the content editor) within ACF fields
This article will demonstrate a solution for moving core WordPress elements within ACF fields. This concept uses a message field as a blank placeholder into which the elements are moved via jQuery.
Here’s a look at what the interface can look like when moving the WP editor within a field group. On the left shows a normal edit page and on the right shows the WP editor moved within a field group and most importantly below a field called ‘Sub Title’.
#gallery-3 {
margin: auto;
}
#gallery-3 .gallery-item {
float: left;
margin-top: 10px;
text-align: center;
width: 50%;
}
#gallery-3 img {
border: 2px solid #cfcfcf;
}
#gallery-3 .gallery-caption {
margin-left: 0;
}
/* see gallery_shortcode() in wp-includes/media.php */
Before
After
Instructions
The placeholder
Assuming you have a field group already setup, go ahead and create a message field in the desired location and give it a label which will relate to the WP element(s) it will soon hold.
The code
Custom CSS/JS can easily be added using the acf/input/admin_head action. The following will target the ACF placeholder field, and move the WP content editor (
#postdivrich) within it. There is also some style to remove a grey background from the element making it sit more naturally within the ACF field.
functions.php
add_action('acf/input/admin_head', 'my_acf_admin_head');
function my_acf_admin_head() {
?>
To date, your efforts have raised $!
Display value within CSS
This example demonstrates how a Number field value named “h2_font_size” can be used to control the font size of all
elements.
oEmbed
Description
The oEmbed field provides an interactive component for embedding videos, images, tweets, audio, and other content. This field makes use of the native WordPress oEmbed functionality.
Screenshots
The oEmbed field interface
The oEmbed field settings
Changelog
Added in version 5.0.0.
Settings
Embed Size
Defines the width and height settings for the embed element.
Template usage
The oEmbed field will return a string containing the embed HTML obtained by the wp_oembed_get() function.
Display value.
This example demonstrates how to display an oEmbed.
Display value with additional attributes.
This example demonstrates how to add extra attributes to both the iframe src and HTML.
0,
'hd' => 1,
'autohide' => 1
);
$new_src = add_query_arg($params, $src);
$iframe = str_replace($src, $new_src, $iframe);
// Add extra attributes to iframe HTML.
$attributes = 'frameborder="0"';
$iframe = str_replace('>', ' ' . $attributes . '>', $iframe);
// Display customized HTML.
echo $iframe;
?>
Responsive embeds
Thanks to the work done by embedresponsively.com, it is possible to make embeds responsive. Please view the website to learn more as each provider may need different CSS settings.
Notes
Customizing other embed features
Due to the large number of embed providers, no settings are available to customize embed features such as overlays and buttons. To customize these settings, you will need to perform a search / replace on the string to add additional arguments to the iframe src.
Options Page
Introduced in ACF PRO 6.2, the Options Pages UI simplifies the process of creating new, customized admin and sub-admin pages to edit ACF fields.
All data saved on an options page is global and saved in the
wp_options table, rather than attached to a particular post or page. This allows the data to be displayed on any page throughout the website, making it a great option for header and footer data.
To access the Option Pages UI in ACF PRO, hover over or click on ACF in the WordPress admin, and then select Option Pages. The new options page can be linked to an existing field group, or you can create a brand new field group on the fly without breaking your workflow.
You can see a breakdown of the process in the video below.
Options Pages are Global
ACF field groups should not be shared across multiple options pages, unless you intend to also share the field group’s values. Entering data into a field mapped to more than one options page will load that value across all option pages to which it is mapped.
Please note that this behavior only applies to field groups used on options pages. All data from option pages is saved in the same location, the
wp_options table. This limitation does not apply to ACF field groups used on posts/pages.
One way around this is to create a different field group for each option page, making sure to assign each field a different name.
Alternatively, you can set custom data storage for one of the options pages, ensuring it will only display values from that source. Click the Permissions tab under “Advanced Settings” in the Options Pages UI, and then click on the dropdown under “Data Storage”. Select Custom Storage and then enter a different string to be used as the
option_name prefix in the
wp_options table, i.e.,
options2.
Screenshots
The ACF Options Pages UI.
Creating a new options page in the UI.
The Visibility tab in Advanced Settings.
How a simple “Site Settings” options page might appear to users.
Template Usage
All the API functions can be used with the options page’s fields. However, a second parameter is required to target the options page. This is similar to passing through a
$post_id to target a specific post object. This example demonstrates how to load a value from an options page.
Continue reading: Get values from an options page
Settings
Here are all of the settings you can configure through the UI:
Page Title
The title of the options page. It will also be used as the name of the options page in the WordPress admin, unless this is changed under Advanced Settings. The options page cannot be saved if this field does not receive input. Defaults to “Site Settings.”
Menu Slug
Sets the URL for the option page. The “Menu Slug” must be present before saving the options page. Defaults to the “Page Title”, but without capitalization and with spaces replaced with hyphens.
Parent Page
A dropdown that allows you to designate the options page as the child of an existing options page. The only choice displayed will be “No Parent” until you have at least one existing options page.
Advanced Configuration
Toggling this on will give you access to the Advanced Configuration settings.
Advanced Settings
Visibility
Menu Icon
Controls the icon used for the option page’s menu item in the WordPress admin. This will accept either an URL or a Dashicon class name for input.
Menu Title
Controls how the options page is titled in the WordPress admin, without changing the “Page Title”.
Menu Position
Controls where the options page menu will appear in the WordPress admin. Inputs must match the Menu Structure used by the
$position parameter in the WordPress
add_menu_page() function.
Redirect to Child Page
Toggling this on will redirect this page to its first child page, if child pages exist.
Description
This area can be used to provide a description of the options page.
Labels
Update Button Label
Controls the label used for the button which updates fields on the options page. This defaults to “Update” if this is left blank.
Updated Message
Controls the message displayed to the user when the options page is successfully updated. Defaults to “Options Updated” if this is left blank.
Permissions
Capability
Controls the WordPress capability a site user must possess to view the options page. Defaults to
edit_posts.
Data Storage
Controls where the options page stores field data. Defaults to “Options”, storing the field data in the options table. Selecting “Custom Storage” instead of “Options” allows loading of field data from a post, user, or term.
Custom Storage
This setting only appears if “Custom Storage” is selected under “Data Storage.” The input can be a numeric post ID or a string.
Autoload Options
Toggling this on automatically loads the fields in the option records when WordPress loads to improve performance.
Of course, not all ACF PRO users will want to register options pages in the UI. We’ve documented how to disable this from the plugin admin here.
Registering Options Pages with Code
Basic Usage
To create an options page, open your
functions.php file, and add the following code:
add_action('acf/init', function() {
if( function_exists('acf_add_options_page') ) {
acf_add_options_page();
}
});
Without passing any parameters to this function, the default options page will be added to your wp-admin sidebar.
Advanced Usage
This example demonstrates how to create a customized options page with children.
add_action('acf/init', function() {
if( function_exists('acf_add_options_page') ) {
acf_add_options_page(array(
'page_title' => 'Theme General Settings',
'menu_title' => 'Theme Settings',
'menu_slug' => 'theme-general-settings',
'capability' => 'edit_posts',
'redirect' => false
));
acf_add_options_sub_page(array(
'page_title' => 'Theme Header Settings',
'menu_title' => 'Header',
'parent_slug' => 'theme-general-settings',
));
acf_add_options_sub_page(array(
'page_title' => 'Theme Footer Settings',
'menu_title' => 'Footer',
'parent_slug' => 'theme-general-settings',
));
}
});
Notes
WordPress 6.8
Since WordPress 6.8, any function that causes ACF to initialise early such as this one will trigger an PHP notice, if you call it before the
acf/init action:
Notice: Function _load_textdomain_just_in_time was called incorrectly. Translation loading for the acf domain was triggered too early. This is usually an indicator for some code in the plugin or theme running too early. Translations should be loaded at the init action or later.
To avoid this, you must make sure you don’t call any ACF functions before the
acf/init action. Our code samples above show how to wrap these calls appropriately.
Order posts by custom fields
This article will demonstrate how to retrieve and sort an array of post objects from the database using native WP functions. There are many ways to query posts in WP, however, this article will make use of the common get_posts function, WP_Query Object and pre_get_posts filter.
Getting started
If you are already familiar with the above function, object and filter you may skip this section.
The WP_Query object is used to query posts and will return an object containing an array of $post objects and many useful methods.
The get_posts function makes use of the above WP_Query object, however, it only returns an array of $post objects making it a simpler way to find and loop over posts.
The pre_get_post filter is called after the query object is created, but before the actual query is run.
Examples
get_posts
This example will use the get_posts function to load all the ‘events’ posts ordered by a custom field value of ‘start_date’.
'event',
'posts_per_page' => -1,
'meta_key' => 'start_date',
'orderby' => 'meta_value',
'order' => 'DESC'
));
if( $posts ): ?>
WP_Query
This example will use the WP_Query object to load all the ‘events’ posts ordered by a custom field ‘featured’. In this case, ‘featured’ is a True / False custom field and the result will show featured posts above the rest.
'event',
'posts_per_page' => -1,
'meta_key' => 'featured',
'orderby' => 'meta_value',
'order' => 'DESC'
));
?>
have_posts() ): ?>
pre_get_posts
This example shows how to modify the current posts query. This is useful to modify an existing post type archive. This filter should be used in the functions.php file and requires some logic to avoid modifying all queries.
functions.php
query_vars['post_type']) && $query->query_vars['post_type'] == 'event' ) {
$query->set('orderby', 'meta_value');
$query->set('meta_key', 'start_date');
$query->set('order', 'DESC');
}
// return
return $query;
}
add_action('pre_get_posts', 'my_pre_get_posts');
?>
Page Link
Description
The Page Link field creates an interactive drop-down to select one or more posts, pages, custom post type items or archive URLs. This field type uses the Select2 library to enable search and AJAX functionality.
Screenshots
The Page Link field interface
The Page Link field settings
Changelog
Added
Allow Archives in version 5.4.0.
Added Select2 UI in version 5.0.0.
Settings
Filter by Post Type
Filters the selectable results via one or more post type. When left empty, all post types will be shown. As results are grouped by their post type, the selected post types here may be positioned into a specific order.
Filter by Taxonomy
Filters the selectable results via one or more taxonomy term.
Allow Null
Allows the current selection to be cleared and an empty value to be saved.
Allow Archives URLs
Includes post type archive URLs within the select list of options.
Multiple
Allows you to select more than one choice. When enabled, you may also drag/drop to reorder the selected choices.
Template usage
The Page Link field will return either a single URL or array of URLs. To get more data from a selected post, please use the post object field instead.
Display single value
This example demonstrates how to display a selected page link value.
Continue reading
Display multiple values
This example demonstrates how to load and display multiple selected page link values.
Further reading
Password
Description
The Password field creates an input for providing a password using a masked field.
Screenshots
Creating a Password field.
Settings on the Presentation tab allow you to control how the Password field will appear.
How the password field might appear to content editors. Instructions added in the Presentation tab are visible here.
Settings
Required
Found on the Validation tab, this requires a valid password be provided as the input and prevents the field from accepting empty values. Defaults to off.
Instructions
Shows instructions when submitting data.
Placeholder Text
Appears within input when no value exists.
Prepend
Adds a visual text element before the input.
Append
Adds a visual text element after the input.
Template usage
Get value
It’s unlikely you’re going to want to output password fields to the frontend, but rather use the value in other code. The following example shows how to load the value of the field “password” from an ACF options page.
$value = get_field( "password", "option");
How to Query Posts by Custom Fields
This article demonstrates how to retrieve an array of post objects from the database using native WordPress functions. There are many ways to query posts in WordPress, however, this article will make use of the common get_posts function, WP_Query object and pre_get_posts filter.
Getting Started
You can skip this section if you’re already familiar with the above function, object, and filter.
The WP_Query object is used to query posts and will return an object containing an array of
$post objects and many useful methods.
The get_posts function makes use of the above
WP_Query object. However, it only returns an array of
$post objects, making it a simpler way to find and loop over posts.
The pre_get_post filter is called after the query object is created, but before the actual query is run.
Example
This example demonstrates how to query all posts and display them in a list. Please note the functions
setup_postdata() and
wp_reset_postdata() are used to allow functions such as
the_permalink() and
the_title() to work as expected.
-1,
'post_type' => 'post'
));
if( $posts ): ?>
Custom Field Parameters
Both the
get_posts function and
WP_Query object accept arguments to perform basic and advanced queries on custom field values. There is both a basic and advanced way to query which are explained below. You can read more about acceptable parameters in the WP codex.
Basic Query Example
This example shows the arguments to find all posts where a custom field called ‘color’ has a value of ‘red’.
$posts = get_posts(array(
'posts_per_page' => -1,
'post_type' => 'post',
'meta_key' => 'color',
'meta_value' => 'red'
));
Advanced Query Example
This example shows arguments to find all posts where a custom field called ‘color’ has a value of ‘red’ or ‘orange’, and another custom field called ‘featured’ (checkbox) is checked.
$posts = get_posts(array(
'posts_per_page' => -1,
'post_type' => 'post',
'meta_query' => array(
'relation' => 'AND',
array(
'key' => 'color',
'value' => array('red', 'orange'),
'compare' => 'IN',
),
array(
'key' => 'featured',
'value' => '1',
'compare' => '=',
),
),
));
Examples
Below you will find an assortment of examples. Please note these examples use the
WP_Queryobject rather than the
get_posts function, but the arguments and logic remain the same.
1. Single custom field value
In this example, we will find all posts that have a
post_type of ‘event’ where the custom field ‘location’ is equal to ‘Melbourne’. The custom field (‘location’ in this case) could be a Text, Radio Button, or Select field (i.e., something that saves a single text value).
-1,
'post_type' => 'event',
'meta_key' => 'location',
'meta_value' => 'Melbourne'
);
// query
$the_query = new WP_Query( $args );
?>
have_posts() ): ?>
have_posts() ) : $the_query->the_post(); ?>
2. Multiple custom field text-based values
In this example, we will find all posts that have a
post_type of ‘event’ where the custom field ‘location’ is equal to ‘Melbourne’, and the custom field ‘attendees’ is higher than 100. The custom field (‘attendees’ in this case) could be a Number, Text, Radio Button, or Select field (i.e., something that saves a single text value).
-1,
'post_type' => 'event',
'meta_query' => array(
'relation' => 'AND',
array(
'key' => 'location',
'value' => 'Melbourne',
'compare' => '='
),
array(
'key' => 'attendees',
'value' => 100,
'type' => 'NUMERIC',
'compare' => '>'
)
)
);
// query
$the_query = new WP_Query( $args );
?>
have_posts() ): ?>
have_posts() ) : $the_query->the_post(); ?>
3. Multiple custom field array-based values
In this example, we will find all posts that have a
post_type of ‘event’ where the custom field ‘location’ is equal to ‘Melbourne’ or ‘Sydney’. The custom field (‘location’ in this case) could be a Multi-Select or Checkbox field (i.e., something that saves a serialized array value).
-1,
'post_type' => 'event',
'meta_query' => array(
'relation' => 'OR',
array(
'key' => 'location',
'value' => 'Melbourne',
'compare' => 'LIKE'
),
array(
'key' => 'location',
'value' => 'Sydney',
'compare' => 'LIKE'
)
)
);
// query
$the_query = new WP_Query( $args );
?>
have_posts() ): ?>
have_posts() ) : $the_query->the_post(); ?>
4. Sub custom field values
In this example, we will find all events that have a ‘city’ or either ‘Melbourne’ or ‘Sydney’. Each ‘city’ is added as a new row to a repeater field called ‘location’.
To successfully query sub field values, we need to remember that the row number is not known (there may be 1, 2, or even 3 rows of Repeater field data). Therefore, we need to use a LIKE clause in our SQL query to allow for a WILDCARD in the meta_key search. To do this, we create a custom filter to replace the standard ‘=’ with ‘LIKE’.
Update: Since the changed behavior of
esc_sql() in WordPress 4.8.3, it is not easy to use the
% character as a placeholder for the following search and replace. Instead, we recommend that you use the
$ character as shown below.
Note: This method requires hooking into the
posts_where filter, which is not guaranteed to run on all post queries. To overcome this, set
suppress_filters to false in the argument array passed to
get_posts() or
WP_Query.
-1,
'post_type' => 'event',
'meta_query' => array(
'relation' => 'OR',
array(
'key' => 'locations_$_city',
'compare' => '=',
'value' => 'Melbourne',
),
array(
'key' => 'locations_$_city',
'compare' => '=',
'value' => 'Sydney',
)
)
);
// query
$the_query = new WP_Query( $args );
?>
have_posts() ): ?>
have_posts() ) : $the_query->the_post(); ?>
Dynamic $_GET parameters
This example shows how to use
$_GET parameters (from the URL) to modify the query of a post type archive. This example assumes a post type exists for ‘event’ and that its archive exists at the url
www.website.com/events.
The event post type contains a select field called ‘city’ with values such as ‘melbourne’ and ‘sydney’. By adding a parameter to the url, the query will be modified and only posts that match the ‘city’ will be shown:
www.website.com/events?city=melbourne.
functions.php
function my_pre_get_posts( $query ) {
// do not modify queries in the admin
if( is_admin() ) {
return $query;
}
// only modify queries for 'event' post type
if( isset($query->query_vars['post_type']) && $query->query_vars['post_type'] == 'event' ) {
// allow the url to alter the query
if( isset($_GET['city']) ) {
$query->set('meta_key', 'city');
$query->set('meta_value', $_GET['city']);
}
}
// return
return $query;
}
add_action('pre_get_posts', 'my_pre_get_posts');
Querying relationship fields
This tutorial will cover the techniques to query relationship fields in both directions. The example used will be “Doctors” and “Locations”.
Screenshots
To save time, this tutorial will not cover the setup process for the 2 post types and their custom fields. However, the screenshots bellow show the data we will be working with.
#gallery-2 {
margin: auto;
}
#gallery-2 .gallery-item {
float: left;
margin-top: 10px;
text-align: center;
width: 50%;
}
#gallery-2 img {
border: 2px solid #cfcfcf;
}
#gallery-2 .gallery-caption {
margin-left: 0;
}
/* see gallery_shortcode() in wp-includes/media.php */
List of location post types
Each location has an address field
List of doctor post types
Each doctor post type has an image and a location field
archive-doctor.php
First, we will create a template file in our theme to display all the doctors. This file is called “archive-doctor” and can be viewed by going to the url “http://website.com/?post_type=doctor” or “http://website.com/doctor” depending on your permalink structure.
Screenshot
Code
Doctors
single-doctor.php
Next, we will create a template file to view each doctor’s information. On this template page, we will show links to the locations where this doctor works.
Screenshot
Code
single-location.php
Last but not least, we will create the single location template file (as we can now navigate to this page from a doctor). So far, we have created a simple “forward facing” relationship between locations and doctors. Now we will do the opposite. On each location page, we will query the WP database for all the doctors that work in that location.
This will be accomplished by using the “get_posts” function. This function makes use of the WP_Query class to fetch posts. See the parameters section of the WP_Query documentation for a list of parameters that this function accepts.
Screenshot
Code
Address
Doctors that work here
'doctor',
'meta_query' => array(
array(
'key' => 'location', // name of custom field
'value' => '"' . get_the_ID() . '"', // matches exactly "123", not just 123. This prevents a match for "1234"
'compare' => 'LIKE'
)
)
));
?>
Understanding the query
The above “get_posts” query finds all posts that are of the type “doctor”. It then finds the “location” custom field for each doctor and runs a LIKE query on the value.
The relationship field saves it’s data as a serialized array. If you are not familiar with this format, please look up the stored value in your database. It will look something like this:
a:2:{i:0;s:2:”35″;i:1;s:2:”33″;}
This serialized array has 2 values, the first is “35”, the second is “33”. As this is the “location” field for a “doctor”, these 2 numbers must be the ID’s of location post types.
In our query, the LIKE value was ‘”‘ . get_the_ID() . ‘”‘, if the location ID was 35 then the LIKE value would become ‘”35″‘. In this case, the query would match against the doctor’s location value (the serialized array shown above) and the doctor will be returned.
Radio Button
Description
The Radio Button field creates a list of select-able inputs.
Screenshots
The Radio Button field interface
The Radio Button field settings
Changelog
Added
Return Format setting in version 5.4.0.
Added
Allow Null setting in version 5.3.8.
Added
Other and ‘Save Other’ settings in version 4.1.7.
Settings
Choices
The choices displayed when selecting a value. Enter each choice on a new line (eg.
Red). For more control over the value and label, you may use a colon to specify both (eg.
red : Red).
Allow Null
Allows the ability to ‘un-select’ a selected value.
Other
Adds a text input allowing for a custom value to be entered.
Save Other
Allows custom values to be appended to the field’s choices. See Notes for more information.
Default Value
Specifies the default value selected when first editing the field’s value. Enter only value (not label).
Layout
The layout orientation of radio inputs. Select from "Vertical" to "Horizontal".
Return Format
Specifies the value format returned by ACF functions. Select from Value, Label or Both (array).
Template usage
Display a single selected value
This example demonstrates how to display the selected value.
Color:
Display value and label
This example demonstrates how to load a selected value and label without using the Format value setting.
Color:
Format value setting
This example demonstrates how to load a selected value and label using the Format value setting (set to
Both).
Color:
Conditional
This example demonstrates how to use a selected value to conditionally perform a task.
array(
array(
'key' => 'color',
'value' => 'red',
)
)
) );
if( $posts ) {
// Do something.
}
Notes
Save other
If using the local JSON feature, any custom values saved to the field’s choices will not appear on page reload. This is because the JSON file will not be updated and will override any field settings found in the DB.
Range
Description
The Range field provides an interactive experience for selecting a numerical value between specific endpoints.
Screenshots
The Range field interface
The Range field settings
Changelog
Added in version 5.6.2.
Settings
Default Value
The default value loaded when editing a new post (when no value exists).
Minimum Value
The minimum (numeric) value allowed. Defaults to 0.
Maximum Value
The maximum (numeric) value allowed. Defaults to 100.
Step Size
The increment at which a numeric value can be set. Defaults to 1.
Prepend
HTML displayed before (to the left) of the range input.
Append
HTML displayed after (to the right) of the range input.
Template usage
Display value within CSS
This example demonstrates how a Range field value can be used to control the font-size of all
elements.
Display value as text.
This example demonstrates how to display a Range field value as text.
Searching for houses within a km radius.
Register fields via PHP
This article will discuss how to register fields and field groups via the functions.php file. There are many benefits to using PHP to register fields, the main of which is customization and distribution. The ability to define fields within the theme’s files allows developers to avoid any data loss when working across multiple environments (dev/staging/live). It also reduces calls to the database and can speed up your website.
If you only require a solution for distribution across multiple environments, please familiarize yourself with the local json feature as this solves the issue with minimal effort.
Getting started
Adding field groups and fields is easy. ACF can even generate the PHP code for you from the
Import / Export menu page within the WP dashboard!
👨💻 Note: It is important to remember that each field group’s
key and each field’s
key must be unique. The
key is a reference for ACF to find, save and load data. If 2 fields or 2 groups are added using the same
key, the later will override the original.
👨💻 Note: Field Groups and Fields registered via code will not be visible/editable via the “Edit Field Groups” admin page.
Functions
Here is a list of functions which will be used in the examples below. You can find these functions and more in the
core/local.php file.
Name
Description
acf_add_local_field_group( $field_group )
Adds a field group to the local cache
acf_add_local_field( $field )
Adds a field to the local cache
acf_get_local_field( $key )
Get a local field
acf_remove_local_field( $key )
Remove a local field
Example
Basic
This example demonstrates how to add a field group.
functions.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;
Minimal
Each field contains many settings which can be removed to minimize your code. In this case ACF will merge in the missing default settings.
functions.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',
)
),
'location' => array (
array (
array (
'param' => 'post_type',
'operator' => '==',
'value' => 'post',
),
),
),
));
endif;
Individual
It is possible to add a field group and field individually. This makes it possible for a field to be defined as a variable and added to multiple field groups. Please note the
$field must contain a
parent setting which matches the key of either the field group, or another parent field ( repeater / flexible content ).
functions.php
if( function_exists('acf_add_local_field_group') ):
acf_add_local_field_group(array(
'key' => 'group_1',
'title' => 'My Group',
'fields' => array (),
'location' => array (
array (
array (
'param' => 'post_type',
'operator' => '==',
'value' => 'post',
),
),
),
));
acf_add_local_field(array(
'key' => 'field_1',
'label' => 'Sub Title',
'name' => 'sub_title',
'type' => 'text',
'parent' => 'group_1'
));
endif;
Add within an action
The functions above can be used in the root of the
functions.php file or within the acf/init action. This action was added in ACF v5.2.7 and is recommended.
The benefit of using this action is that the function is guaranteed to exist, and won’t run unless ACF is active.
functions.php
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');
Group Settings
Below is a list of available settings for a field group. Please note these settings can be viewed when editing a field group, and exported for minimal effort.
Group Settings
$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' => '',
);
Field Settings
Below is a list of available generic settings for a field. In addition to these generic settings, each field is also given field type specific settings which are listed down the page.
Field Settings
$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' => '',
);
Field type settings
Below is a list of extra settings available to each field type.
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 ) 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' => 'vertical',
/* (bool) Whether to allow custom options to be added by the user. Default false. */
'allow_custom' => false,
/* (bool) Whether to allow custom options to be saved to the field choices. Default false. */
'save_custom' => false,
/* (bool) Adds a "Toggle all" checkbox to the list. Default false. */
'toggle' => false,
/* (string) Specify how the value is formatted when loaded. Default 'value'.
Choices of 'value', 'label' or 'array' */
'return_format' => 'value',
);
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
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,
);
Register multiple options pages
Multiple options pages can be registered by making use of the acf_add_options_page() and acf_add_options_sub_page() functions. Both functions can be used within the theme
functions.php file.
Once registered, each options page will appear within the field group location rules making it quite easy to assign specific field groups to specific options pages.
Please note that for each options page, all values are saved and loaded using ‘option’ as the
$post_id. This means that values are not saved to individual options pages, therefore, all fields require unique names to avoid data loss.
Requirements
To make use of the options page feature, you will need a copy of ACF PRO (ACF v5), or the options page add-on (ACF v4)
Examples
Basic
This example demonstrates how to create the default options page with 3 extra sub pages. By default the parent options page will redirect to the first child, however, this setting can be customized (please see following example).
functions.php
if( function_exists('acf_add_options_page') ) {
acf_add_options_page();
acf_add_options_sub_page('General');
acf_add_options_sub_page('Header');
acf_add_options_sub_page('Footer');
}
Advanced
This example demonstrates how to create a new parent options page with 2 extra sub pages. Please note the use of
redirect => false which allows the parent to have it’s own page instead of redirecting to the first child.
functions.php
if( function_exists('acf_add_options_page') ) {
acf_add_options_page(array(
'page_title' => 'Theme General Settings',
'menu_title' => 'Theme Settings',
'menu_slug' => 'theme-general-settings',
'capability' => 'edit_posts',
'redirect' => false
));
acf_add_options_sub_page(array(
'page_title' => 'Theme Header Settings',
'menu_title' => 'Header',
'parent_slug' => 'theme-general-settings',
));
acf_add_options_sub_page(array(
'page_title' => 'Theme Footer Settings',
'menu_title' => 'Footer',
'parent_slug' => 'theme-general-settings',
));
}
Registering a Custom Post Type
Overview
Post Types are great for storing data objects other than posts and pages, where WordPress provides an admin UI for managing your data and a URL structure for viewing them on the frontend of the site.
Add New
To register a new post type, navigate to the ‘ACF’ > ‘Post Types’ screen and click ‘Add New’. You will see a screen with some basic settings for the post type.
Basic Settings
The required fields of “‘Plural Label”, “Singular Label” and “Post Type Key” are the minimum required information to create a post type, however, there are other settings available if you want to perform more granular configurations.
Plural Label
This is the plural label of the date object you are registering. For example, Movies, actors, and books.
Singular Label
This is the singular label of the data object you are registering. For example, Movie, actor, and book.
Post Type Key
This is automatically generated from the singular label you enter but can be changed. It must be a string made up of lowercase letters, numbers, underscores and dashes only. It has a 20 character limit.
Public
This setting controls if the post type is public or private. It is on by default, meaning the post type shows in the admin dashboard and is publicly accessible on the site frontend.
Hierarchical
This setting controls the type of post type when it comes to allowing parent and child relationships between objects of the post types, like the WordPress ‘Pages’ post type.. It is off by default.
Advanced Configuration
There are a large number of settings that can be configured when registering a post type. To keep things simple, ACF doesn’t show them by default but you can control them when the ‘Advanced Configuration’ toggle is on.
General
The ‘General Settings’ gives you several general settings related to the post type.
Linked Taxonomies
Select from existing taxonomies that should be used to classify the post type.
Supports
Allows you to define which features of the content edit screen for the post type are supported. Enable the title, featured image, author, and more.
You can also add custom items to allow you to customize the editor for your site.
Description
Use this to add a description about your post type that will be displayed in the post type list screen.
Active
The active toggle is a quick way to deactivate the post type so it can be turned off without deleting it.
Labels
The ‘Labels’ tab allows you to define the label strings used for the post type throughout the admin dashboard. You can quickly either regenerate all labels based on your ‘Plural Label’ and ‘Singular Label’ entered earlier or clear all labels.
All of the labels used by WordPress can be configured.
Visibility
The ‘Visibility’ tab contains the settings that control how the post type will be displayed in the admin dashboard and the frontend of the site. Control how it appears in the sidebar menu, remove it from the admin bar, exclude it from search results on the frontend, and more.
Show in UI
Enabled by default, this means the post type can be edited and managed in the WordPress admin dashboard.
Show in Admin Menu
Enabled by default, this controls if the post type appears in the sidebar menu in the admin dashboard.
Admin Menu Parent
By default the post type will get a new top level item in the admin menu. If an existing top level item is supplied here, the post type will be added as a submenu item under it.
Menu Position
A number that controls the position of the menu item in the admin dashboard sidebar menu.
Menu Icon
This is the icon used for the post type menu item in the admin dashboard. Can be a URL or Dashicon class name to use for the icon.
Custom Meta Box Callback
A PHP function name to be called when setting up the meta boxes for the edit screen.
Show In Admin Bar
Enabled by default, controls if the post type should appear as an item in the ‘New’ menu in the admin bar.
Appearance Menus Support
Enabled by default, controls if items can be added to menus in the ‘Appearance’ > ‘Menus’ screen. Must be turned on in ‘Screen options’.
Exclude From Search
Sets whether posts should be excluded from search results.
URLs
The ‘URLs’ tab contains the settings that control how the post type appears in URLs. This includes the permalink structure of URLs for items of the post type, if the post type should have an archive page URL, and how to control the query variable settings for the URL.
Permalink Rewrite
Rewrite the URL for an item of the post type using the post type key as the slug, a custom slug or disable it to prevent URL rewriting.
Front URL Prefix
Enabled by default, alters the permalink structure to add the
WP_Rewrite::$front prefix to URLs.
Feed URL
Enables an RSS feed URL for the post type items.
Pagination
Enabled by default, allows pagination support for the items URLs such as the archives.
Archive
Controls if the post type has an item archive that can be customized with an archive template file in your theme.
Publicly Queryable
Enabled by default, controls if URLs for an item and items can be accessed with a query string.
Query Variable Support
Controls id items can be accessed using the non-pretty permalink, with the post type key as the query variable, a custom variable or query variable access is disabled.
Permissions
The ‘Permissions’ tab contains settings all about accessing the post type.
Rename Capabilities
By default the capabilities of the post type will inherit the ‘Post’ capability names, eg. edit_post, delete_posts. Enable to use post type specific capabilities, eg. edit_{singular}, delete_{plural}.
Singular Capability Name
Choose another post type to base the capabilities for this post type.
Plural Capability Name
Optionally provide a plural to be used in capabilities.
Can Export
Enabled by default, controls if the post type to be exported from ‘Tools’ > ‘Export’.
Delete With User
Controls if the items by a user are deleted when that user is deleted.
REST API
The ‘REST API’ tab contains settings to control the post type’s behavior in the WordPress REST API.
Show in REST API
Enabled by default, controls if this post type is exposed in the REST API. Required to use the block editor.
Base URL
The base slug for the post type REST API URLs.
Namespace Route
The namespace part of the REST API URL.
Controller Class
Optional custom PHP controller class to use instead of
WP_REST_Posts_Controller.
The Next Step
Once you have configured the post type and saved your changes, a saved success notice appears along with some helpful links to perform typical next actions.
These include:
Creating a new ACF field group for the post type
Connecting existing ACF field groups to the post type
Creating a new taxonomy for the post type
Creating a New Field Group
A common workflow is to register a post type then add some fields to it to store other structured data outside of the post title and content. This is made extremely easy by clicking the ‘Add fields to’ link, which takes you to a new field group where the location rule is already set to make the field group appear when editing posts of the new post type.
Connecting to Existing Field Groups
There will be times when a new post type is created and existing field groups should also be displayed when editing posts of the new post type. You can connect existing field groups by clicking the ‘Link existing field groups’ link and selecting the field groups in the modal that appears.
This process adds a new location rule to the selected field groups to make them appear when editing posts of the new post type.
Registering a Custom Taxonomy
Overview
Taxonomies are used to classify and categorize individual posts for a post type. WordPress provides an admin UI for managing terms in a taxonomy and categorizing posts with terms.
Add New
To register a new taxonomy, navigate to the ‘ACF’ > ‘Taxonomy’ screen and click ‘Add New’. You will see a screen with some basic settings for the taxonomy.
Basic Settings
The required fields of “Plural Label”, “Singular Label” and “Taxonomy Key” are the minimum required information to create a taxonomy, however, there are other settings available if you want to perform more granular configurations.
Plural Label
This is the plural label of the taxonomy you are registering. For example, Genres, Series, Franchises.
Singular Label
This is the singular label of the taxonomy you are registering. For example, Genre, Series, Franchise.
Taxonomy Key
This is automatically generated from the singular label you enter but can be changed. It must be a string made up of lowercase letters, numbers, underscores and dashes only. It has a 20 character limit.
Post Types
Select one or more existing post types to connect the taxonomy to, so that objects of the post types can be classified with the taxonomy
Public
This setting controls if the taxonomy is public or private. It is on by default, meaning the taxonomy shows in the admin dashboard and is publicly accessible on the site frontend.
Hierarchical
This setting controls the type of taxonomy when it comes to allowing parent and child relationships between taxonomy terms. The native WordPress Category taxonomy is hierarchical but Tags is not. It is off by default.
Advanced Configuration
There are a large number of settings that can be configured when registering a taxonomy. To keep things simple, ACF doesn’t show them by default but you can control them when the ‘Advanced Configuration’ toggle is on.
General
The ‘General Settings’ gives you several general settings related to the taxonomy.
Sort Terms
Whether terms in this taxonomy should be sorted in the order they are provided to
wp_set_object_terms().
Default Term
Create a term for the taxonomy that cannot be deleted. It will not be selected for posts by default.
Term Name
The name of the default term (required).
Term Slug
Single word, no spaces. Underscores and dashes allowed.
Term Description
A descriptive summary of the term.
Description
A descriptive summary of the taxonomy.
Active
The active toggle is a quick way to deactivate the taxonomy so it can be turned off without deleting it.
Labels
The ‘Labels’ tab allows you to define the label strings used for the taxonomy throughout the admin dashboard. You can quickly either regenerate all labels based on your ‘Plural Label’ and ‘Singular Label’ entered earlier or clear all labels.
All of the labels used by WordPress can be configured.
Visibility
The ‘Visibility’ tab contains the settings that control how the taxonomy will be displayed in the admin dashboard and the frontend of the site. Control how it appears in the sidebar menu, remove it from the admin bar, exclude it from search results on the frontend, and more.
Show in UI
Enabled by default, this means the taxonomy can be edited and managed in the WordPress admin dashboard.
Show in Admin Menu
Enabled by default, this controls if the taxonomy appears in the sidebar menu in the admin dashboard.
Meta Box
Controls the meta box on the content editor screen. By default, the Categories meta box is shown for hierarchical taxonomies, and the Tags meta box is shown for non-hierarchical taxonomies. Allows you to supply a custom meta box callback or disable the meta box completely.
Register Meta Box Callback
A PHP function name to be called to handle the content of a meta box on your taxonomy.
Meta Box Sanitization Callback
A PHP function name to be called tor sanitizing taxonomy data saved from a meta box.
Appearance Menus Support
Enabled by default, controls if items can be added to menus in the ‘Appearance’ > ‘Menus’ screen. Must be turned on in ‘Screen options’.
Tag Cloud
Enabled by default, list the taxonomy in the Tag Cloud Widget controls.
Quick Edit
Enabled by default, show the taxonomy in the quick/bulk edit panel.
Show Admin Column
Display a column for the taxonomy on post type listing screens.
URLs
The ‘URLs’ tab contains the settings that control how the taxonomy appears in URLs. This includes the permalink structure of URLs for terms of the taxonomy, and how to control the query variable settings for the URL.
Permalink Rewrite
Rewrite the URL for an item of the taxonomy using the taxonomy key as the slug, a custom slug or disable it to prevent URL rewriting.
Front URL Prefix
Enabled by default, alters the permalink structure to add the
WP_Rewrite::$front prefix to URLs.
Hierarchical
Enables parent-child terms in URLs for hierarchical taxonomies.
Publicly Queryable
Enabled by default, controls if URLs for an item and items can be accessed with a query string.
Query Variable Support
Controls id items can be accessed using the non-pretty permalink, with the taxonomy key as the query variable, a custom variable or query variable access is disabled.
REST API
The ‘REST API’ tab contains settings to control the taxonomy’s behavior in the WordPress REST API.
Show in REST API
Enabled by default, controls if this taxonomy is exposed in the REST API.
Base URL
The base URL for the taxonomy REST API URLs.
Namespace Route
The namespace part of the REST API URL.
Controller Class
Optional custom controller to use instead of
WP_REST_Terms_Controller.
The Next Step
Once you have configured the taxonomy and saved your changes, a saved success notice appears along with some helpful links to perform typical next actions.
These include:
Creating a new ACF field group for the taxonomy
Connecting existing ACF field groups to the taxonomy
Creating a new post type for the taxonomy
Creating a New Field Group
A common workflow is to register a taxonomy then add some fields to it to store other structured data outside of the term title and content. This is made extremely easy by clicking the ‘Add fields to’ link, which takes you to a new field group where the location rule is already set to make the field group appear when editing terms of the new taxonomy.
Connecting to Existing Field Groups
There will be times when a new taxonomy is created and existing field groups should also be displayed when editing terms of the new taxonomy. You can connect existing field groups by clicking the ‘Link existing field groups’ link and selecting the field groups in the modal that appears.
This process adds a new location rule to the selected field groups to make them appear when editing terms of the new taxonomy.
Relationship
Description
The Relationship field provides a dual-column component to select one or more posts, pages or custom post type items, providing search, post type and taxonomy filtering controls to help find results.
Screenshots
Creating a Relationship field in an ACF field group.
The Relationship field UI as it might appear to content editors.
Settings
Filter by Post Type
Filters the selectable results by post type. When left empty, all post types are shown. Results are grouped by post type, so selected post types may be positioned in a specific order.
Filter by Post Status
Filters the selectable results by status, i.e, Published, Draft, etc. Shows posts of every status if left empty.
Filter by Taxonomy
Filters the selectable results via one or more taxonomy terms.
Filters
Specifies which filters are displayed in the component. Select from “Search”, “Post Type”, and/or “Taxonomy”.
Return Format
Specifies the returned value format. Choose from Post Object (
WP_Post) or Post ID (integer).
Required
Found on the Validation tab, this requires an input be entered, preventing the field from accepting empty values. Defaults to off.
Minimum Posts
Sets a limit on how many posts are required.
Maximum Posts
Sets a limit on how many posts are allowed.
Instructions
Shows instructions when submitting data.
Elements
Specifies which elements are displayed in each result. Select from “Featured Image”.
Conditional Logic
Enabling this setting allows you to customize the logic which determines if the current field should be visible. Groups of conditional logic rules can be created to allow for multiple and/or statements.
Bidirectional
Found on the Advanced tab, enabling this setting allows you to update a value in the target fields for each value selected for this field, adding or removing the Post ID, Taxonomy ID, or User ID of the item being updated. Please see Bidirectional Relationships for more information on using this setting to create bidirectional relationships directly in ACF’s UI.
Template usage
The Relationship field will return an array of items where each item is either a
WP_Post object or an integer value depending on the Return Format set.
Display list of posts (with setup_postdata)
This example demonstrates how to loop over a Post Object value and display a list of clickable links. Here, we use a special function named
setup_postdata() to enable the use of WordPress template functions. The field in this example uses Post Object as the Return Format, and is a multiple value.
A custom field from this post:
Display list of posts (without setup_postdata)
This example demonstrates how to loop over a Post Object value and display a list of clickable links. Here, the global post variable is never changed, so all “post” related functions need a second parameter to specify which object. The field in this example uses Post Object as the Return Format, and is a multiple value.
Notes
Customization
The Relationship field contains filters to customize the posts displayed, and the text displayed for each post.
Reverse query
It is possible to perform a reverse query on a post (post A) to find all the posts (post B, post C) which have selected it (post A). To learn more about a reverse query, please read this in-depth tutorial.
Repeater
Description
The Repeater field provides a neat solution for repeating content – think slides, team members, CTA tiles and alike.
This field type acts as a parent to a set of sub fields which can be repeated again and again. What makes this field type so special is its versatility. Any kind of field can be used within a Repeater, and there are no limits to the number of repeats either (👨💻 unless defined in the field settings).
Screenshots
The Repeater field interface
The Repeater field settings
Settings
Sub Fields
Defines the set of repeatable sub fields.
Collapsed
Enables each row to be collapsed by specifying a single sub field to display.
Minimum Rows
Sets a limit on how many rows of data are required.
Maximum Rows
Sets a limit on how many rows of data are allowed.
Layout
Defines the layout style of the appearance of the sub fields.
Table: Sub fields are displayed in a table. Labels will appear in the table header.
Block: Sub fields are displayed in blocks, one after the other.
Row: Sub fields are displayed in a two column table. Labels will appear in the first column.
Button Label
The text shown in the ‘Add Row’ button.
Pagination
Added in ACF 6.0. Defines if the repeater should only load a set number of rows per page when editing the repeater in the admin. If disabled (which it is by default), all rows will be loaded at once. This setting does not affect template usage or results returned via the REST API. Note: This setting is not currently supported inside flexible content and other repeater fields. In these cases, this setting will not be shown.
Rows per page
Added in ACF 6.0. Sets the number of rows that are displayed on a page if the “Pagination” setting is enabled.
Template usage
The Repeater field will return an array of rows, where each row is an array containing sub field values.
For the best developer experience, we created some extra functions specifically for looping over rows and accessing sub field values. These are the have_rows, the_row, get_sub_field, and the_sub_field functions.
Basic loop
This example demonstrates how to loop through a Repeater field and load a sub field value.
Foreach Loop
This example demonstrates how you can manually loop over a Repeater field value using a foreach loop.
';
foreach( $rows as $row ) {
$image = $row['image'];
echo '
';
}
echo '';
}
Nested loops
This example demonstrates how to loop through a nested Repeater field and load a sub-sub field value.
Color:
Display multiple values
This example demonstrates how to load and display multiple selected values.
Color:
Display value and label
This example demonstrates how to load a selected value and label without using the “Return Format” setting.
Color:
Load value and label with Return Format
This example demonstrates how to load a selected value and label using the “Return Format” setting, in this case set to “Both (Array)”.
Color:
Conditional
This example demonstrates how to use a selected value to conditionally perform a task. In this case, the conditional is checking to see if
red matches the selected option.
'acf-demo-card' ] ); ?>>
This template retrieves the two ACF field values:
$title = get_field( 'card_title' );
$text = get_field( 'card_text' );
The template only outputs the heading and paragraph when those fields contain values.
That conditional behavior will make the preview problem easy to see. If both fields are empty, the block has almost nothing to render.
4. Activate the Plugin
In WP Admin, go to: Plugins → Installed Plugins
Find ACF Block Preview Demo and click Activate.**
Once activated, WordPress will register the block using the metadata in
block.json.
You can verify this by opening a post or page, launching the block inserter, and searching for ACF Demo Card.
The block should now appear in the search results.
If it does not appear, check if:
The plugin is activated
The file is named exactly named
block.json
The plugin’s registration path points to the directory containing
block.json
The JSON is valid
Create the ACF Field Group
Now that the block exists, we can attach ACF fields to it.
In WP Admin, go to ACF → Field Groups. Click on Add New and name the field group Demo Card Fields.
Add the first field:
Field Label: Card Title
Field Name: card_title
Field Type: Text
Add the second field:
Field Label: Card Text
Field Name: card_text
Field Type: Text Area
Under Location Rules, configure:
Block is equal to ACF Demo Card
Save the field group. This is what it should look like in WP Admin:
Experience the Empty Preview Problem
Now let’s experience the issue from the content editor’s perspective. Open a new page in the WordPress Block Editor. Launch the block inserter and add ACF Demo Card.
Do not enter any field values.
Because
card_title and
card_text are empty, the PHP template has no visible content to output. The block exists in the editor, but its preview area appears blank.
This is the pain point.
The editor can see the block in List View and interact with its toolbar, but the visual canvas does not explain what the component is supposed to look like.
Click the pencil icon in the block toolbar to enter edit mode.
You should now see the ACF form containing Card Title and Card Text:
As you can see in the image I entered some real content. After clicking Done, the PHP template now has real values to retrieve. The rendered block appears in the editor now.
The block works, but the editor had to insert it and add content before seeing a useful visual result. Next, we will solve that problem for the block inserter preview.
Find the ACF Field Keys
To pass example ACF values through
block.json, we need the unique ACF field keys. These are not the same as the field names.
Our field names are:
card_title
card_text
The field keys look like:
field_6a3c20b679eec
field_6a3c20de79eed
Each field key is unique to the field created on your site. To find them, go to: ACF → Field Groups → Demo Card Fields
At the top-right of the screen, click Screen Options and enable Field Keys:
The field keys should now appear alongside each field. For this demo, the keys are:
Card Title:
field_6a3c20b679eec
Card Text:
field_6a3c20de79eed
Your field keys will be different. Copy the values from your own field group and use them in the next step.
Add Example ACF Data to block.json
Open the block’s
block.json file again.
Add an
example object above the
acf configuration:
"example": {
"attributes": {
"mode": "preview",
"data": {
"field_6a3c20b679eec": "Plan Your Austin Stay",
"field_6a3c20de79eed": "Browse short-term rentals by neighborhood, amenities, and price."
}
}
}
The full
block.json file should now look like this:
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "acf/demo-card",
"title": "ACF Demo Card",
"description": "A demo card used to test ACF Block previews.",
"category": "widgets",
"icon": "index-card",
"keywords": ["acf", "card", "preview"],
"example": {
"attributes": {
"mode": "preview",
"data": {
"field_6a3c20b679eec": "Plan Your Austin Stay",
"field_6a3c20de79eed": "Browse short-term rentals by neighborhood, amenities, and price."
}
}
},
"acf": {
"blockVersion": 3,
"mode": "preview",
"renderTemplate": "render.php"
},
"supports": {
"align": false
}
}
Let’s focus on this section:
"data": {
"field_6a3c20b679eec": "Plan Your Austin Stay",
"field_6a3c20de79eed": "Browse short-term rentals by neighborhood, amenities, and price."
}
The keys are the unique ACF field keys. The values are the temporary example content we want WordPress to use when constructing the block preview.
ACF makes this data available to the render template, so our existing calls still work:
get_field( 'card_title' );
get_field( 'card_text' );
We do not need to add special preview checks to
render.php, and we do not need to create a static preview image. The actual block template renders against the example data.
Test the Block Inserter Preview
Save
block.json, then return to the WordPress Block Editor and refresh the page. Open the block inserter and search for ACF Demo Card.
Select or hover over the block so WordPress displays its preview.
You should now see Plan Your Austin Stay and Browse short-term rentals by neighborhood, amenities, and price:
This is the finished editor experience.
Before inserting the block, the content editor can see a realistic example of what the component looks like.
This is especially useful on sites with many custom blocks. Instead of choosing from a list of block names and empty previews, editors can browse something closer to a visual component library.
What Happens After the Block Is Inserted?
There is an important distinction to understand.
The
example values are only used to build the visual block preview. Click the block in the inserter to add a new copy to the page. The newly inserted block’s actual ACF fields will still be empty.
For the problem covered in this guide, we want example data because our goal is to improve the block-selection experience.
Why Not Use a Static Preview Image?
Another approach is to detect the preview state in the PHP template and display an image:
if ( $is_preview ) {
echo '';
return;
}
That can work, but it creates a separate representation of the block.
It may become outdated when the component design changes. It also does not use the block’s real markup or current styles.
Using example ACF data allows WordPress to render the actual PHP template with temporary values.
This has several benefits:
The preview uses the real block markup
Current block styles are reflected
No separate preview image is required
The example values stay close to the block configuration
Editors get a more accurate representation of the component
Working With More Complex ACF Fields
Our demo uses a Text field and Text Area field, but the same general pattern can be used with other ACF field types.
The value inside
example.attributes.data needs to match the structure expected by the field.
For example:
A True/False field may use
0 or
1
A Post Object or Relationship field may use post IDs
A Repeater field needs to preserve the expected nested data structure
An Image field may need the value format expected by the template and field configuration
Start with simple fields while testing the workflow, then add more complex values once the basic preview works.
Conclusion
ACF Stoke!!! You now have an ACF Block with a populated visual preview powered by example field data in
block.json.
The result is a meaningful block inserter preview that helps content editors understand the component before adding it.
For sites with a growing library of custom ACF Blocks, this small addition can make the Block Editor feel more visual, discoverable, and user-friendly.
[1] WP Engine is a proud member and supporter of the community of WordPress® users. The WordPress® trademark is the intellectual property of the WordPress Foundation. Uses of the WordPress® trademarks in this website are for identification purposes only and do not imply an endorsement by WordPress Foundation. WP Engine is not endorsed or owned by, or affiliated with, the WordPress Foundation.
Shortcode
Shortcodes can be used within a WYGIWYG to display another field’s value. To learn more about shortcodes, click here.
From ACF 6.3.0, the ACF shortcode is disabled by default for new installs of ACF. If you need to enable it, see enabling the ACF shortcode.
For security, we recommend disabling the ACF shortcode if you are not using it.
Usage
Place the shortcode marker with the desired field within your wysiwyg content. This shortcode runs the same as the the_field() function.
[acf field="field_name" post_id="123"]
Example
This is a story about a boy named [acf field="name"]. He is [acf field="age"] years old.
Limitations
Only works for simple text based values
Disabling the Shortcode
The ACF shortcode allows access to any field on any post type as was enabled by default any install of ACF created before the release of ACF 6.3. This means any user who has permission to publish posts on your site can view any ACF data if they know the field name or key. For this reason, we recommend you disable the shortcode if your site is not using it. You can use the following setting to disable it:
add_action( 'acf/init', 'set_acf_settings' );
function set_acf_settings() {
acf_update_setting( 'enable_shortcode', false );
}
Enabling the Shortcode
When enabled, the ACF shortcode allows access to any field on any post type. This means any user who has permission to publish posts on your site can view any ACF data if they know the field name or key. For this reason, from ACF 6.3 the shortcode is disabled by default for new installs. If you do need to use it, for example for a page builder, you can use the following setting to enable it:
add_action( 'acf/init', 'set_acf_settings' );
function set_acf_settings() {
acf_update_setting( 'enable_shortcode', true );
}
Structured Data for ACF Blocks
Output Schema.org structured data from ACF Block fields.
Description
ACF Blocks can automatically output JSON-LD structured data for their field values. This enables rich snippets and AI discoverability for block-based content.
Requirements
ACF 6.8 or later
Schema feature enabled via
add_filter( 'acf/settings/enable_schema', '__return_true' );
Configuration
Via block.json
Add the
autoJsonLd and optional
schemaType properties to the
acf namespace:
{
"name": "acf/recipe-card",
"title": "Recipe Card",
"category": "formatting",
"acf": {
"mode": "preview",
"autoJsonLd": true,
"schemaType": "Recipe"
}
}
Via Programmatic Registration
Use the
acf array when registering the block:
acf_register_block_type( array(
'name' => 'recipe-card',
'title' => __( 'Recipe Card' ),
'category' => 'formatting',
'acf' => array(
'autoJsonLd' => true,
'schemaType' => 'Recipe',
),
'render_template' => 'blocks/recipe-card.php',
));
Properties
autoJsonLd
(boolean) Enable JSON-LD output for this block. Default:
false
schemaType
(string|array) The Schema.org type(s) for the block. Optional; ACF can auto-detect from field mappings. Can be a single type or array of types.
Field Mapping
Map block fields to Schema.org properties in the field group editor:
Edit the field group assigned to the block
For each field, set the Schema.org Property setting
The mapped values will appear in the block’s JSON-LD output
Output
JSON-LD is output inline with each block instance on the frontend:
Multiple Blocks
Each block instance outputs its own JSON-LD script. For pages with multiple blocks of the same type, each gets a separate structured data object.
Filters
Enable JSON-LD for specific blocks
add_filter( 'acf/ai/block_jsonld_enabled', function( $enabled, $block ) {
// Enable for specific block
if ( $block['name'] === 'acf/my-block' ) {
return true;
}
return $enabled;
}, 10, 2 );
Modify block JSON-LD data
add_filter( 'acf/schema/block_jsonld_data', function( $data, $block, $post_id ) {
// Add custom properties
$data['custom'] = 'value';
return $data;
}, 10, 3 );
Example: Recipe Block
block.json:
{
"name": "acf/recipe",
"title": "Recipe",
"acf": {
"autoJsonLd": true,
"schemaType": "Recipe"
}
}
Field mappings:
– Recipe Name →
name
– Description →
description
– Prep Time (minutes) →
prepTime (Duration format)
– Cook Time (minutes) →
cookTime (Duration format)
– Servings →
recipeYield
– Ingredients (Repeater) →
recipeIngredient
– Instructions (Repeater) →
recipeInstructions
Output:
{
"@context": "https://schema.org",
"@type": "Recipe",
"name": "Chocolate Chip Cookies",
"description": "Classic homemade cookies",
"prepTime": "PT15M",
"cookTime": "PT12M",
"recipeYield": "24 cookies",
"recipeIngredient": [
"2 cups flour",
"1 cup sugar",
"1 cup chocolate chips"
],
"recipeInstructions": [
{
"@type": "HowToStep",
"text": "Preheat oven to 350°F"
},
{
"@type": "HowToStep",
"text": "Mix dry ingredients"
}
]
}
Notes
JSON-LD is not output in the block editor preview
Empty field values are automatically excluded
Block JSON-LD is output inline with the block, not in
Multiple blocks on a page each get their own JSON-LD script
The
schemaType is optional if fields are mapped; ACF infers the type
Synchronized JSON
Synchronized JSON is a feature (added in version 5.1.5) which detects changes to local JSON files and allows the user to update the corresponding field groups within the Database. This functionality is visible when viewing the field group admin page but only when ACF has detected there are field groups available for synchronizing.
Available for sync
JSON field groups are determined ‘available for sync’ when either the JSON field group does not exist in the DB (field group key is used to match pair), or when the JSON field group contains a higher ‘modified’ value than the DB post’s modified date. The modified value can be found within the JSON file (assuming the file has been created by ACF PRO version 5.1.5 or later) and is a GMT unix timestamp from when the field group was last saved.
If you do not wish for your field group to qualify for ‘available for sync’, simply add an extra value to the JSON array called ‘private’:
'private' : true. This may become useful for plugin / theme developers who wish to keep their bundled field groups hidden from the user.
Tab
Description
The Tab field is used to group together fields into tabbed sections.
When editing a field group, be aware that all fields following the Tab field (or until another Tab field is defined) will be grouped together using the Tab field label as the tab heading.
Screenshots
The Tab field interface
The Tab field settings
Changelog
Added
Placement setting in version 5.1.7.
Added
Endpoint setting in version 5.2.8.
Added sub field compatibility in version 5.0.0.
Settings
Placement
Changes the tab style from a top aligned row to a left aligned sidebar. The
left aligned option will be ignored if the field group appears in a table element (editing a user, attachment, taxonomy or field group label setting on left).
Endpoint
Defines an endpoint for the previous Tab group. When used in combination with an empty field label, this field can be used as a tab stopper.
Taxonomy
Description
The Taxonomy field allows the selection of one or more taxonomy terms.
Screenshots
Creating a Taxonomy field in an ACF field group.
The Taxonomy field UI as it might appear to content editors, in this case showing parent and child categories.
Changelog
Split setting
load_save_terms into
load_terms and
save_terms in version 5.2.7.
Create Terms added in version 5.2.3
Settings
Taxonomy
Selects the taxonomy you wish to select term(s) from.
Create Terms
Allows new terms to be created while editing. Defaults to on.
Save Terms
Connects selected terms to the post. Defaults to off.
Load Terms
Loads values from the post terms. Defaults to off.
Return Value
Specifies the format of the returned data. Choose from Term Object (
WP_Term) or Term ID (int).
Appearance
Selects the type of interface displayed (Checkbox, Multi Select, Radio Buttons, or Select).
Required
Enabling this prevents the field from accepting empty values. Defaults to off.
Instructions
Shows instructions when submitting data.
Conditional Logic
Enabling this setting allows you to customize the logic which determines if the current field should be visible. Groups of conditional logic rules can be created to allow for multiple and/or statements.
Bidirectional
Found on the Advanced tab, enabling this setting allows you to update a value in the target fields for each value selected for this field, adding or removing the Post ID, Taxonomy ID, or User ID of the item being updated. Please see Bidirectional Relationships for more information on using this setting to create bidirectional relationships directly in ACF’s UI.
Template usage
The Taxonomy field will return one or more values (objects or IDs) depending on the Return Value setting. Below are some examples of how you can use this data.
Display single value
This example demonstrates how to get and display a single term object. This would imply that your Appearance setting is Radio Buttons or Select.
name ); ?>
description ); ?>
Display multiple values
This example demonstrates how to get and loop over multiple selected term objects. This implies that your Appearance setting is Checkbox or Multi Select.
Display values from a selected term
The Advanced Custom Fields plugin can be used to add custom fields to taxonomy terms.
Building on this, the following examples demonstrate how to load a custom field value from a selected term value.
Term name: name ); ?>
Term color:
Notes
Customizing query args
The query arguments used to find and display taxonomy terms can be customized via one of the following filters depending on the Appearance setting of your Taxonomy field.
For Select and Multi Select, use the acf/fields/taxonomy/query filter.
For Checkbox and Radio, use the acf/fields/taxonomy/wp_list_categories filter.
Customization of Text
The text displayed for each taxonomy term can be customized via the acf/fields/taxonomy/result filter.
Testing Pre-Release Versions of ACF PRO
Participating in the ACF PRO pre-release program is a great way to test new features before the official launch and help our team gather valuable feedback. This guide outlines how to install a pre-release version (such as a Beta or Release Candidate) and how to share your findings.
⚠️ Important Warning
Pre-release versions are not recommended for production sites. Please use a development or staging environment for all testing.
1. How to Install a Pre-Release Version
Access to pre-release versions is available exclusively to active ACF PRO license holders.
Log In
Log in to your ACF account.
Go to Licenses
Navigate to the “Licenses” page in your account dashboard.
Find Pre-Releases
On this page, you will find an “Install pre-release version” tab or a dropdown menu next to your license key.
Download
Select the latest available pre-release version (e.g.,
ACF PRO 6.x.x-beta1) to download the plugin’s
.zip file.
Install in WordPress
Go to your WordPress admin dashboard, navigate to Plugins > Add New, click Upload Plugin, and select the
.zip file you just downloaded.
2. How to Activate the Plugin
After installation, the activation process is the same as for any other version of ACF PRO.
Activate Plugin
Once the plugin has been installed from the
.zip file, click the Activate Plugin button.
Verify Your License
To ensure you receive all future pre-release updates and that all PRO features are enabled:
Go to ACF > Updates.
Enter your ACF PRO license key and click Activate.
3. Enabling Automatic Pre-Release Updates
To automatically receive update notifications for pre-release versions directly in your WordPress dashboard, you need to define the
ACF_UPDATE_CHANNEL constant in your
wp-config.php file.
This setting ensures that ACF checks for updates beyond the stable releases.
How to Set the Update Channel
Add the following code snippet to your WordPress installation’s
wp-config.php file, ideally before the line that says
/* That's all, stop editing! Happy publishing. */.
You have two options for the channel value:
For Beta versions (Less stable, earliest access to features):
define( 'ACF_UPDATE_CHANNEL', 'beta' );
For Release Candidate versions (More stable, closer to final release):
define( 'ACF_UPDATE_CHANNEL', 'RC' );
Remember to clear any caching on your site after making this change to ensure WordPress immediately recognizes the new setting.
4. How to Provide Feedback
Your feedback is essential to refining the release. We have two primary channels for you to share your thoughts, depending on the type of feedback you have.
Bug Reports
If you encounter a bug, an error, or something that seems broken, please contact our support team directly. This is the fastest way to ensure our developers can investigate and resolve the issue.
Feature Requests
If you have ideas for improvements, new features, or suggestions on the new functionality, the best place to share them is on our official feedback board.
Stay Informed
Want to stay in the loop? Sign up for the ACF Beta News email list to hear about future pre-release versions.
Text
Description
The Text field creates a basic text input, useful for storing single string values.
Screenshots
Creating a Text field within an ACF field group.
The Presentation tab lets you control how the Text field will appear to content editors.
How the Text field appears to content editors. Changes made on the Presentation tab are reflected here.
Changelog
Formatting setting removed in version 5.0.0.
Settings
Default Value
The default value shown when creating a new post.
Required
Found on the Validation tab, this prevents the field from accepting empty values. Defaults to off.
Character Limit
Limits the number of characters allowed.
Instructions
Shows instructions when submitting data.
Placeholder Text
Appears within input when no value exists.
Prepend
Adds a visual text element before the input.
Append
Adds a visual text element after the input.
Template usage
Display value
This example demonstrates how to display a Text field named “heading” within a
tag. We don’t recommend outputting any ACF value without any sort of protection or escaping.
Load value
This example demonstrates how to load the value of a Text field named “confirm” and perform an action based on its value.
$confirm = get_field('confirm');
if( $confirm === 'SEND_EMAIL' ) {
// Do something.
}
Text Area
Description
The Text Area field creates a basic textarea input, useful to store simple (i.e., unstyled) paragraphs of text to use in your theme.
Screenshots
Creating a Text Area field in ACF.
The Presentation tab controls how the field will display.
How the Text Area field appears when editing content. You can see how changes made on the Presentation tab are reflected here.
Changelog
Formatting setting removed in version 5.0.0.
Rows setting added in 4.3.5.
Settings
Default Value
The default value shown when creating a new post.
Required
Found on the Validation tab, this prevents the field from accepting empty values. Defaults to off.
Character Limit
Limits the number of characters allowed.
Instructions
Shows instructions when submitting data.
Rows
Sets the height of this field. Defaults to 8.
Placeholder Text
Appears within input when no value exists.
New Lines
Changes the way new lines are formatted. Selecting “Automatically add paragraphs” will add paragraph tags around the value. Selecting “Automatically add
” will convert any new lines to HTML line breaks. Selecting “No Formatting” will not convert
any tags, and you will see any HTML displayed as normal text similar to regular content.
Template usage
Display value with paragraphs automatically added
This example demonstrates how to display a Text Area field named
product_description when the “Automatically add paragraphs” setting is enabled.
Product Description
Display value without formatting
This example demonstrates how to display a Text Area field named
product_description when the “No Formatting” setting is enabled. In this case, we have to indicate a paragraph manually with the
tag.
Product Description
the_field()
Description
Displays the value of a specific field.
Intuitive and powerful, this function can be used to output the value of any field from any location. Please note this function is the same as
echo get_field().
Parameters
the_field($selector, [$post_id], [$format_value]);
$selector (string) (Required) The field name or field key.
$post_id (mixed) (Optional) The post ID where the value is saved. Defaults to the current post.
$format_value (bool) (Optional) Whether to apply formatting logic. Defaults to true.
Examples
Display a value from the current post
This example shows how to display the value of field "text_field" from the current post.
Display a value from a specific post
This example shows how to display the value of field "text_field" from the post with ID = 123.
Check if value exists
This example shows how to check if a value exists before displaying it.
Get a value from different objects
This example shows a variety of valid $post_id values that specify where the value is saved.
$post_id = false; // current post
$post_id = 123; // post ID = 123
$post_id = "user_123"; // user ID = 123
$post_id = "term_123"; // term ID = 123
$post_id = "category_123"; // same as above
$post_id = "option"; // options page
$post_id = "options"; // same as above
the_field( 'my_field', $post_id );
Notes
Prior to ACF 5.11,
the_field() could be used to display the values of options or meta for items not associated with ACF fields. This had security implications as site options could be exposed.
the_field() also could display values of fields that are no longer registered with ACF.
This was updated in ACF 5.11, see the Updates to ACF Field Functions in 5.11 resource for more info.
the_flexible_field()
Description
This function is deprecated. Please use the have_rows() function instead.
This function is used within a while-loop to loop through each row of a Flexible Content field.
Unlike
have_rows(), this function will take a step through the available rows each time it is called, causing undesired results when also used within an if-statment.
Parameters
the_flexible_field( $field_name, $post_id );
$field_name (string) (Required) The name of the Flexible Content field to be retrieved. e.g. ‘content’
$post_id (mixed) (Optional) The post ID where the value is saved. Defaults to the current post.
Return
(bool) True if a row exists.
Change Log
Deprecated in version 3.3.4
Added in version 3.1.0
Requirements
Flexible Content field Add-on version 1.0.0 or later.
Example
This example demonstrates how to loop through a Flexible Content field called “content” and display various layouts.
the_repeater_field()
Description
This function is deprecated. Please use the have_rows() function instead.
This function is used within a while-loop to loop through each row of a repeater field.
Unlike
have_rows(), this function will take a step through the available rows each time it is called, causing undesired results when also used within an if-statment.
Parameters
the_repeater_field( $field_name, $post_id );
$field_name (string) (Required) The name of the Repeater field to be retrieved. e.g. ‘gallery_images’
$post_id (mixed) (Optional) The post ID where the value is saved. Defaults to the current post.
Return
(bool) True if a row exists.
Change Log
Deprecated in version 3.3.4
Added in version 2.0.3
Requirements
Repeater field Add-on version 1.0.0 or later.
Examples
Loop through Repeater field
This example demonstrates how to loop through a repeater field called “gallery_images”.
Loop through Repeater field from another post
This example demonstrates looping through a Repeater field from a different post with the ID of 123.
Note: You don’t need to specify the
$post_id for any sub field functions.
';
while( the_repeater_field('repeater_field_name', 123) ) {
echo '
';
}
echo '';
}
the_sub_field()
Description
Displays the value of a specific sub field value from a Repeater or Flexible Content field loop.
This function is essentially the same as
echo get_sub_field().
Parameters
the_sub_field( $selector, [$format_value] );
$selector (string) (Required) The sub field name or field key.
$format_value (bool) (Optional) Whether to apply formatting logic. Defaults to true.
Examples
Display a value from within a Repeater field.
This example shows how to loop through a Repeater field and display a sub field value.
No todos found.
Display a value from within a Flexible Content field.
This example shows how to loop through a Flexible Content field and generate HTML for different layouts.
Nested loops
This example shows how to loop through a nested Repeater field and display sub field values.
Time Picker
Description
The Time Picker field creates a jQuery time selection popup.
Screenshots
The Time Picker field interface
The Time Picker field settings
Changelog
Added in version 5.3.9.
Settings
Display Format
The time format that is displayed when selecting a date.
Return Format
The time format that is returned when loading the value.
Template usage
The Time Picker field returns a string value using the Return Format setting.
Display value
This example demonstrates how to display a time value.
Monday: -
Query posts within time range
This example demonstrates how to query posts for all stores that are open.
It assumes a custom post type called ‘store’ exists with a custom field for each day’s open and close time in the following naming convention: ‘monday_open_time’, ‘monday_close_time’, ‘tuesday_open_time’, etc.
When working with the meta_query array, remember that WordPress reads this as
$meta $compare $value (eg. ‘monday_open_time’ < $time)
-1,
'post_type' => 'store',
'meta_query' => array(
'relation' => 'AND',
array(
'key' => $today.'_open_time',
'compare' => '<=',
'value' => $time,
'type' => 'TIME'
),
array(
'key' => $today.'_close_time',
'compare' => '>=',
'value' => $time,
'type' => 'TIME'
)
)
));
if( $posts ): ?>
Stores open now
post_title; ?>:
ID ); ?> - ID ); ?>
Notes
Database format
The value selected can be returned and displayed in different formats but will be saved to the database as ‘H:i:s’. This format is used throughout the WordPress database tables and will allow for straight-foward database querying.
Time format strings
To customize the Display Format and Return Format settings further, refer to the full list of time format strings within the PHP date() documentation.
True / False
Description
The True / False field allows you to select a value that is either 1 or 0.
Screenshots
The True / False field interface
The True / False field settings
Changelog
Added
UI setting in version 5.5.0.
Added
On Text setting in version 5.5.0.
Added
Off Text setting in version 5.5.0.
Settings
Message
The text displayed alongside the toggle.
Default Value
Specifies the default state selected when first editing the field’s value.
Stylized UI
Changes the default checkbox input into a stylized toggle switch.
On Text
The text displayed within the stylized toggle switch. Defaults to ‘Yes’. HTML may be entered for icons or custom markup.
Off Text
The text displayed within the stylized toggle switch. Defaults to ‘No’. HTML may be entered for icons or custom markup.
Template usage
The True / False field returns a Boolean value of either
true or
false.
Note that the actual value saved into the database is an integer of either 1 or 0.
Conditional
This example demonstrates how to use the value of ‘enable_sidebar’ to conditionally do a task.
array(
array(
'key' => 'show_in_sidebar',
'value' => '1',
)
)
) );
if( $posts ) {
foreach( $posts as $post ) {
// Do something.
}
}
update_field()
Description
Updates the value of a specific field.
Parameters
update_field($selector, $value, [$post_id]);
$selector (string) (Required) The field name or field key.
$value (mixed) (Required) The new value.
$post_id (mixed) (Optional) The post ID where the value is saved. Defaults to the current post.
Return
(int|bool) Meta ID if the field value didn’t exist and the field is not being saved as an option. Otherwise true on successful update, false on failure.
Examples
Updating via field name
This example shows how to update the value of a field called ‘views’ on the current post being viewed.
// Get the current value.
$count = (int) get_field('views');
// Increase it.
$count++;
// Update with new value.
update_field('views', $count);
Updating via field key
This example shows how to achieve the same result as above using the field’s key instead of its name. The field’s key should be used when saving a new value to a post (when no value exists). This helps ACF create the correct ‘reference’ between the value and the field’s settings.
Each value saved in the database is given a ‘reference’ of the field’s key. This allows ACF to connect a value with its field. ACF does this so it can format values when loaded based of the field type and settings. For example, the image field contains a setting to return an array of image data instead of the attachment ID.
// Get the current value.
$count = (int) get_field('field_123456');
// Increase it.
$count++;
// Update with new value.
update_field('field_123456', $count);
Update a value from different objects
This example shows a variety of $post_id values to update a value from a post, user, term and option.
$post_id = false; // current post
$post_id = 1; // post ID = 1
$post_id = "user_2"; // user ID = 2
$post_id = "category_3"; // category term ID = 3
$post_id = "event_4"; // event (custom taxonomy) term ID = 4
$post_id = "option"; // options page
$post_id = "options"; // same as above
update_field( 'my_field', 'my_value', $post_id );
Saving values to a new post
This example will demonstrate how to create a new post, and save multiple field values to it.
// Create new post.
$post_data = array(
'post_title' => 'My post',
'post_type' => 'post',
'post_status' => 'publish'
);
$post_id = wp_insert_post( $post_data );
// Save a basic text value.
$field_key = "field_123456";
$value = "some new string";
update_field( $field_key, $value, $post_id );
// Save a checkbox or select value.
$field_key = "field_1234567";
$value = array("red", "blue", "yellow");
update_field( $field_key, $value, $post_id );
// Save a repeater field value.
$field_key = "field_12345678";
$value = array(
array(
"sub_field_1" => "Foo",
"sub_field_2" => "Bar"
)
);
update_field( $field_key, $value, $post_id );
// Save a flexible content field value.
$field_key = "field_123456789";
$value = array(
array( "sub_field_1" => "Foo1", "sub_field_2" => "Bar1", "acf_fc_layout" => "layout_1_name" ),
array( "sub_field_x" => "Foo2", "sub_field_y" => "Bar2", "acf_fc_layout" => "layout_2_name" )
);
update_field( $field_key, $value, $post_id );
// Save a value for a clone field set to “Prefix Field Names”.
update_field( ‘clone_field_name_original_field_name’, $post_id, $value );
Notes
No change detected
If the value passed to this function is the same as the value that is already in the database, this function returns false.
update_row()
Updates a row of data for an existing Repeater or Flexible Content field value.
Parameters
update_row($selector, $row, $value, [$post_id])
$selector (string) (Required) The field name or field key.
$row (int) (Required) The row number to update.
$value (array) (Required) The new row data.
$post_id (mixed) (Optional) The post ID where the value is saved. Defaults to the current post.
Return
(bool) True on successful update, false on failure.
Change Log
Added in version 5.3.2
Examples
Add a new row using field names
This example shows how to update the first row of data of an existing repeater field called ‘images’. This repeater field contains 3 sub fields (‘image’, ‘alt’, ‘link’).
Please see notes regarding index offset.
$row = array(
'image' => 123,
'alt' => 'Another great sunset',
'link' => 'http://website.com'
);
update_row('images', 1, $row);
Notes
Index offset
When targeting a specific row number, please note that row numbers begin from 1 and not 0. This means that the first row has an index of 1, the second row has an index of 2, and so on.
To begin indexes from 0, please use the row_index_offset setting like so.
functions.php
add_filter('acf/settings/row_index_offset', '__return_zero');
update_sub_field()
Description
Updates the value of a specific sub field.
This function can be used inside or outside of a
have_rows() loop. When used inside, the current row will be used to update the sub field value. When used outside, the rows and parents must be specified to target the correct value place.
Parameters
update_sub_field($selector, $value, [$post_id]);
$selector (string|array) (Required) The sub field name or key, or an array of ancestors and row numbers.
$value (mixed) (Required) The new value.
$post_id (mixed) (Optional) The post ID where the value is saved. Defaults to the current post.
Return
(bool) True on successful update, false on failure.
Change Log
Added in version 5.0.0
Examples
Update a sub field inside of a have_rows() loop
This example shows how to loop through a Repeater field and update one of its sub field values using the current row number.
if( have_rows('repeater') ) {
$i = 0;
while( have_rows('repeater') ) {
the_row();
$i++;
update_sub_field('caption', "This caption is in row {$i}");
}
}
Update a sub field outside of a have_rows() loop
This example shows how to update a sub field value outside of a
have_rows() loop. Here, the
$selector parameter is provided an array containing a mixture of field names and row numbers. This array should read from left to right, the parents to children relationship separated by the row number.
Please see notes regarding index offset.
// Update "caption" within the first row of "repeater".
update_sub_field( array('repeater', 1, 'caption'), 'This caption is for the first row of the repeater!' );
Update a nested sub field
The
update_sub_field() function can also be used to target a nested sub field both inside and outside of a
have_rows() loop. This example shows how to update a nested sub field function using both methods.
// Loop over parent rows.
if( have_rows('repeater') ) {
$parent_i = 0;
while( have_rows('repeater') ) {
the_row();
$parent_i++;
// Loop over child rows.
if( have_rows('sub_repeater') ) {
$child_i = 0;
while( have_rows('sub_repeater') ) {
the_row();
$child_i++;
// Update nested sub field value with reference to both parent and child indexes.
update_sub_field('sub_sub_field', "This value is for repeater row {$parent_i}, and sub_repeater row {$child_i}");
}
}
}
}
// target a nested sub field directly.
update_sub_field( array('repeater', 1, 'sub_repeater', 2, 'sub_sub_field'), 'This value is for repeater row 1, and sub_repeater row 2!' );
Notes
Index offset
When targeting a sub field using a specific row number, please note that row numbers begin from 1 and not 0. This means that the first row has an index of 1, the second row has an index of 2, and so on.
To begin indexes from 0, please use the row_index_offset setting like so.
functions.php
add_filter('acf/settings/row_index_offset', '__return_zero');
update_sub_row()
Updates a row of data for an existing Repeater or Flexible Content sub field value.
This function can be used inside or outside of a
have_rows() loop. When used inside, the current row will be used to update the sub field value. When used outside, the rows and parents must be specified to target the correct value place.
Please note this function is used to modify a sub field value. To modify a parent field value, please use the update_row() function.
Parameters
update_sub_row($selector, $row, $value, [$post_id])
$selector (string|array) (Required) The sub field name or key, or an array of ancestors and row numbers.
$row (int) (Required) The row number to update.
$value (array) (Required) The new row data.
$post_id (mixed) (Optional) The post ID where the value is saved. Defaults to the current post.
Return
(bool) True on successful update, false on failure.
Change Log
Added in version 5.4.7
Update a sub row inside of a have_rows() loop
This example shows how to update a row of data to an existing nested repeater field called ‘images’. This nested repeater field contains 3 sub fields (‘image’, ‘alt’, ‘link’).
// Loop over all staff members.
if( have_rows('staff_members') ) {
while( have_rows('staff_members') ) {
the_row();
// Get this staff member's name.
$name = get_sub_field('name');
// Update this staff member's first image.
$value = array(
'image' => 123,
'alt' => "The first photo of $name",
'link' => 'http://website.com'
);
update_sub_row('images', 1, $value);
}
}
Update a sub row outside of a have_rows() loop
This example shows how to update a row of data outside of a
have_rows() loop. Here, the
$selector parameter is provided an array containing a mixture of field names and row numbers. This array should read from left to right, the parents to children relationship separated by the row number.
Please see notes regarding index offset.
// Update the first staff member's first image.
$value = array(
'image' => 123,
'alt' => "The first photo of the first staff member",
'link' => 'http://website.com'
);
update_sub_row( array('staff_members', 1, 'images'), 1, $value );
// Update the first staff member's second image.
update_sub_row( array('staff_members', 1, 'images'), 2, $value );
Notes
Index offset
When targeting a sub field using a specific row number, please note that row numbers begin from 1 and not 0. This means that the first row has an index of 1, the second row has an index of 2, and so on.
To begin indexes from 0, please use the row_index_offset setting like so.
functions.php
add_filter('acf/settings/row_index_offset', '__return_zero');
URL
Description
The URL field is a text input specifically designed for storing web addresses.
Screenshots
Creating a URL field in the UI.
The Presentation tab of the URL field allows you to provide instructions to content editors, show placeholder text, and define wrapper attributes.
How the field is displayed to content editors in WP Admin.
Settings
Default Value
The default value shown when creating a new post.
Required
Found on the Validation tab, this requires a valid URL be provided as the input and prevents the field from accepting empty values. Defaults to off.
Instructions
Shows instructions when submitting data.
Placeholder Text
Appears within input when no value exists.
Template usage
Display value
This example demonstrates how to use a URL field named “sales_url” within an anchor tag. We don’t recommend outputting any ACF value without any sort of protection or escaping.
User
Description
The User field allows the selection of one or more users.
This field type is useful for creating relationships between data objects. It stores its value as the WordPress user ID, and can return the full
WP_User data on retrieval.
Screenshots
Creating a User field in an ACF field group.
The User field UI as it might appear to content editors, with users sorted by role.
Changelog
Added
return_format setting in version 5.6.9.
Settings
Filter by Role
Filters the available users by one or more user roles. Defaults to an empty string.
Return Format
Specifies the returned value format. Defaults to “User Array” in the plugin’s UI, and ‘array’ in PHP. “User Array” returns an array of user data, “User Object” returns the
WP_User object, and “User ID” returns the user ID.
Select Multiple
Allows content editors to select multiple values. Defaults to off.
Required
Enabling this prevents the field from accepting empty values. Defaults to off.
Allow Null
Allows an empty value to be saved. Defaults to off.
Instructions
Shows instructions when submitting data.
Conditional Logic
Enabling this setting allows you to customize the logic which determines if the current field should be visible. Groups of conditional logic rules can be created to allow for multiple and/or statements.
Bidirectional
Found on the Advanced tab, enabling this setting allows you to update a value in the target fields for each value selected for this field, adding or removing the Post ID, Taxonomy ID, or User ID of the item being updated.
For programmatic documentation, please see our guide to registering fields via PHP.
Template usage
Display a single selected user
This example demonstrates how to display a selected user (‘multiple’ = false, return_format = ‘array’).
Display multiple selected users
This example demonstrates how to display multiple selected users in a list. (‘multiple’ = true, return_format = ‘object’).
Using acf_form to create a new post
This article will cover how to create a form on the front end of your website to add new content.
Getting started
If you have not already, please familiarize yourself with the acf form functions. Two functions are available to create a working form in a template file.
Name
Description
acf_form_head()
This function is placed at the top of a template file and will register the necessary assets (CSS/JS), process the saved data, and redirect the url. This function does not accepts any parameters
acf_form()
This function is placed within a template file and will create the form’s HTML. This function accepts an array of settings to customize the form
Settings
The acf_form() parameter contains two settings called
post_id and
new_post. By using these settings correctly, a new post an be created using the form data.
The
post_id setting is used to edit an existing post, but when set to ‘new_post’, a new post will be created.
The
new_post setting is used to specify an array of elements that make up a post. These elements can be found in the wp_insert_post() documentation.
Examples
Basic
This form will create a new post.
page-new-post.php
functions.php
add_action('acf/save_post', 'my_save_post');
function my_save_post( $post_id ) {
// bail early if not a contact_form post
if( get_post_type($post_id) !== 'contact_form' ) {
return;
}
// bail early if editing in admin
if( is_admin() ) {
return;
}
// vars
$post = get_post( $post_id );
// get custom fields (field group exists for content_form)
$name = get_field('name', $post_id);
$email = get_field('email', $post_id);
// email data
$to = 'contact@website.com';
$headers = 'From: ' . $name . ' <' . $email . '>' . "\r\n";
$subject = $post->post_title;
$body = $post->post_content;
// send email
wp_mail($to, $subject, $body, $headers );
}
Using Context With ACF Blocks
ACF Blocks opens the door to more creative building possibilities. One example we previously explored was using InnerBlocks and parent/child relationships, where we nested ACF Blocks inside of each other. Nesting your ACF Blocks organizes your block structure and codebase while allowing for a refined editorial experience.
Ready to dive into the code?
You can dive right in by downloading the tt4child.zip! Be sure to have the TwentyTwentyFour theme installed as well as ACF PRO.
ACF 6.0 introduced support for WordPress’s block context. Block context enables higher-level blocks, such as parent blocks, to supply values that descendant blocks within the same structure can utilize. This functionality permits direct child blocks and blocks further down the hierarchy to receive values from a parent block. This process occurs without the necessity for embedding these values directly into the code or establishing a direct link between the parent and descendant blocks.
It is critical to note that block context only flows downward from parent blocks, and it’s not possible to share data upward from child blocks to their parent.
Creating Block Context
Block context is defined in the block’s
block.json, just like other block properties and attributes. The relationship of block context relies on there being a block that is the provider and a block that is the consumer of the providing block’s context.
The provider block defines
providesContext in its
block.json:
Example block that provides context
{
...rest of block.json
"providesContext": {
"acf/fields": "data"
},
...rest of block.json
}
And the consumer block defines the
usesContext in its
block.json:
Example block that consumes context
{
...rest of block.json
"usesContext": ["acf/fields"],
...rest of block.json
}
Displaying Context Values in ACF Blocks
Once you have established a binding context relationship between your ACF Blocks, you can reference values from the parent block in any nested block by checking and outputting the value in the child block’s template.
One thing to note: ACF Blocks use field keys in the block editor, and block data is only hydrated to field names upon saving. Because of this, you should use
$context['acf/fields']['field_key'] to get access to the data inside your template if it exists, before defaulting back to
$context['acf/fields']['field_name'] if it doesn’t. This supports both backend and frontend output of context data.
Also, whenever the providing parent block’s field value is updated in the editor, the child block that consumes the parent’s context will be automatically re-rendered.
You should also be aware that sharing ACF data with your child blocks will result in sending the complete ACF field data back to the server for rendering previews. This may have performance implications for your blocks in the editor.
Also, ACF automatically passes the
postId and
postType down through block context by default, which expedites nesting your ACF Block in the Query Loop block.
https://www.advancedcustomfields.com/wp-content/uploads/2024/01/ACF-block-context-demo.mp4
Conclusion
In summary, ACF Blocks introduces a versatile and powerful way to extend the functionality of the WordPress editor, offering a rich set of features that enhance both the developer and editor experiences. By leveraging InnerBlocks and parent/child relationships, you can structure your content with greater flexibility and precision. The introduction of block context in ACF 6.0 further amplifies this by allowing data to flow seamlessly between blocks, removing the need for direct code embeddings or explicit relationships.
This advancement simplifies the development process and opens up a myriad of creative possibilities for content management and presentation. Whether you are building complex layouts, crafting unique editorial experiences, or providing dynamic content relationships, ACF Blocks equipped with block context capabilities are an invaluable tool in your WordPress development arsenal.
Remember, while the power of ACF Blocks and block context brings great flexibility, it’s important to consider performance implications and the best practices for data management to ensure your site remains fast and responsive. With the right approach, ACF Blocks can transform the way you think about and build with WordPress.
Download the tt4child.zip and dive into the code to see firsthand how ACF Blocks can revolutionize your WordPress projects. Happy coding!
Using the ACF Datastore
The ACF datastore is an opt-in feature that integrates ACF fields with Gutenberg’s native
wp.data store. When enabled, ACF field values are saved through WordPress’s REST API instead of the legacy metabox AJAX request, enabling full revision and autosave support.
Note: The datastore is currently available in ACF PRO while we collect feedback from early adopters.
Requirements
ACF PRO 6.8.1 or later
WordPress 6.7 or later
Enabling the Datastore
The datastore is disabled by default. To enable it, add this filter to your theme or plugin:
add_filter( 'acf/settings/enable_datastore', '__return_true' );
You can also enable it conditionally:
add_filter( 'acf/settings/enable_datastore', function( $enabled ) {
// Only enable for specific post types
if ( get_post_type() === 'product' ) {
return true;
}
return $enabled;
});
Features
Revision Support
When the datastore is enabled, ACF field values are included in post revisions. This means you can:
View ACF field changes in the revision diff screen
Restore ACF field values when reverting to a previous revision
See exactly what changed between versions
Autosave Support
ACF field values are automatically captured in WordPress autosaves. If the browser crashes or the user navigates away, their ACF field data is preserved alongside the post content.
Block Bindings Support
When the datastore is enabled, ACF fields become available in WordPress 6.7’s Block Bindings UI. You can bind Heading, Paragraph, Image, and Button blocks to ACF fields directly from the editor’s Attributes panel, with live preview and in-place editing.
To use block bindings, you also need to enable “Allow Access to Value in Editor UI” for each field in the Presentation tab of the field settings.
See Block Bindings for full documentation.
JavaScript API
The datastore exposes a
wp.data store called
acf/fields for reading and writing field values programmatically.
Reading Field Values
// Get a single field value
const value = wp.data.select( 'acf/fields' ).getFieldValue( 'field_name' );
// Get all field values
const allValues = wp.data.select( 'acf/fields' ).getFieldValues();
Writing Field Values
// Set a single field value
wp.data.dispatch( 'acf/fields' ).setFieldValue( 'field_name', 'new value' );
// Set multiple field values
wp.data.dispatch( 'acf/fields' ).setFieldValues({
field_name: 'value',
another_field: 'another value'
});
Subscribing to Changes
wp.data.subscribe( () => {
const value = wp.data.select( 'acf/fields' ).getFieldValue( 'my_field' );
console.log( 'Field value changed:', value );
});
Legacy API Compatibility
The datastore maintains bidirectional sync with ACF’s existing jQuery-based field DOM. This means:
Changes made via the JavaScript API update the field inputs in the metabox
Changes made by editing fields in the metabox update the datastore
Existing code using
acf.getField() continues to work
You can also use
acf.store.set() to write values, which syncs to both the DOM and the wp.data store.
Migration Considerations
Save Flow Changes
When the datastore is enabled, ACF fields are saved through Gutenberg’s REST API rather than the legacy metabox AJAX request. If you have custom JavaScript hooked into ACF’s save events through the metabox path, you’ll need to update it to hook into Gutenberg’s REST save instead.
Before (legacy save):
acf.addAction( 'submit', function( $form ) {
// This won't fire with the datastore enabled
});
After (REST save):
wp.data.subscribe( () => {
const isSaving = wp.data.select( 'core/editor' ).isSavingPost();
// Handle save state
});
Existing Revision Handling
If you’ve built custom revision handling for ACF fields (using
wp_save_post_revision or similar), you may see double-handling when the datastore is enabled since ACF values are now natively included in revisions.
Review any custom revision code and remove it if it’s now redundant.
Known Limitations
Nested Relational Fields
Relational sub-fields inside Repeaters or Groups are not covered by the AJAX label hydration in this release. Only top-level relational fields hydrate correctly when the value isn’t in the pre-rendered options.
Workarounds:
– Keep relational fields at the top level where possible
– Pre-populate the field’s choices on the server using the
acf/fields/{field_type}/query filter
– After setting a value programmatically, reload the page to let the field’s render path fetch the label
WordPress Version Requirement
The
acf/settings/enable_datastore filter has no effect on WordPress versions before 6.7. The datastore requires APIs that were stabilized in that release.
Disabling the Datastore
If you encounter issues after enabling the datastore, you can disable it to immediately revert to the legacy save path:
add_filter( 'acf/settings/enable_datastore', '__return_false', 100 );
This returns ACF to exactly the same behavior as version 6.8.0 with no other code changes required.
Troubleshooting
Fields Not Saving
Verify WordPress 6.7+ is installed
Check that the filter is being applied (use
acf_is_using_datastore() to verify)
Look for JavaScript errors in the browser console
Ensure no other plugins are interfering with the REST API save
Custom Save Hooks Not Firing
If your custom JavaScript save hooks stopped working, they’re likely hooked into the legacy metabox AJAX path. Update them to use Gutenberg’s
wp.data subscriptions instead.
Revision Diff Shows Raw Data
ACF field values are stored in
meta._acf for the datastore. The revision diff will show the serialized values. This is expected behavior.
Troubleshooting Validation Security Nonce Errors
With ACF 6.3.12 and above, there are two potential errors that can appear if ACF is unable to verify the security nonce while validating your fields.
ACF was unable to perform validation because the provided nonce failed verification.
This error indicates that ACF received a security nonce, but the nonce failed verification. This can occur if you’ve left the browser open for a long time while editing a page. To confirm if that’s the case, try logging out and back in again.
If that doesn’t help, and you have a development/staging version of the site, you can try deactivating any other plugins and themes to rule out a potential conflict.
ACF was unable to perform validation because no nonce was received by the server.
This happens when ACF doesn’t receive a security nonce at all. This most commonly happens when the PHP
max_input_vars setting is too low and there are lots of ACF fields present on the page. To correct this, ask your host to see what your current
max_input_vars setting is, and if it can be increased to at least 10,000.
If you’ve tried the above and are still running into this issue, please contact our support team and we’ll be glad to help troubleshoot further.
What’s New With ACF Blocks in ACF 6
ACF 6.0 includes ACF Blocks Version 2. This next generation of ACF Blocks brings us much closer to the native block experience, while still giving you the PHP based templating language you know as a WordPress developer.
In the last few releases of WordPress, Gutenberg has made significant changes to all aspects of the block editor and block registration, and this has impacted ACF Blocks. We’ve not been able to move as fast as we would have liked on implementing changes to support these new features for back compatibility reasons. ACF 6.0 ships with a new block versioning system, allowing you to opt in to new versions which will change things like the markup and structure of ACF Blocks in both the backend and frontend, and may require updates to your theme to support.
Backwards Compatibility
The changes to blocks in ACF 6.0 are designed to be backwards compatible with ACF 5.x, with one notable exception. Due to the changes in block IDs, if you use
parse_blocks() to read data from an ACF Block, it will no longer have a block ID present in that data. For workarounds to this, see our examples for adding a block ID back in.
Whilst we recommend users upgrade to block.json blocks to take advantage of new and upcoming WordPress features if they can, blocks registered with
acf_register_block_type() will continue to work with ACF 6.
Block.json Support
Since WordPress 5.8, WordPress has supported – and recommended – that blocks are registered through a JSON configuration file. All of the WordPress Block Documentation was migrated to only show
block.json configuration objects, and it became confusing for users to know what WordPress configuration options were usable in ACF PRO. ACF 6.0 introduces support for
block.json registration of blocks with ACF.
For blocks registered through a
block.json file, you can mark them as ACF Blocks by adding a new ACF configuration key to the JSON file, which contains the ACF specific configuration, for example:
{
"name": "all-fields-block",
"title": "All Fields Test Block",
"description": "All fields test block",
"style": "file:./all-fields-block.css",
"category": "theme",
"icon": "admin-comments",
"apiVersion": 2,
"keywords": [
"test",
"quote"
],
"acf": {
"mode": "preview",
"renderTemplate": "all-fields-block.php",
"postTypes": [ "post" ]
},
"styles": [
{ "name": "default", "label": "Default", "isDefault": true },
{ "name": "red", "label": "Red" },
{ "name": "green", "label": "Green" },
{ "name": "blue", "label": "Blue" }
],
"supports": {
"align": true,
"anchor": true,
"alignContent": false,
"color": {
"text": true,
"background": true,
"link": true
},
"alignText": true,
"spacing": {
"margin": [
"top",
"bottom"
],
"padding": true
},
"typography": {
"lineHeight": true,
"fontSize": true
},
"fullHeight": true
},
"attributes": {
"backgroundColor": {
"type": "string",
"default": "purple"
}
},
"example": {
"attributes": {
"data": {
"text": "This is an example text field",
"text_area": "This is an example text area field"
}
}
}
}
You then need to use the standard WordPress block registration function
register_block_type, rather than
acf_register_block_type:
register_block_type( 'path/to/folder/containing/block.json' );
If you don’t specify a namespace for your block like in our example above:
"name": "all-fields-block",, ACF will automatically add it if it is an ACF block to become the equivalent of
"name": "acf/all-fields-block" although you are now free to use your own namespace for your blocks.
This new method of registering blocks is now the recommended way to register a block, replacing the
acf_register_block_type function.
The
renderTemplate property should either be a full path to the template file, or relative to the location of the JSON file.
You can also now specify default attributes for your block, as shown in our example above in the
attributes key. You can use this to set defaults for the WordPress provided block attributes, such as
backgroundColor.
WordPress uses a camelCase format inside JSON files, and ACF adopts that too. Configuration keys such as
render_template when used in
acf_register_block_type need to be
renderTemplate when used in JSON, likewise
align_content and
full_height should be
alignContent and
fullHeight for example. All previous configuration objects are supported, except for
enqueue_style,
enqueue_script and
enqueue_assets for reasons explained below:
Block Asset Loading
When ACF Blocks was first introduced, it supported enqueueing block specific assets before WordPress had native support. Recent (and upcoming) updates to Gutenberg will require these assets to be loaded using specific WordPress asset configuration keys such as
editorScript,
script,
editorStyle and
style.
WordPress 5.9 users who use Block Styles may have noticed that the ACF registration of styles was not applied to those previews, which is why all ACF Block users should migrate their blocks to use those WordPress provided methods of asset loading.
The previous methods of asset loading in ACF Blocks will continue to work for the time being in
acf_register_block_type, but as WordPress continues to make changes across releases we expect that to stop working – especially with the upcoming plan to isolate each block in an iframe.
Block ID Changes
ACF 6.0 will no longer save block IDs to the block comment of ACF Blocks. This affects all versions of ACF Blocks and means you can easily copy and paste blocks, simplify your post type templates, use your blocks in block patterns, or duplicate blocks without having any issues where block IDs clash.
This change shouldn’t affect most users, since we still generate a
$block['id'] for your templates as we know some users use that for element IDs, but the format of those IDs will change. Just like in ACF 5.x, block IDs may be duplicated, but the number of situations where this can happen has been reduced significantly to one: if you have multiple blocks on the same page with the exact same data, attributes and context.
Due to the dynamic block ID generation, this change is backwards compatible for the majority of users, unless you use
parse_blocks() to read ACF data, and rely on it returning a block ID.
Internally, ACF builds the new dynamic block ID from a md5 hash of the block’s attributes and context, but as WordPress block context may not be available in
parse_blocks() so you will not reliably be able to match our dynamic block ID with the result of
parse_blocks().
There are a couple of options to get around this. You could generate your own hash through a checksum of the sorted data attributes, use user entered anchors, or you could automatically generate an ID that is saved server side whenever a block is saved using the
acf/pre_save_block filter.
Here’s a couple of possible examples, the first will automatically generate an anchor attribute if the user doesn’t enter one:
add_filter(
'acf/pre_save_block',
function( $attributes ) {
if ( empty( $attributes['anchor'] ) ) {
$attributes['anchor'] = 'acf-block-' . uniqid();
}
return $attributes;
}
);
Alternatively, you could generate a new custom ID attribute which would be used on the front-end too if set, but note that it will be regenerated each time the block is saved, and this id will not be used in the backend editor:
add_filter(
'acf/pre_save_block',
function( $attributes ) {
if ( empty( $attributes['id'] ) ) {
$attributes['id'] = 'acf-block-' . uniqid();
}
return $attributes;
}
);
Block Versioning Details
A new
blockVersion (inside the ACF key in
block.json) or
acf_block_version (if using
acf_register_block_type) key is now supported. For blocks registered via
block.json, this defaults to
2. For
acf_register_block_type, this defaults to
1.
For now, the main change between the two versions is the way
markup is rendered. If you use block version 2 (which requires WordPress 5.8+), the container markup when using InnerBlocks will match between backend and frontend rendering, with any inner blocks wrapped in a new (and single level)
element. This can help make your CSS layouts easier, as you can be sure both render views have the same markup.
Whilst this wrapper must appear in the backend block editor, if you wish to disable it for the frontend, you can do that with a new filter, and optionally enable or disable it based on the block name:
add_filter( 'acf/blocks/wrap_frontend_innerblocks', 'acf_should_wrap_innerblocks', 10, 2 );
function acf_should_wrap_innerblocks( $wrap, $name ) {
if ( $name == 'acf/test-block' ) {
return true;
}
return false;
}
If you just wish to modify the class being used for the wrapper, instead of the default
acf-inner-blocks-container you can simply add a class to your
tag inside your block template, such as …
Block Registry Standardization
In previous versions of ACF PRO, a lightweight shim of the block configuration was registered in PHP, and then the full configuration registered in JS.
In this build of ACF, the full block configuration is now saved in the WordPress PHP Block Registry. This makes it easier for you to access details of the block configuration in your templates or render callbacks.
Block Context Changes
During development, we saw a conversation on twitter discussing the viability of using data from an ACF Block inside blocks contained in its
children.
We suspected this would be possible using block context, the system core blocks like the Query Loop block use to know the current post type.
ACF 6.0 introduces support for block context. This means if you want to pass ACF field data from a parent block to an InnerBlock, the InnerBlock will automatically reload the template, showing changes live as you make changes to fields in the parent. This support should also improve the reliability of blocks used inside Query Loop blocks.
To enable this, you need to tell WordPress to share the ACF
data attribute to its child blocks with a custom key (
acf/fields in our example) with
providesContext in block.json:
"providesContext": {"acf/fields": "data"}
Then, to consume that context in an ACF block, you need to pass the context key in
usesContext:
"usesContext": ["acf/fields"],
One thing to note: ACF Blocks use field keys in the block editor, and block data is only hydrated to field names upon save. Because of this, you should use
$context['acf/fields']['field_key'] to get access the data inside your template if it exists before defaulting back to
$context['acf/fields']['field_name'] if it doesn’t exist to support both backend and frontend output of context data.
You should also be aware that if you share ACF data through to your child blocks, the full ACF fields data will be sent back to the server in order to render previews. This may have performance implications for your blocks in the editor.
Blocks Without Fields
With Full Site Editing and the Query Loop block, it’s now much more likely you might want to use ACF Blocks without any specific fields attached to the block, for example because it’s showing post templating elements like titles or post content, or because you want to display fields which are added on the post being displayed, rather than from the block.
ACF 6.0 adds support for this by providing advisory text when a block has no fields assigned, whereas previously the block’s edit mode would simply be blank and not selectable.
Developers who wish to modify the default advisory text can do so with the new
acf/blocks/no_fields_assigned_message filter which offers 2 parameters: the message to be displayed and the name of the block it will be displayed on.
Block Bug Fixes
We’ve also fixed a number of other bugs which apply to all versions of ACF Blocks.
The
render_block_preview JavaScript event is now always fired every time a block preview is displayed, rather than just the first time.
Accordion fields inside an ACF block now are styled to match the native sidebar experience of the block editor.
ACF Block preloading now works again for blocks saved in edit mode, and for blocks without any saved field data (due to changes in block preloading for the removal of Block IDs, you may need to edit each block once before it can be preloaded.)
ACF Block edit forms will now behave correctly if they’re not visible when loaded.
Working with Nested Repeaters
Creating and displaying nested repeater / flexible content fields is very easy using the Advanced Custom Fields plugin. This article will demonstrate how to build a simple to-do list that uses a nested repeater to output groups of items.
Field group
Below is a screenshot showing the field group used for this to-do list, and the location rules indicating when this field group should appear.
Data
Below is a screenshot showing a page which this field group appears on. As shown above, a page template of “To-do List” was used as a location rule to attach the field group to the page.
Template
Now that we have created the field group and entered data for our to-do list, we can now loop over and display the data in our template. This tutorial assumes a template file for “To-do List” exists, so let’s edit that file. In the following code we will be using these functions:
have_rows() – allows us to loop through the available rows in a repeater / flexible content field
get_sub_field() – returns the value of a sub field (from the current repeater in “has_sub_field”)
the_sub_field() – displays the value of a sub field (from the current repeater in “has_sub_field”)
>
Here is a screenshot showing the HTML produced from the above code.
#gallery-3 {
margin: auto;
}
#gallery-3 .gallery-item {
float: left;
margin-top: 10px;
text-align: center;
width: 50%;
}
#gallery-3 img {
border: 2px solid #cfcfcf;
}
#gallery-3 .gallery-caption {
margin-left: 0;
}
/* see gallery_shortcode() in wp-includes/media.php */
Conclusion
Working with nested repeaters is easy, but can sometimes become confusing. To make life easier, try to use simple field names. Remember that sub fields can also use the same names as the ancestors so there’s no need to for long unique field names.
wp acf json export
Exports field groups, post types, taxonomies, and options pages to a JSON file.
Description
Exports ACF items to a JSON file, replicating the functionality of the export tool in the WordPress admin. You can export all items or filter by specific types and keys.
Options
wp acf json export [--field-groups=] [--post-types=] [--taxonomies=] [--options-pages=] [--dir=] [--stdout]
--field-groups=
(string) Optional. Export specific field groups by key or label, comma separated.
--post-types=
(string) Optional. Export specific post types by key or label, comma separated.
--taxonomies=
(string) Optional. Export specific taxonomies by key or label, comma separated.
--options-pages=
(string) Optional. Export specific options pages by key or label, comma separated. Requires ACF PRO.
--dir=
(string) Required (unless using
--stdout). Directory path to write the JSON file to.
--stdout
(flag) Optional. Output JSON to stdout instead of writing to a file. Useful for piping to other commands.
Examples
Export all items to a directory
$ wp acf json export --dir=./exports/
Success: Exported 15 item(s) to ./exports/acf-export-2025-01-01.json
Export specific field groups by key
$ wp acf json export --field-groups=group_abc123,group_def456 --dir=./
Export a field group by label
$ wp acf json export --field-groups="My Field Group" --dir=./
Export multiple item types
$ wp acf json export --field-groups=group_abc123 --post-types=post_type_def456 --dir=./exports/
Export to stdout for piping
# Output raw JSON
$ wp acf json export --stdout
# Pretty print with jq
$ wp acf json export --field-groups=group_abc123 --stdout | jq .
# Pipe to another command
$ wp acf json export --stdout > backup.json
Backup before deployment
# Export current state before sync
$ wp acf json export --dir=./backups/
$ wp acf json sync
Return
When using
--dir, the command creates a file named
acf-export-YYYY-MM-DD.json in the specified directory and outputs a success message with the item count and file path.
When using
--stdout, the JSON is output directly to the terminal.
Notes
You must specify either
--dir or
--stdout
Cannot use both
--dir and
--stdout together
If no filter options are provided, all items across all types are exported
Items can be specified by their ACF key (e.g.,
group_abc123) or by their title/label
The export includes all fields for field groups
Options pages require ACF PRO
Errors
Error
Cause
You must specify –dir or –stdout
Neither output option was provided
Cannot specify both –dir and –stdout
Both output options were provided
Directory not found
The specified directory does not exist
Directory is not writable
The directory exists but cannot be written to
No items found to export
No items match the specified filters
wp acf json import
Imports field groups, post types, taxonomies, and options pages from a JSON file.
Description
Reads an ACF export JSON file and imports the items into the database, replicating the functionality of the import UI in the WordPress admin. If an item with the same key already exists, it will be updated.
Options
wp acf json import
(string) Required. Path to the JSON file to import.
Examples
Import from an export file
$ wp acf json import ./acf-export-2025-01-01.json
Imported field-group: My Field Group (group_abc123)
Imported post-type: Book (post_type_def456)
Success: Imported 2 item(s).
Import a single field group JSON file
$ wp acf json import ./group_abc123.json
Imported field-group: Product Fields (group_abc123)
Success: Imported 1 item(s).
Re-import to update existing items
$ wp acf json import ./acf-export.json
Updated field-group: My Field Group (group_abc123)
Success: Imported 1 item(s).
Import from acf-json directory file
$ wp acf json import ./wp-content/themes/mytheme/acf-json/group_abc123.json
Return
The command outputs each imported item with its action (Imported/Updated), type, title, and key.
Notes
The file must have a
.json extension
Supports both single item JSON files and export arrays containing multiple items
If an item with the same key exists, it will be updated rather than duplicated
Options pages require ACF PRO
Invalid JSON or items without keys are skipped with a warning
Errors
Error
Cause
File not found
The specified file path does not exist
File must have .json extension
The file is not a JSON file
Import file is empty or contains invalid JSON
The JSON could not be parsed
wp acf json status
Shows the sync status for ACF item types (field groups, post types, taxonomies, options pages).
Description
Displays how many items are pending sync. Items are considered “pending” when the JSON file is newer than the database entry, or when the item exists in JSON but not in the database.
Options
wp acf json status [--type=] [--detailed] [--format=]
--type=
(string) Optional. Limit to a specific item type. Defaults to all item types (field groups, post types, taxonomies, options pages).
–
field-group
–
post-type
–
taxonomy
–
options-page (ACF PRO only)
--detailed
(flag) Optional. Show detailed list of modified items instead of just counts.
--format=
(string) Optional. Output format. Default:
table
–
table
–
json
–
yaml
–
csv
Examples
Check all item types
$ wp acf json status
+---------------+---------+-------+----------------+
| Type | Pending | Total | Status |
+---------------+---------+-------+----------------+
| field-group | 3 | 12 | Sync available |
| post-type | 0 | 2 | In sync |
| taxonomy | 1 | 3 | Sync available |
| options-page | 0 | 1 | In sync |
+---------------+---------+-------+----------------+
4 item(s) pending sync. Run wp acf json sync to apply changes.
Check only field groups
$ wp acf json status --type=field-group
Show detailed list of pending items
$ wp acf json status --detailed
+-------------------+------------------+---------------+--------+
| Key | Title | Type | Action |
+-------------------+------------------+---------------+--------+
| group_abc123 | Product Fields | field-group | Update |
| group_def456 | Homepage | field-group | Create |
| taxonomy_ghi789 | Product Category | taxonomy | Update |
+-------------------+------------------+---------------+--------+
Output status as JSON for scripts
$ wp acf json status --format=json
[{"Type":"field-group","Pending":3,"Total":12,"Status":"Sync available"}]
CI/CD pipeline check
# Check if sync is needed before deployment
$ wp acf json status --format=json | jq '.[] | select(.Pending > 0)'
Notes
The status command is read-only and does not modify your database
Use this command to verify sync state before running
wp acf json sync
Options pages require ACF PRO
wp acf json sync
Syncs local JSON changes to the database.
Description
Imports pending JSON changes for ACF item types (field groups, post types, taxonomies, options pages). This command reads JSON files from your theme/plugin
acf-json directory and creates or updates the corresponding database entries.
Warning: This command modifies your database. Use
--dry-run first to preview changes before running on production.
Options
wp acf json sync [--type=] [--key=] [--dry-run]
--type=
(string) Optional. Limit sync to a specific item type. Defaults to all item types (field groups, post types, taxonomies, options pages).
–
field-group
–
post-type
–
taxonomy
–
options-page (ACF PRO only)
--key=
(string) Optional. Sync a specific item by its ACF key (e.g.,
group_abc123).
--dry-run
(flag) Optional. Preview what would be synced without making changes. Recommended for production deployments.
Examples
Preview what will be synced (safe)
$ wp acf json sync --dry-run
3 item(s) pending sync:
+-------------------+------------------+---------------+--------+
| Key | Title | Type | Action |
+-------------------+------------------+---------------+--------+
| group_abc123 | Product Fields | field-group | Update |
| group_def456 | Homepage | field-group | Create |
| taxonomy_ghi789 | Product Category | taxonomy | Update |
+-------------------+------------------+---------------+--------+
Sync all pending changes
$ wp acf json sync
Updated field-group: Product Fields (group_abc123)
Created field-group: Homepage (group_def456)
Updated taxonomy: Product Category (taxonomy_ghi789)
Success: 3 item(s) synced.
Sync only field groups
$ wp acf json sync --type=field-group
Sync a specific field group
$ wp acf json sync --key=group_abc123
Updated field-group: Product Fields (group_abc123)
Success: 1 item(s) synced.
CI/CD deployment workflow
# Preview changes
$ wp acf json sync --dry-run
# Apply changes
$ wp acf json sync
# Verify sync completed
$ wp acf json status
Notes
Always run
--dry-run first on production environments
The sync command replicates the “Sync” functionality in the WordPress admin
Items marked as private are skipped
If no items are pending, the command outputs “Everything is already in sync.”
Options pages require ACF PRO
wp acf json
Manages ACF JSON import, export, and synchronization for item types (field groups, post types, taxonomies, options pages).
Description
The
wp acf json command provides CLI access to ACF’s Local JSON functionality, enabling automated workflows for version control, deployments, and CI/CD pipelines.
Available Commands
Command
Description
wp acf json status
Shows the sync status for ACF items
wp acf json sync
Syncs local JSON changes to the database
wp acf json import
Imports items from a JSON file
wp acf json export
Exports items to a JSON file
Examples
# Show sync status for all item types
$ wp acf json status
# Sync all pending local JSON changes to database
$ wp acf json sync
# Import from a JSON file
$ wp acf json import ./acf-export.json
# Export all items to a directory
$ wp acf json export --dir=./exports/
# Export to stdout
$ wp acf json export --stdout
Requirements
ACF 6.8 or later
WP-CLI 2.0 or later
Options pages require ACF PRO
Notes
These commands replicate the functionality available in the WordPress admin UI, making them ideal for:
CI/CD deployments: Sync JSON files to database as part of your deployment pipeline
Version control workflows: Export field groups to JSON for commit to Git
Automated testing: Set up test environments with consistent field configurations
Multi-environment management: Move configurations between staging and production
WP-CLI Commands
All available WP-CLI commands for ACF and ACF PRO, with links to documentation for usage and subcommands.
Commands
Command
Subcommand
Description
wp acf json
Manages ACF JSON import, export, and synchronization
status
Shows the sync status for ACF items
sync
Syncs local JSON changes to the database
import
Imports items from a JSON file
export
Exports items to a JSON file
Global Parameters
These parameters are available for all
wp acf subcommands:
--path=
: Path to the WordPress installation.
--url=
: Target site URL (for multisite).
--user=
: Set the WordPress user for the command.
Examples
# Show sync status for all ACF items
wp acf json status
# Sync all pending local JSON changes to database
wp acf json sync
# Export field groups to JSON files
wp acf json export --type=field-group
Requirements
ACF 6.8 or later
WP-CLI 2.0 or later
WP REST API Integration
Since version 5.11, ACF has included support for viewing and managing custom fields via the WordPress REST API. This allows developers to access and edit their custom field data using default WP REST API endpoints, or build custom themes using React, Vue, or any other JavaScript library.
Endpoints
Any custom field groups added to WordPress data like posts (including custom post types), users, and categories (including custom taxonomies) will be available in their respective WP REST API endpoints, namely:
/{post-type}
posts, pages, custom-post-types, etc.
/{post-type}/{post_id}
/{post-type}/{post_id}/revisions
/{post-type}/{post_id}/revisions/{revision_id}
/{post-type}/{post_id}/autosaves
/{post-type}/{post_id}/autosaves/{autosave_id}
/users
/users/{user_id}
/users/me
/categories
/categories/{category_id}
/{custom-taxonomy}/{term_id}
Enabling the REST API for Your ACF Fields
By default, field groups are not visible in the WP REST API. You must opt-in if you want them to show in the WP REST API.
You can enable REST API visibility for a specific field group in its Settings area. Click the Group Settings tab, and then click Show in REST API.
Using the REST API With Custom Post Types and Taxonomies
By default, custom post types and taxonomies created in ACF are visible in the WP REST API, with a default namespace of
wp/v2 and default controller class of
WP_REST_Posts_Controller for post types, and
WP_REST_Terms_Controller for taxonomies.
To change the default REST API visibility or settings for custom post types, navigate to ACF > Post Types, and select or register a custom post type. Toggle on Advanced Configuration to open “Advanced Settings”. Click the REST API tab to access the settings, including visibility, namespace, and controller class. This tab also allows you to create a base URL for the post type REST API URLs.
A similar process can be followed for custom taxonomies.
Request Methods
The following three request methods can be used in conjunction with ACF data:
GET requests allow you to view ACF data.
OPTIONS requests allow you to view the schema for the ACF data.
POST requests allow you to update any ACF fields, and require you to authenticate to perform the request.
GET request
A GET request will show the ACF data in the REST response.
In the following example, we’ve configured a custom post type
book, and an ACF field group for all books, with Author (Text), Author Bio (WYSIWYG), and Author Image (Image) fields. We’ll add data to each book for these custom fields.
Performing a GET request to
https://hellfish.media/wp-json/wp/v2/book/{ID}, where
{ID} is the ID of the given book, shows the custom field data in the
acf JSON object, just below the
template data.
{
"id": 3944,
"date": "2021-11-15T10:11:38",
"date_gmt": "2021-11-15T10:11:38",
"guid": {
"rendered": "https://hellfish.media/?post_type=book&p=3944"
},
"modified": "2021-11-15T10:11:52",
"modified_gmt": "2021-11-15T10:11:52",
"slug": "tales-of-the-flying-hellfish",
"status": "publish",
"type": "book",
"link": "https://hellfish.media/book/tales-of-the-flying-hellfish/",
"title": {
"rendered": "Tales of the Flying Hellfish"
},
"content": {
"rendered": "
Presumably, the Flying Hellfish was first dispatched to Normandy for the Invasion of Normandy.
\n
Burns was always the unit’s troublemaker. The Hellfish got stuck with Burns because he obstructed a probe from J. Edgar Hoover, thus resulting in his demotion. He faked his own death several times and even ruined Simpson’s chance to assassinate Adolf Hitler.
\n
At one point, near the end of the war, the unit stormed a German castle. While searching through it, Private Burns found a collection of stolen paintings. While discussing what they should do with them, Burns mentions the idea of tontine, where the members must enter into a contract of when the last surviving member inherits the paintings if the others pass away. The unit agrees for their own personal reasons (Gumble wanting to buy his way into high society, Abe not wanting to end up “in one of them old folk’s homes”). Everyone signs and shakes on this prospect.
\n
Ox was the first member to die because of a hernia he got while taking the crate out of the castle. Five more were killed in a parade float accident in 1979. After Asa Phelps died, only Burns and Abe remained. Later, Simpson gave Burns a dishonorable discharge from the Hellfish for trying to kill him and his grandson Bart, expelling him from the tontine and declaring himself the sole possessor of the paintings in default, much to Burns’ dismay. Unfortunately for Grampa and Bart, their victory was cut short when the U.S. State Department arrive and took the paintings, as they have been searching for them for 50 years to avoid any international incidents with the German government. The State Department then returns the paintings to their rightful owner’s descendant, Baron von Herzenberger.
\n
\n",
"protected": false
},
"template": "",
"acf": {
"author": "Abraham Simpson",
"author_bio": "Abraham Jebediah \"Abe\" Simpson II, commonly known as Grampa Simpson or simply Grampa, (born August 26, 1920) is a major character in The Simpsons. He is the oldest patriarch of the Simpson family, father of Homer Simpson, and paternal grandfather of Bart, Lisa and Maggie Simpson.",
"author_image": 3949
},
"_links": {
"self": [
{
"href": "https://hellfish.media/wp-json/wp/v2/book/3944"
}
],
"collection": [
{
"href": "https://hellfish.media/wp-json/wp/v2/book"
}
],
"about": [
{
"href": "https://hellfish.media/wp-json/wp/v2/types/book"
}
],
"wp:attachment": [
{
"href": "https://hellfish.media/wp-json/wp/v2/media?parent=3944"
}
],
"curies": [
{
"name": "wp",
"href": "https://api.w.org/{rel}",
"templated": true
}
]
}
}
OPTIONS request
Performing an OPTIONS request to a WordPress REST API endpoint allows you to see the schema for that data object, i.e., the available fields and their properties. For ACF fields, it allows you to see details for the field. For example, the basic Text field can have a “Max Length” character limit, which will show up in the schema for that field. Please see REST API Field Types for more details.
In our example post above, making an OPTIONS request will return the schema for the book, including data about the ACF fields we’ve set up.
{
"acf": {
"description": "ACF field data",
"type": "object",
"properties": {
"author": {
"type": [
"string",
"null"
],
"required": false
},
"author_bio": {
"type": [
"string",
"null"
],
"required": false
},
"author_image": {
"type": [
"integer",
"null"
],
"required": false
}
},
"required": false
}
}
POST Request
Performing a POST request will allow you to change data about the book. In our case, we can update the
author,
author_bio, and
author_image ACF fields. Because POST requests allow you to change data, you will need to authenticate your request, using one of the available authentication methods. To update your ACF field groups, you need to pass the data as a JSON encoded
acf object, using the same structure as it appears in the GET request. In our example above, to update the
author data, we would pass the following data:
{
"acf": {
"author": "Abraham (Abe) Simpson"
}
}
Below is an example of making a POST request via JavaScript, using the WordPress apiFetch utility:
import apiFetch from '@wordpress/api-fetch';
// POST
apiFetch( {
path: '/wp/v2/book/{ID}',
method: 'POST',
data: {
"acf": {
"author": "Abraham (Abe) Simpson",
}
},
} ).then( ( res ) => {
console.log( res );
} );
This will result in the
acf object on the book being updated.
Passing
null to your ACF fields deletes the content of the field:
import apiFetch from '@wordpress/api-fetch';
// POST
apiFetch( {
path: '/wp/v2/book/{ID}',
method: 'POST',
data: {
"acf": {
"author_bio": null
}
},
} ).then( ( res ) => {
console.log( res );
} );
This will result in the following
acf object on the book:
{
"acf": {
"author": "Abraham (Abe) Simpson",
"author_bio": "",
"author_image": 3949
}
}
Authentication
Since ACF uses core WP REST API endpoints, it uses core authentication methods (cookies and nonces) by default. This means if you’re building something in the WordPress dashboard, the code will be run in an already logged-in session, and no specific authentication is needed.
Should you wish to build something using the REST API endpoints outside a logged-in session (for example a JavaScript application powered by the REST API), you will need to authenticate any POST requests. There are a number of ways to handle this authentication, including Application Passwords (available in WordPress core) and the JSON Web Tokens plugin.
REST API Field Types
This table lists all ACF field types supported in the WP REST API.
Field Type
Types
Notes
Text
string, null
Text Area
string, null
Number
number, null
A string representation of a number is OK. e.g.; ‘123’.
Range
number, null
A string representation of a number is OK. e.g.; ‘123’.
Email
string (email), null
If value isn’t correct email format, request will fail with 400 bad request.
URL
string (uri), null
If string doesn’t have a protocol, the API will prefix http://.
Password
string, null
Image
integer, null
Expects attachment ID.
File
integer, null
Expects attachment ID.
Wysiwyg Editor
string, null
oEmbed
string (uri), null
If string doesn’t have a protocol, the API will prefix http://.
Gallery
number[], null
Array of attachment IDs.
Select
string, array, null
Will support either array or single string. Array to select multiple values.
Checkbox
string, array, null
Will support either array or single string.
Radio Button
string, null
Button Group
string, null
True/False
boolean, null
0 and 1 can also be sent through as a string.
Link
object, null
Object accepts title, url, & target properties.
Post Object
int, array, null
Will support either array or single string. Array to select multiple values.
Page Link
string, int, array, null
Will support either array or single string. Array to select multiple values.
Relationship
int, array, null
Will support either array or single string. Array or CSV to select multiple values.
Taxonomy
string, array, null
Will support either array or single string. Array to select multiple values.
User
string, array, null
Will support either array or single string. Array or CSV to select multiple values.
Google Map
object, null
Can be as simple as lat, lng properties. Supports: address, lat, lng, zoom, place_id, name, street_number, street_name, street_name_short, city, state, state_short, post_code, country, country_short.
Date Picker
string, null
A Ymd formatted date string.
Date Time Picker
string, null
A Y-m-d H:i:s formatted date time string.
Time Picker
string, null
A H:i:s formatted time string.
Color Picker
string, null
Either a 6-char hex code, an RGB or an RGBA string.
Message
Not currently supported in the REST API.
Accordion
Not currently supported in the REST API.
Tab
Not currently supported in the REST API.
Group
object,null
An object containing the subfield names and values.
Repeater
array, null
An array of objects, each representing a row of values mapped to sub field names.
Flexible Content
array, null
An array of objects, each representing a layout of values mapped to sub field names. acf_fc_layout is a required property for each object and must match the name of a layout configured on the flexible content field being updated.
Clone
object, null
Will only appear in REST requests if the Clone field is set to Group mode. When set to Group mode, this property will accept an object containing the subfield names and values. If it’s set to Seamless mode instead, the fields being cloned will show up in its place. If the Clone field is marked as required, all subfields will also be required.
Developer Notes
Disabling the ACF REST API system
It is possible to completely disable WP REST API support, by returning
false to the
acf/settings/rest_api_enabled filter. Doing so overrides any “Show in REST API” settings for your field groups, and completely disable WP REST API support for ACF:
add_filter( 'acf/settings/rest_api_enabled', '__return_false' );
Extending the REST API System
Scoping visible fields using the
_fields query parameter
The WP REST API
?_fields query parameter can be used to query just the
acf object, or specific fields within it.
// Return the acf object and all available fields:
/wp-json/wp/v2/book/{ID}?_fields=acf
// Return only a specific field from the acf object:
/wp-json/wp/v2/book/{ID}?_fields=acf.author,acf.author_bio
// Return a specific sub-field from a specific group field from the acf object:
/wp-json/wp/v2/book/{ID}?_fields=acf.author_meta.profile_url
Controlling the output format
Using the
acf_format parameter in your WP REST API request can be used to modify the output of a request.
The default value for this parameter is
light, and it passes the field values to the
format_value_for_rest() method on the specific field type object before rendering the data in the response. This applies very lightweight formatting and keeps the field output raw and in line with the schema. The example responses earlier in this document show the output of the
light format.
Passing
standard to the parameter will ensure that all fields will be formatted using the global
acf_format_value() ACF function. Below is an example of passing
standard to the parameter for our earlier example. As you can see, the
author_image field now includes more information about the image:
/wp-json/wp/v2/book/{ID}?_fields=acf&acf_format=standard
{
"acf": {
"author": "Abraham Simpson",
"author_bio": "
Abraham Jebediah “Abe” Simpson II, commonly known as Grampa Simpson or simply Grampa, (born August 26, 1920) is a major character in The Simpsons. He is the oldest patriarch of the Simpson family, father of Homer Simpson, and paternal grandfather of Bart, Lisa and Maggie Simpson.
\n",
"author_image": {
"ID": 3949,
"id": 3949,
"title": "Abraham_Simpson",
"filename": "Abraham_Simpson.webp",
"filesize": 28342,
"url": "https://hellfish.media/wp-content/uploads/2021/11/Abraham_Simpson.webp",
"link": "https://hellfish.media/book/tales-of-the-flying-hellfish/abraham_simpson/",
"alt": "",
"author": "1",
"description": "",
"caption": "",
"name": "abraham_simpson",
"status": "inherit",
"uploaded_to": 3944,
"date": "2021-11-15 10:11:31",
"modified": "2021-11-15 10:11:31",
"menu_order": 0,
"mime_type": "image/webp",
"type": "image",
"subtype": "webp",
"icon": "https://hellfish.media/wp-includes/images/media/default.png",
"width": 302,
"height": 482,
"sizes": {
"thumbnail": "https://hellfish.media/wp-content/uploads/2021/11/Abraham_Simpson-150x150.webp",
"thumbnail-width": 150,
"thumbnail-height": 150,
"medium": "https://hellfish.media/wp-content/uploads/2021/11/Abraham_Simpson-188x300.webp",
"medium-width": 188,
"medium-height": 300,
"medium_large": "https://hellfish.media/wp-content/uploads/2021/11/Abraham_Simpson.webp",
"medium_large-width": 302,
"medium_large-height": 482,
"large": "https://hellfish.media/wp-content/uploads/2021/11/Abraham_Simpson.webp",
"large-width": 302,
"large-height": 482,
"1536x1536": "https://hellfish.media/wp-content/uploads/2021/11/Abraham_Simpson.webp",
"1536x1536-width": 302,
"1536x1536-height": 482,
"2048x2048": "https://hellfish.media/wp-content/uploads/2021/11/Abraham_Simpson.webp",
"2048x2048-width": 302,
"2048x2048-height": 482,
"avatar": "https://hellfish.media/wp-content/uploads/2021/11/Abraham_Simpson.webp",
"avatar-width": 302,
"avatar-height": 482
}
}
}
}
Additionally, if you want to default the format to standard for all response data, you can enforce this by using the
acf/settings/rest_api_format filter:
add_filter( 'acf/settings/rest_api_format', function () {
return 'standard';
} );
Should you want to apply specific additional formatting on a WP REST API ACF field value, the
acf/rest/format_value_for_rest filter is applied on all ACF field values formatted for the WP REST API:
/**
* Filter the formatted value for a given field.
*
* @param mixed $value_formatted The formatted value.
* @param string|int $post_id The post ID of the current object.
* @param array $field The field array.
* @param mixed $value The raw/unformatted value.
* @param string $format The format applied to the field value.
*/
return apply_filters( 'acf/rest/format_value_for_rest', $value_formatted, $post_id, $field, $value, $format );
You can use this filter to apply your own formatting/output on the formatted field value. For example, implementing this code snippet will make every
acf field value in the response include the field label as part of the field object:
add_filter('acf/rest/format_value_for_rest', function ($value_formatted, $post_id, $field, $value, $format){
return array(
$field['label'] => $value_formatted
);
}, 10, 5);
{
"acf": {
"author": {
"Author": "Abraham Simpson"
},
"author_bio": {
"Author Bio": "Abraham Jebediah \"Abe\" Simpson II, commonly known as Grampa Simpson or simply Grampa, (born August 26, 1920) is a major character in The Simpsons. He is the oldest patriarch of the Simpson family, father of Homer Simpson, and paternal grandfather of Bart, Lisa and Maggie Simpson."
},
"author_image": {
"Author Image": 3949
}
}
}
It is also possible to use this filter for specific field types, or on specific fields by name or key.
Apply to all fields of type
text:
add_filter('acf/rest/format_value_for_rest/type=text', function ($value_formatted, $post_id, $field, $value, $format){
// return the overridden value
}, 10, 5);
Apply to the field with the name
author:
add_filter('acf/rest/format_value_for_rest/name=author', function ($value_formatted, $post_id, $field, $value, $format){
// return the overridden value
}, 10, 5);
Apply to the field with the key
field_123456789:
add_filter('acf/rest/format_value_for_rest/key=field_123456789', function ($value_formatted, $post_id, $field, $value, $format){
// return the overridden value
}, 10, 5);
);
Filtering the fields displayed on any endpoint
The
acf/rest/get_fields filter can be used to control which fields are shown or available for update. The
$http_method parameter passed to the filter can be used to alter the fields displayed for a specific request method (i.e. GET, POST, or OPTIONS):
add_filter( 'acf/rest/get_fields', function ( $fields, $resource, $http_method ) {
// Modify and return the $fields array here.
// Example 1: Disable all fields for all request methods on a particular custom post type.
if ( $resource['type'] == 'post' && $resource['sub_type'] == 'book' ) {
return [];
}
// Example 2: Show only a specific field on term GET requests.
if ( $http_method == 'GET' && $resource['type'] == 'term' ) {
return wp_list_filter( $fields, [ 'name' => 'author' ] );
}
// Example 3: Exclude particular field types on user POST requests.
if ( $http_method == 'POST' && $resource['type'] == 'user' ) {
return array_filter( $fields, function ( $field ) {
return ! in_array( $field['type'], [
'password',
'file',
] );
} );
}
return $fields;
}, 10, 3 );
Controlling the REST API embed links
GET requests to objects with certain field types will also include an embed link – a URL which points to another resource. An example of this would be the User field, which will add a link to the selected user in the
_links section of the REST response:
"acf:user": [
{
"embeddable": true,
"href": "https://hellfish.media/wp-json/wp/v2/users/1"
}
],
If you need to simplify the REST response, it is possible to disable the embed link handler using the global
acf/settings/rest_api_embed_links filter:
add_filter( 'acf/settings/rest_api_embed_links', '__return_false' );
If more granular control is required the
acf/rest/get_field_links filter and its
type,
name, and
key variations can be used to modify the links returned at the field level. e.g.;
add_filter( 'acf/rest/get_field_links', function ( $links, $post_id, $field, $value ) {
// Returning an empty array or any value that loosely equates to FALSE will disable links for this particular field. e.g;
if ( $field['name'] === 'author' ) {
return false;
}
// Define any number of embeddable links and choose how to group them using the rel key. Note that if embeddable is
// set to FALSE, the resource will not be expanded when the _embed query parameter is present.
$links = [
[
'rel' => 'acf:post',
'href' => rest_url( 'wp/v2/posts/123' ),
'embeddable' => true,
],
[
'rel' => 'acf:post',
'href' => rest_url( 'wp/v2/posts/456' ),
'embeddable' => true,
],
[
'rel' => 'acf:user',
'href' => rest_url( 'wp/v2/users/234' ),
'embeddable' => true,
],
[
'rel' => 'author_meta_group',
'href' => 'http://example.com', // External links can be used.
'embeddable' => false, // FALSE disables WordPress' embed handling.
],
];
return $links;
}, 10, 4 );
Controlling a field’s schema
Schema is used by WordPress to validate and sanitize data on input. It also allows external systems/services to understand the API data. Schema is generated for each resource endpoint by ACF. It is possible to control a field’s schema using the
acf/rest/get_field_schema filter and its
type,
name, and
key variations. e.g.:
add_filter( 'acf/rest/get_field_schema', function ( $schema, $field ) {
if($field['type'] === 'number'){
$schema['minimum'] = 1;
$schema['maximum'] = 100;
$schema['multipleOf'] = 1;
}
return $schema;
}, 10, 2 );
For more information on extending the WP REST API, please see the schema documentation.
Wysiwyg Editor
Description
The Wysiwyg field creates a WordPress content editor as seen in Posts and Pages. Wysiwyg is an acronym for "what you see is what you get".
This is one of the most useful fields for editing content as it allows for both text and multimedia to be edited and styled within a single area.
Screenshots
The Wysiwyg editor field interface
The Wysiwyg editor field settings
Changelog
Added Visual / Text options for
Tabs in version 5.0.0
Settings
Default Value
The default value shown when creating a new post.
Tabs
Selects which modes are shown to the user. Each Wysiwyg editor contains a visual and text mode. Choose from Visual and Text, Visual Only, or Text Only.
Toolbar
Specifies which toolbar to show. Choose from Full or Basic. The Full toolbar reflects the typical WordPress editor toolbar with 2 rows of buttons. The Basic toolbar is a minified single row of buttons useful for a more trimmed experience.
Show Media Upload Buttons
Provides the ability to upload inline media to the Wysiwyg field.
Delay initialization?
Defers initialization of editor until editor is clicked instead of on page load. This is useful to speed up load times.
Template usage
The Wysiwyg editor field will return your content formatted for HTML in the same manner that the_content() does.
Basic display
This example demonstrates how to display a Wysiwyg field’s content.
Notes
The acf_the_content filter
When loading a Wysiwyg field value, the value is passed through a filter
acf_the_content to apply HTML formatting. This filter, closely based on the WordPress the_content filter, is used instead to avoid unwanted recursion issues.
If you are using the
the_content filter to modify content, please be sure to also filter
acf_the_content as well.