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

Please enter a Twitter handle.

@

This will check for our Twitter field value and display it if there is one available. Next, we’ll add the Author Info block’s display logic in the corresponding demo-acf-plugin/blocks/author-info/template.php file. blocks/author-info/template.php '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', ), ), ), ), array( array( 'core/column', array( 'verticalAlignment' => 'center', 'width' => '120px', ), array( array( 'core/image', array( 'align' => 'center', 'sizeSlug' => 'thumbnail', 'linkDestination' => 'none', 'className' => 'is-style-rounded', 'url' => 'https://i.pravatar.cc/120', ), array(), ), ), ), array( 'core/column', array( 'verticalAlignment' => 'center', 'width' => '', ), array( array( 'core/paragraph', array( 'fontSize' => 'large', 'content' => 'Taylor Swift', ), array(), ), array( 'core/paragraph', array( 'style' => array( 'spacing' => array( 'margin' => array( 'bottom' => '0', 'top' => '0', ), ), ), 'fontSize' => 'small', 'content' => 'Ea qui voluptate irure nulla aliquip nulla anim laborum exercitation eu incididunt.', ), array(), ), array( 'acf/author-twitter-v1', array( 'name' => 'acf/author-twitter-v1', 'data' => array( 'twitter' => 'wp_acf', ), 'mode' => 'auto', ), array(), ), ), ), ), ), ); ?>
$block_id, 'class' => esc_attr( $class_name ), ) ) ); ?> >
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
123, 'post_title' => false, 'post_content' => false, 'submit_value' => __('Update meta') )); ?>
Create a specific post This example demonstrates how to create a new post when submitting the form. page-new-form.php
'new_post', 'new_post' => array( 'post_type' => 'event', 'post_status' => 'publish' ), 'submit_value' => 'Create new event' )); ?>
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', 'title' => __('Testimonial'), 'description' => __('A custom testimonial block.'), 'render_template' => get_template_directory() . '/template-parts/blocks/testimonial/testimonial.php', 'enqueue_style' => get_template_directory_uri() . '/template-parts/blocks/testimonial/testimonial.css', )); testimonial.php
...
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.

', $start_date ); return; } if( $end_date && strtotime($end_date) < $now ) { echo sprintf( '

Content expired on %s.

', $end_date ); return; } } // Define notification message shown when editing. if( $start_date && $end_date ) { $notification = sprintf( 'Content visible from %s until %s.', $start_date, $end_date ); } elseif( $start_date ) { $notification = sprintf( 'Content visible from %s.', $start_date ); } elseif( $end_date ) { $notification = sprintf( 'Content visible until %s.', $end_date ); } else { $notification = 'Content unrestricted.'; } ?>
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. <?php echo $image['alt']; ?> 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())     
                 
  •          
