Is ACF Still the Best Choice in 2026?
Yes. Despite the growth of native WordPress block patterns and full site editing, ACF Pro remains the most practical tool for structured custom data in WordPress. Its field group interface is faster to configure than registering meta fields in PHP, its REST API integration is straightforward, and its Elementor dynamic tag support is unmatched by alternatives. For developer-built sites, headless WordPress, and complex data models, ACF Pro is still the standard.
ACF Free covers basic field types. ACF Pro ($149/year for unlimited sites as of 2026) adds Repeater, Flexible Content, Gallery, Clone, Options Page, and native Gutenberg block registration — all of which are essential for serious projects.
Building on CriticalWP's managed platform means your Elementor + ACF Pro stack runs on Cloudflare Enterprise infrastructure — fast, stable, and updated by our team. Get started for $50/month →
Field Groups — Creating, Configuring, and Fixing Them
A field group is a collection of ACF fields assigned to a specific location in WordPress — a post type, page template, taxonomy, user profile, widget, or options page. Everything in ACF starts with a field group.
Creating a Field Group
Go to Custom Fields → Add New. Give the group a name, add your fields, then set Location Rules at the bottom to determine where the group appears. Save — the group is now active and will appear on any post/page matching the location rules.
Fixing a Broken Field Group
If a field group disappears or stops showing fields, check these in order:
- Location rules — the most common cause. The rule must exactly match what you're editing. "Post Type → Page" won't show on a custom post type
- ACF JSON sync — if you're using ACF Local JSON and the JSON file is out of sync with the database, fields may be missing. Go to Custom Fields → Tools → Sync
- Plugin conflict — deactivate other plugins temporarily to rule out interference with ACF's field registration hooks
- ACF Pro license — an expired license won't deactivate the plugin but may disable Pro features silently
Repeater Fields and have_rows()
The ACF Repeater field stores multiple rows of sub-fields. It's ACF Pro only. The correct way to loop through repeater data on the front end is with have_rows():
if ( have_rows('your_repeater_field') ) :
while ( have_rows('your_repeater_field') ) : the_row();
$sub_value = get_sub_field('sub_field_name');
echo $sub_value;
endwhile;
endif;
For a Group field containing sub-fields, the same pattern applies — have_rows() works on Group fields as well as Repeaters. For nested repeaters, call have_rows() again inside the outer loop:
if ( have_rows('outer_repeater') ) :
while ( have_rows('outer_repeater') ) : the_row();
if ( have_rows('inner_repeater') ) :
while ( have_rows('inner_repeater') ) : the_row();
echo get_sub_field('inner_field');
endwhile;
endif;
endwhile;
endif;
To count repeater rows without looping: count( get_field('your_repeater_field') ).
ACF Date Picker — Stored Format YMD
This catches a lot of developers. The ACF Date Picker field stores values in the database in YMD format (YYYYMMDD) by default — regardless of what display format you configure in the field settings. The "Return Format" setting only affects what get_field() returns.
So if you're querying posts by a date field using WP_Query meta_query, you need to use the raw stored format (YYYYMMDD) for comparisons to work correctly:
$today = date('Ymd'); // Matches ACF's stored format
$args = array(
'meta_query' => array(
array(
'key' => 'event_date',
'value' => $today,
'compare' => '>=',
'type' => 'DATE',
),
),
);
If you need to display a formatted date, use PHP's DateTime to convert from the raw YMD string:
$raw_date = get_field('event_date'); // Returns 'Ymd' format
$date_obj = DateTime::createFromFormat('Ymd', $raw_date);
echo $date_obj->format('F j, Y'); // Outputs: May 8, 2026
ACF Fields in Elementor Dynamic Tags
ACF Pro fields appear in Elementor's dynamic tag picker automatically — but only under specific conditions. If your ACF fields are not showing in Elementor, work through these fixes in order:
- Location rules must match the post type you're editing — a field group assigned to a specific page won't show when editing other pages of the same type. Set the location to "Post Type → is equal to → [your post type]"
- ACF Pro is required — the free version does not expose fields to Elementor's dynamic tag system
- Clear Elementor's cache — go to Elementor → Tools → Regenerate Files & Data after creating new field groups
- Field type compatibility — Repeater, Flexible Content, Gallery, and Clone fields do not appear natively in Elementor dynamic tags. Use Text, Image, Date, Select, URL, Email, and Number fields for direct dynamic tag support
- Editing context — global templates (headers, footers) may not show post-specific fields. Edit a specific post directly to confirm fields appear there first
When an ACF field shows "--" in Elementor instead of a value, the field is being found but has no value saved for that specific post. Check that the post actually has data saved in the field — go to the post editor and verify the ACF field contains a value.
CriticalWP's managed platform includes Elementor and Astra Pro pre-configured — your ACF dynamic tags work out of the box without fighting hosting or plugin conflicts. See what's included →
ACF and the WordPress REST API
ACF fields are not exposed to the REST API by default. To include a field in REST API responses, open the field group, expand the field, and enable "Show in REST API" in the field settings. This makes the field available under the meta key in REST responses.
For custom post types, the post type must also have show_in_rest => true set when registering it:
register_post_type('your_cpt', array(
'show_in_rest' => true,
// ...other args
));
For taxonomy fields, enable show_in_rest on the taxonomy registration as well. To expose ACF taxonomy fields specifically, also set show_in_rest on individual ACF fields attached to taxonomy terms.
The ACF to REST API plugin is an older solution that exposed all ACF fields to the API automatically. In 2026, ACF Pro's native show_in_rest setting is the preferred approach — it gives you field-level control over what's exposed without a third-party plugin dependency.
ACF JSON Sync Across Environments
ACF Local JSON stores field group definitions as JSON files in your theme's acf-json/ folder. This means field groups can be version-controlled and synced between development, staging, and production environments by committing the JSON files.
The correct workflow:
- Create or modify field groups in your development environment — ACF auto-saves changes to
acf-json/ - Commit the JSON files to your repository
- Deploy to staging/production — ACF detects the JSON files are newer than the database version
- Go to Custom Fields → Tools → Sync and sync the changed field groups
If the sync page shows no available syncs but you know JSON files exist, confirm the acf-json/ folder is inside your active theme directory and is readable by PHP.
ACF with WPML and Polylang (Multilingual)
Both WPML and Polylang have official ACF compatibility, but configuration differs between them.
WPML + ACF: WPML's String Translation module handles ACF field translation. In WPML → Settings → Custom Fields Translation, set each ACF field to "Copy", "Translate", or "Don't translate". Fields set to "Translate" appear in the WPML translation editor. The ACF WPML plugin (free, by OnTheGoSystems) extends this integration for Repeater and Flexible Content fields.
Polylang + ACF: Polylang's ACF integration is less automatic. You need to either use the ACF for Polylang plugin or manually manage field translation by hooking into ACF's acf/load_field filter to modify field values based on the current language.
ACF with Gutenberg Blocks
ACF Pro's block registration allows you to create custom Gutenberg blocks with an ACF field interface instead of writing React/JavaScript. Register a block using acf_register_block_type():
add_action('acf/init', function() {
acf_register_block_type(array(
'name' => 'your-block',
'title' => 'Your Block',
'render_template' => 'template-parts/blocks/your-block.php',
'category' => 'common',
'icon' => 'editor-ul',
'keywords' => array('custom', 'block'),
'supports' => array('align' => false),
));
});
The render_template is a PHP file where you use standard ACF get_field() calls to output field values. The block preview in the editor re-renders on each field change by default — to prevent this (useful for complex blocks with slow renders), add 'example' => array('attributes' => array('mode' => 'preview')) to your block registration args.
The block wrapper ID issue — ACF blocks generate a wrapper id attribute with a base64-encoded string. This is expected behavior and does not need to be removed, but if you're targeting the block with CSS or JavaScript, use a class instead of the ID.
ACF vs Taxonomies — When to Use Each
The rule is straightforward: use taxonomies when you need to group and filter content by category (queryable, archive pages, used across many posts). Use ACF fields when you need to store structured data specific to individual posts that doesn't need its own archive page.
- Use a taxonomy: Product category, blog post topic, location, team, event type — anything you filter by or display as a list across the site
- Use ACF: Event date, price, specifications, coordinates, related documents, a series of team member bios on a single page — structured per-post data
- Use both: A taxonomy for filtering + an ACF field for detailed data on the same content. A "Project" post type with a "Service Type" taxonomy for filtering and ACF fields for project details, client name, and before/after images
Export and Import ACF Field Groups
To export field groups: Custom Fields → Tools → Export Field Groups. Select the groups to export and download as JSON. This JSON file contains the full field group definition and can be imported on any WordPress install.
To import: Custom Fields → Tools → Import Field Groups, upload the JSON file. The field group is created in the database and ACF JSON is written if the folder exists.
The exported JSON structure includes the field group key, location rules, field keys, field types, and all configuration — it's version-controllable and portable between environments.
ACF Performance — Does It Slow Down WordPress?
ACF itself adds minimal overhead. The performance impact comes from how fields are used, not from ACF loading. Common performance issues:
- Too many get_field() calls per page — each call is a database query. On archive pages with 20 posts each calling 10 fields, that's 200 extra queries. Use
get_fields()once per post to retrieve all fields in a single query, then access them from the returned array - Repeater fields with many rows — large repeaters on high-traffic pages add query load. Consider caching the output with a transient if the data changes infrequently
- Orphaned ACF data — deleted field groups leave their data in the
wp_postmetatable. On large sites this adds bloat. Clean orphaned data periodically using the ACF cleanup approach: identify meta keys prefixed with_that match deleted field names, then remove them in batches - Relationship fields on large datasets — querying relationship fields across thousands of posts is slow. Add custom database indexes on the meta_key values you query frequently
ACF Troubleshooting Reference
Fields Not Showing on the Post Edit Screen
Check location rules first. Then verify the field group is active (not in draft/trash). If using ACF JSON, sync the field group. If a third-party plugin is modifying field registration, deactivate plugins to isolate. See our complete guide to fixing WordPress plugin issues for a full conflict isolation walkthrough.
Fields Not Saving or Resetting on Save
Usually caused by a nonce conflict from another plugin, a PHP memory limit being hit during save, or a field key collision (two fields with the same key). Enable WP_DEBUG and check the debug log immediately after saving to see the specific error.
ACF Not Working After a WordPress Update
WordPress updates can deprecate PHP functions ACF depends on. Update ACF Pro immediately after a WordPress core update. If updating ACF breaks something, check the ACF changelog for breaking changes — some major versions require theme or function updates.
Options Page Missing
The ACF Options Page requires ACF Pro. Verify Pro is active and licensed. The options page is registered with acf_add_options_page() — this must run on the acf/init hook or within the after_setup_theme hook. If the function call is in a plugin that loads before ACF, it may run before ACF is available.
Relationship Field Returning No Results
The relationship field queries posts using WP_Query internally. If no results appear in the relationship picker, check: the post type is set correctly in the field settings, the posts are published (not draft), and there are no conflicts with plugins that modify WP_Query globally.
ACF Shortcode Disabled
Since ACF 5.9, the [acf] shortcode is disabled by default for security reasons. To re-enable it, add add_filter('acf/shortcode/allow_access', '__return_true'); to your functions.php. Only enable this if you control who can edit posts on your site.
Frequently Asked Questions
have_rows() and the_row() to loop, then get_sub_field() to retrieve values inside the loop. The same pattern works for Group fields and nested repeaters.show_in_rest => true set when registered. No third-party plugin needed in ACF Pro.get_field() calls per page. Use get_fields() once per post to retrieve all fields in a single query instead.