Flexible Content Fields for WordPress
Flexible content is the custom fields feature that turns WordPress into a page builder without the bloat. Define multiple “row layouts” (hero, features, testimonials, CTA), let editors mix and match layouts to build a page. Field Forge’s flexible content field is fully ACF-compatible and powers modular landing page patterns on production WordPress sites.
What flexible content does
A flexible content field is a row-based field where each row can be one of several predefined layouts. Unlike a repeater (where every row has the same sub-fields), flexible content lets editors pick which layout to use per row.
Example: landing page builder
A field group called “Landing Page Sections” contains a flexible content field with four possible layouts:
- Hero — title, subtitle, background image, CTA button
- Features — repeating icon + title + description (nested repeater)
- Testimonial — quote, author, photo
- CTA — headline, button
An editor building a landing page clicks “Add Row” and chooses which layout to use. They can add a Hero, then Features, then two Testimonials, then another Features, then a CTA. Mix and match in any order, any number of each.
The result: a custom landing page builder with consistent design and structured data.
How layouts are defined
In Field Forge’s visual builder, you configure a flexible content field by defining layouts. Each layout is a named container for sub-fields:
Flexible Content: Page Sections
Layout: Hero
- Title (Text, required)
- Subtitle (Textarea)
- Background Image (Image, required)
- CTA Button (Group: text + URL)
Layout: Features
- Section Title (Text)
- Features (Repeater)
- Icon (Select from icon library)
- Title (Text)
- Description (Textarea)
Layout: Testimonial
- Quote (Textarea)
- Author Name (Text)
- Author Photo (Image)
- Author Company (Text)
Layout: CTA
- Headline (Text)
- Primary Button (Group)
Editors see a dropdown or grid of these layouts when adding rows.
Template code (ACF-compatible)
Flexible content uses the same template functions as ACF and SCF. Code written for ACF works unchanged:
<?php if (have_rows('page_sections')) : ?>
<?php while (have_rows('page_sections')) : the_row(); ?>
<?php if (get_row_layout() === 'hero') : ?>
<section class="hero">
<h1><?php the_sub_field('title'); ?></h1>
<p><?php the_sub_field('subtitle'); ?></p>
<?php $image = get_sub_field('background_image'); ?>
<img src="<?php echo esc_url($image['url']); ?>">
</section>
<?php elseif (get_row_layout() === 'features') : ?>
<section class="features">
<h2><?php the_sub_field('section_title'); ?></h2>
<?php if (have_rows('features')) : ?>
<div class="feature-grid">
<?php while (have_rows('features')) : the_row(); ?>
<div class="feature">
<h3><?php the_sub_field('title'); ?></h3>
<p><?php the_sub_field('description'); ?></p>
</div>
<?php endwhile; ?>
</div>
<?php endif; ?>
</section>
<?php elseif (get_row_layout() === 'testimonial') : ?>
<blockquote>
<p><?php the_sub_field('quote'); ?></p>
<cite><?php the_sub_field('author_name'); ?></cite>
</blockquote>
<?php elseif (get_row_layout() === 'cta') : ?>
<section class="cta">
<h2><?php the_sub_field('headline'); ?></h2>
</section>
<?php endif; ?>
<?php endwhile; ?>
<?php endif; ?>
The get_row_layout() function returns the layout name of the current row, letting you branch rendering logic. This is identical to how ACF handles flexible content.
When to use flexible content vs a page builder
Flexible content wins when:
- You need structured data (for APIs, TypeScript, headless, schema.org markup)
- Editors should be constrained to approved layouts (not free design)
- Pages need to render consistently across devices and over time
- You’re running a headless WordPress site (Elementor / Divi content doesn’t serialize cleanly to JSON)
- Content needs to be queryable (e.g., “show all testimonials from pages in this category”)
Page builders (Elementor, Divi) win when:
- Editors want full visual control over every element
- The site is marketing-heavy and design changes frequently
- You’re not using the WordPress REST API or GraphQL for frontend
Many sites use both: flexible content for structured sections (product pages, landing pages, case studies) and a page builder for one-off marketing pages.
Migrating from ACF flexible content
If you’re coming from ACF (or SCF), your existing flexible content data migrates cleanly. Field Forge’s importer:
- Reads your ACF flexible content field definitions
- Recreates layouts in Field Forge
- Migrates all existing row data with layout labels preserved
- The ACF compatibility layer handles
get_row_layout()/have_rows()calls in your theme
Template code using get_row_layout() keeps working unchanged.
Performance on flexible content
Flexible content fields are historically slow in ACF and SCF because each row’s data is stored as separate wp_postmeta entries. A page with 10 flexible content rows and 5 sub-fields per row = 50 meta entries, and the query to reconstruct the row order and layout names is complex.
Field Forge stores flexible content rows in the custom wp_fieldforge_values table with proper parent_id and row_index columns. A single query fetches all rows with their layouts and sub-field values. Learn more about custom table storage →
REST API output
Flexible content rows are exposed as an array of objects with the layout name included:
{
"page_sections": [
{
"acf_fc_layout": "hero",
"title": "Welcome to Our Site",
"subtitle": "Building better WordPress experiences",
"background_image": { "id": 123, "url": "..." }
},
{
"acf_fc_layout": "features",
"section_title": "Why Choose Us",
"features": [
{ "title": "Fast", "description": "..." },
{ "title": "Reliable", "description": "..." }
]
},
{
"acf_fc_layout": "cta",
"headline": "Ready to start?"
}
]
}
The acf_fc_layout key matches ACF’s output format for REST API consumers that already parse ACF data.
Ready to use flexible content?
Flexible content is included in every paid plan.