Save Save Save Save Save Save Adding fields to Menu Items This guide will demonstrate how to add custom fields to a WordPress Menu Item and how to then modify the Menu Item’s HTML. Menus are used to organize a group of links (menu items) for your theme to display as navigation. If you are unfamiliar with registering or editing a Menu, please read the WordPress Menu User Guide and Navigation_Menus documentation. Menu Items are added to a Menu. Learn how to add fields to Menus. Changelog Added support for Menu in version 5.6.0 Adding fields The Advanced Custom Fields plugin makes it very easy to add custom fields to a Menu Item, 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 a Menu Item Under Locations, select the Menu Item rule and choose ‘All’ (to show this field group on all menu items) or a specific menu/location (to show this field group only for a specific menu’s items) Change the Instruction placement setting to ‘Below labels’ to best mimic the WP core UI. Editing fields Once you have created a field group and assigned it to appear for a Menu Item edit screen, editing the field values is done by navigating to the Appearance > Menus admin page. WP stores each Menu Item 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 Menu Item can be easily done via the wp_nav_menu_objects filter. This filter is run each time a Menu is rendered (via the wp_nav_menu() function) and allows you to modify the Menu Item objects. Each object contains a title value which is output in each menu link element. This example shows how to modify all Menu Item objects and append an icon if a value exists for the new ‘icon’ field. functions.php add_filter('wp_nav_menu_objects', 'my_wp_nav_menu_objects', 10, 2); function my_wp_nav_menu_objects( $items, $args ) { // loop foreach( $items as &$item ) { // vars $icon = get_field('icon', $item); // append icon if( $icon ) { $item->title .= ' '; } } // return return $items; } Conclusion Here is a look at how this may look in your browser. Notice the new icon elements! Notes Reserved keywords Please be aware that some reserved keywords exist for Menu Items which may conflict with field names. To avoid any errors that may potentially break the Customizer screen, please avoid using “description” as a field name when attached to a Menu Item. Save Adding fields to Menus This guide will demonstrate how to add custom fields to a WordPress Menu and how to then modify the Menu’s HTML. Menus are used to organize a group of links (menu items) for your theme to display as navigation. If you are unfamiliar with registering or editing a Menu, please read the WordPress Menu User Guide and Navigation_Menus documentation. Menus are used to group menu items. Learn how to add fields to Menu Items. Changelog Added support for Menu in version 5.6.0 Adding fields The Advanced Custom Fields plugin makes it very easy to add custom fields to a Menu, 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 a Menu Under Locations, select the Menu rule and choose either ‘All’ (to show this field group on all menus) or a specific menu/location (to show this field group only for a specific menu) Change the Style setting to ‘Seamless’ if you wish for the field group to appear joined to the core settings (No heading or border) as shown in this guide’s screenshots. Editing fields Once you have created a field group and assigned it to appear for a Menu edit screen, editing the field values is done by navigating to the Appearance > Menus admin page. WP stores each Menu as a term object in the wp_terms table. ACF will store all custom field values in the wp_termmeta table. Displaying fields Customizing the HTML for a WordPress Menu can be easily done via the wp_nav_menu_items filter. This filter is run each time a Menu is rendered (via the wp_nav_menu() function) and allows you to modify the
  • elements HTML for the Menu. This example shows how to modify the main navigation menu from the twentyseventeen theme (Menu location is called ‘top’ in this theme). Please note that a second argument is required by the ACF functions to specify where to load the value from. Because each Menu is a term object, we can simply pass this object as the second parameter. The Menu term object is found by using the $args->menu data. functions.php add_filter('wp_nav_menu_items', 'my_wp_nav_menu_items', 10, 2); function my_wp_nav_menu_items( $items, $args ) { // get menu $menu = wp_get_nav_menu_object($args->menu); // modify primary only if( $args->theme_location == 'top' ) { // vars $logo = get_field('logo', $menu); $color = get_field('color', $menu); // prepend logo $html_logo = '
  • '; // 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! <?php echo get_the_title(get_field('image_test')) ?> 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.
    • <?php echo esc_attr($image['alt']); ?>

    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.
    <?php echo esc_attr( $hero['image']['alt'] ); ?>
    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.
    <?php echo esc_attr( $image['alt'] ); ?>
    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”. <?php the_sub_field('alt'); ?>
    " >
    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. <?php echo esc_attr( $author_badge['alt'] ); ?> 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.

    $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 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() ): ?>
      have_posts() ) : $the_query->the_post(); $class = get_field('featured') ? 'class="featured"' : ''; ?>
    • >
    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
    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.
      ID ); $title = get_the_title( $featured_post->ID ); $custom_field = get_field( 'field_name', $featured_post->ID ); ?>
    • A custom field from this post:
    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 wp_get_attachment_image( $image, 'full' ); echo wp_kses_post( wpautop( $row['caption'] ) ); 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 'Block preview'; 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”. <?php the_sub_field('alt'); ?> 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 '
  • sub_field_1 = ' . get_sub_field('sub_field_1') . ', sub_field_2 = ' . get_sub_field('sub_field_2') .', etc
  • '; } 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’).
    author-avatar

    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
    'new_post', 'post_title' => true, 'post_content' => true, )); ?>
    Post Type This form will create a new published ‘event’ post. page-new-post.php
    'new_post', 'post_title' => true, 'post_content' => true, 'new_post' => array( 'post_type' => 'event', 'post_status' => 'publish' ) )); ?>
    Contact form This example will make a basic contact form, send an email, and redirect the user to a thank-you page. page-contact.php
    'new_post', 'post_title' => true, 'post_content' => true, 'new_post' => array( 'post_type' => 'contact_form', 'post_status' => 'publish' ), 'return' => home_url('contact-form-thank-you'), 'submit_value' => 'Send' )); ?>
    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": "

    The Flying Hellfish (also referred to as just “the Hellfish“) was the military unit Abraham Simpson, Charles Montgomery Burns, and several other Springfieldians served in during World War II.

    \n

    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.