Advanced Custom Fields (ACF) Guide for Beginners: How to Use ACF with WordPress
In today’s digital landscape, mastering Advanced Custom Fields (ACF) in WordPress is essential for developers who want to provide structured, editor-friendly content without excessive manual effort. This comprehensive guide is tailored for WordPress theme builders and site developers aiming to enhance their projects with ACF. You will learn how to set up ACF, output fields in your theme, and incorporate best practices for performance and security.
What is Advanced Custom Fields (ACF)?
ACF is a powerful WordPress plugin that streamlines the management of custom fields (post meta) and seamlessly maps them to posts, pages, taxonomies, users, and options. Originally introduced as a free plugin, it later evolved into a paid “Pro” version with enhanced features.
Editions: Free vs ACF Pro (Short Summary)
| Feature | ACF (Free) | ACF Pro |
|---|---|---|
| Basic fields (text, image, textarea, WYSIWYG) | ✓ | ✓ |
| Repeater field | ✓ | |
| Flexible Content | ✓ | |
| Options pages | ✓ | |
| Gallery enhancements & clone fields | ✓ |
ACF Pro provides advanced tools such as Repeater and Flexible Content fields, as well as the ACF Blocks API for creating Gutenberg blocks. Choose ACF for structured content without the need for a full-fledged plugin or when server-rendered templates are preferred over complex client-side block development.
For a complete list of functions and field types, refer to the official ACF documentation: ACF Resources.
Installation and Basic Setup
Follow these steps to install ACF from your WordPress admin:
- Navigate to Plugins > Add New and search for “Advanced Custom Fields”.
- Click Install Now and then Activate (for the free version).
- For ACF Pro, upload the ZIP file through Plugins > Add New > Upload Plugin, then click Activate.
Creating Your First Field Group
- In the WordPress admin, go to Custom Fields > Add New.
- Enter a Field Group name (e.g., “Page Hero”).
- Click Add Field, then select a field type (text, image, link, etc.).
- Set a field name (machine name) such as
hero_title, and give it an intuitive label like “Hero Title”. - Define location rules (e.g., Show if Post Type is Page OR Page Template is About).
- Save the Field Group.
Location rules dictate where field groups appear: based on post type, specific page templates, taxonomy terms, user profiles, or options pages (Options pages require ACF Pro).
Tip: Enable Local JSON to version field group definitions by storing JSON files in your theme, which is beneficial for collaboration and repository workflows.
Common Field Types and When to Use Them
Here are some common ACF field types along with brief usage notes:
- Text: Short single-line strings (e.g., subtitle).
- Textarea: Multi-line text (intro or summary).
- WYSIWYG: HTML content for rich blocks (long descriptions).
- Number: Numeric values for sorting or calculations.
- Image: Single image (hero background).
- Gallery: Multiple images (product gallery) — Pro adds improved features.
- File: Attachments or downloadable PDFs.
- Select/Checkbox/Radio: Controlled options for editors.
- Link: URL + text target (CTA links).
- Relationship/Post Object/Taxonomy: Link to other posts or terms (related posts, products).
- Repeater (ACF Pro): Repeatable row sets (team members, FAQs).
- Flexible Content (ACF Pro): Block-like, multi-layout areas suited for page-builder needs.
Naming and Field Key Conventions:
- Use descriptive, snake_case field names (e.g.,
team_member_title). - Avoid collisions with native meta keys or plugin keys.
- Field keys (e.g.,
field_123abc) are generated by ACF and useful during migrations.
Performance Note: Be cautious with repeaters and large relationships to prevent issues with postmeta.
Displaying Field Values in Themes (PHP)
ACF provides helper functions for fetching and displaying field values:
get_field('field_name', $post_id)– retrieves the value.the_field('field_name', $post_id)– directly echoes the value.get_post_meta($post_id, 'meta_key', true)– utilizes a native WP function.
Basic Examples
Text Field Example (in single.php or page template):
<?php
$hero_title = get_field('hero_title');
if ( $hero_title ) {
echo '<h1>' . esc_html( $hero_title ) . '</h1>';
}
?>
Image Field Example:
<?php
$hero_image = get_field('hero_image');
if ( $hero_image ) {
$url = esc_url( $hero_image['url'] );
$alt = esc_attr( $hero_image['alt'] );
echo '<div class="hero" style="background-image:url(' . $url . ');" role="img" aria-label="' . $alt . '"></div>';
}
?>
Repeater Loop Pattern:
<?php
if ( have_rows('team_members') ) {
echo '<ul class="team">';
while ( have_rows('team_members') ) {
the_row();
$name = get_sub_field('name');
$role = get_sub_field('role');
echo '<li><strong>' . esc_html($name) . '</strong><span>' . esc_html($role) . '</span></li>';
}
echo '</ul>';
}
?>
Escaping and Sanitization: Always sanitize output — use esc_html() for plain text, esc_url() for URLs, wp_kses_post() for trusted HTML blocks, and esc_attr() for attributes.
Using ACF with Gutenberg and Blocks
ACF Pro simplifies the creation of custom Gutenberg blocks via acf_register_block_type.
When to Use ACF Blocks vs Dynamic Templates
- Use ACF Blocks for block UI in Gutenberg while favoring server-side rendering.
- For interactive blocks with rich client-side functionality, consider building native JS/React blocks.
Registering a Simple ACF Block
add_action('acf/init', 'my_acf_init_block_types');
function my_acf_init_block_types() {
if( function_exists('acf_register_block_type') ) {
acf_register_block_type(array(
'name' => 'hero-block',
'title' => __('Hero'),
'render_template' => 'template-parts/blocks/hero/hero.php',
'category' => 'layout',
'icon' => 'cover-image',
'keywords' => array('hero','banner'),
));
}
}
Once created, add a field group and set the location rule to “Block is equal to Hero” to display its fields in the editor. The render_template file will handle ACF fields using get_field() as usual.
ACF and the REST API / Headless WordPress
Post meta isn’t automatically included in REST API responses. For headless setups, consider:
- Using the ACF to REST API plugin to add fields cleanly to REST responses.
- Registering ACF fields with
show_in_restfor inclusion in REST responses.
Example for exposing fields via register_post_meta:
register_post_meta('post', 'hero_title', array(
'show_in_rest' => true,
'single' => true,
'type' => 'string',
));
Best Practices for Structured JSON:
- Return arrays/objects instead of serialized strings.
- Use dedicated endpoints for consistent structures.
- Cache responses for improved performance.
Performance and Security Best Practices
Avoid Expensive Meta Queries
- Use
meta_querycautiously; large meta queries can slow down performance. - Preload data and minimize repeated calls to
get_field()in loops.
Caching
Cache expensive ACF reads with transients:
$cache_key = 'home_hero_data';
$hero = get_transient($cache_key);
if ( false === $hero ) {
$hero = get_field('hero_settings', 'option');
set_transient($cache_key, $hero, HOUR_IN_SECONDS);
}
Sanitization and Validation
Utilize ACF field validation and sanitize on save when allowing HTML, ensuring output is escaped properly.
Caution with Relationships and Repeater Fields
Heavy use of these fields can increase postmeta entries and degrade performance; consider custom tables if dealing with significant data.
Common Pitfalls and Troubleshooting
Field Name Collisions
- Ensure field names match the field group’s machine name and correspond to the correct post type.
Scope/Post ID Issues
- When working outside the loop or during AJAX callbacks, pass the post ID explicitly to
get_field('name', $post_id).
Migration and Environment Changes
- Use ACF Local JSON and Export/Import tools to synchronize field group definitions across environments.
Serialized Meta Risks
- Avoid direct editing of serialized data; always use ACF functions or PHP to update fields.
ACF Pro License/Updates
- Keep ACF Pro updated to access ongoing support and features.
Practical Examples / Mini Tutorials
- Hero Block (Simple): Field Group: “Hero”
- hero_title (Text)
- hero_subtitle (Textarea)
- hero_background (Image)
- hero_cta (Link)
Template Snippet (template-parts/sections/hero.php):
<?php
$title = get_field('hero_title');
$subtitle = get_field('hero_subtitle');
$image = get_field('hero_background');
$cta = get_field('hero_cta');
?>
<section class="hero" style="background-image:url(<?php echo esc_url($image['url']); ?>);">
<div class="container">
<h1><?php echo esc_html($title); ?></h1>
<p><?php echo esc_html($subtitle); ?></p>
<?php if ( $cta ) : ?>
<a class="btn" href="<?php echo esc_url($cta['url']); ?>"><?php echo esc_html($cta['title']); ?></a>
<?php endif; ?>
</div>
</section>
-
Portfolio Item with Gallery and Related Posts: Fields: gallery (Gallery), related_projects (Relationship) Display example: use
get_field('related_projects')to loop through related posts and display them usingsetup_postdata()orWP_Query. -
FAQ Page with Repeater: Fields: faqs (Repeater)
- question (Text)
- answer (WYSIWYG)
Accessible markup example:
<?php if ( have_rows('faqs') ) : ?>
<div class="faqs">
<?php while ( have_rows('faqs') ) : the_row(); ?>
<details>
<summary><?php echo esc_html(get_sub_field('question')); ?></summary>
<div><?php echo wp_kses_post(get_sub_field('answer')); ?></div>
</details>
<?php endwhile; ?>
</div>
<?php endif; ?>
- Exporting ACF Data and Migrating Field Groups:
Use the Export feature in ACF admin or enable Local JSON (
acf-jsondirectory in your theme) to version field groups, ideal for repository strategies. For more on organizing code, read about Organizing code for larger projects.
Plugins and Add-ons Worth Knowing
- ACF Extended: Enhances the ACF admin UI with additional features (conditional logic, UI helpers).
- ACF to REST API: Clearly exposes ACF fields in REST responses, ideal for headless setups.
- Query builders/UI helpers: Various community plugins simplify building
WP_Queryqueries with ACF fields.
When to Consider Custom Tables
For large datasets with frequent complex queries, a custom table may be a better fit than relying on postmeta. Check out Designing maintainable theme/plugin architecture for more on data isolation strategies.
Resources and Next Steps
Official Documentation and Tutorials:
- ACF Official Resources
- WordPress Developer Resources (Meta & REST API)
- Beginner-friendly Guide on WPBeginner
Suggested Follow-up Projects:
- Create a reusable field group (Hero + CTA) and implement Local JSON in your theme.
- Build a simple ACF Block and render it server-side in Gutenberg.
- Expose selected ACF fields via the REST API to construct a headless demo using a JavaScript front end.
Community and Help:
- Utilize WordPress.org support and ACF support pages for assistance.
- For local development, refer to guides like Local development with WSL or Containerized WordPress development.
Consider sharing advanced examples or case studies; learn how to contribute ACF tutorials or examples.
Conclusion
ACF is an essential tool for WordPress developers seeking a simple way to manage structured content. Start small by creating a basic field group, incorporate it into your templates with proper output sanitization, and use Local JSON for version control. As your projects grow, explore ACF Pro features like Repeater, Flexible Content, and Blocks while focusing on performance and security. Happy building with ACF to enhance and streamline content delivery!