2026年11月12日
2026年11月12日
ACF Flexible Content: Setting Up Layouts and Displaying Them
This article is a localized edition of the Japanese original. Read the Japanese original
The Flexible Content field in Advanced Custom Fields (ACF) lets you prepare layouts (building blocks) such as "heading", "text" and "image" in advance, so editors can arrange as many of them as they like, in any order, on each page. It suits landing pages and pages built by stacking sections.
This article explains how to create a Flexible Content field and the code that displays it in a theme template (as of October 2026; the display code was tested with Secure Custom Fields 6.9.7 and WordPress 6.9).
Requirements
- Flexible Content is an ACF PRO feature. It is not included in the free version of ACF.
- Secure Custom Fields, a plugin derived from ACF and distributed by WordPress.org, also has Flexible Content and is displayed with the same functions (
have_rows(),get_row_layout()and so on). - The display code goes into the theme's PHP templates. Block themes (such as Twenty Twenty-Five) render pages with HTML templates, so the PHP code below assumes a page template in a classic theme (or its child theme).
Step 1: Create the Flexible Content field
- In the admin area, go to "ACF" → "Field Groups" and add a new field group.
- Add a field and choose "Flexible Content" as the field type.
- Enter a label (for example, Page sections) and a field name (for example,
page_sections). The field name is used in the template code. - In the field group's Location Rules, choose where it appears (for example, Post Type is equal to Page) and save.
The Flexible Content field has these main settings (from the official ACF documentation):
| Setting | Description |
|---|---|
| Layouts | The layouts available on the edit screen |
| Button Label | The text shown on the button that adds a layout |
| Minimum Layouts | The minimum number of layouts required |
| Maximum Layouts | The maximum number of layouts allowed |
Step 2: Prepare layouts and sub fields
For each layout, set the Label, Name, Limit and Display, plus the fields used inside it (sub fields). This article uses the following three layouts as an example.
| Layout name | Sub field (name, type) | Purpose |
|---|---|---|
heading |
heading_text (Text) |
Section heading |
text_block |
body (WYSIWYG Editor) |
Body text |
image_block |
image (Image) |
Image |
- The layout "Name" is the value
get_row_layout()returns in the template. Using letters, numbers and underscores makes it easier to handle in code. - For the image field, Return Format can be an image array, a URL or an ID. The code in this article uses Image ID. With an ID,
wp_get_attachment_image()outputs animgtag withsrcset.
After saving, open a page's edit screen. Add layouts with the field's button and confirm that you can reorder them.
Step 3: Display it in a template
Put the following code inside the loop of a page template (for example, page.php or a custom page template).
<?php
if ( have_rows( 'page_sections' ) ) :
while ( have_rows( 'page_sections' ) ) :
the_row();
$layout = get_row_layout();
if ( 'heading' === $layout ) {
printf( '<h2>%s</h2>', esc_html( get_sub_field( 'heading_text' ) ) );
} elseif ( 'text_block' === $layout ) {
echo '<div class="section-text">' . wp_kses_post( get_sub_field( 'body' ) ) . '</div>';
} elseif ( 'image_block' === $layout ) {
$image_id = get_sub_field( 'image' ); // Field whose Return Format is set to "Image ID"
if ( $image_id ) {
echo wp_get_attachment_image( $image_id, 'large' );
}
}
endwhile;
endif;
have_rows()returnstruewhile layouts added to the page remain.the_row()moves to the next layout,get_row_layout()gets that layout's name, andget_sub_field()gets a sub field's value.- Escape values when you output them. Pass text through
esc_html()and WYSIWYG values that contain HTML throughwp_kses_post(). - When you use it outside the template loop or display another page's values, pass the post ID, as in
have_rows( 'page_sections', $post_id ).
Step 4: Split each layout into its own file
As layouts increase, the if branches get long. You can keep things organized by adding a file named after each layout to the theme and loading it with get_template_part().
<?php
while ( have_rows( 'page_sections' ) ) :
the_row();
get_template_part( 'template-parts/flexible/' . get_row_layout() );
endwhile;
In the theme's template-parts/flexible/heading.php, write only the display for that layout. Inside the loaded file, get_sub_field() still returns the current row's values.
<?php
// template-parts/flexible/heading.php
?>
<h2 class="section-heading"><?php echo esc_html( get_sub_field( 'heading_text' ) ); ?></h2>
Create text_block.php and image_block.php the same way. Layouts without a matching file display nothing.
Step 5: Check the output
On a page's edit screen, add a few layouts, fill in the content, save, and view the page.
- Do the sections appear in the order you added them?
- If nothing appears, check that the field name in the template (
page_sections) and the layout names match the ACF settings exactly - If nothing appears where the image should be, or
Arrayis shown, check that the image field's Return Format is "Image ID"
Notes for ongoing use
- Do not rename layouts later: Pages already saved keep their data under the old name. After a rename, those rows no longer match the template's branches and stop displaying.
- Manage field group settings as JSON: ACF's Local JSON (a feature that saves field group settings as files when you create an
acf-jsonfolder in your theme) makes it easier to keep settings in sync between production and development. - Limit the number of layouts per page: Use Minimum Layouts, Maximum Layouts and each layout's Limit to keep choices manageable for editors.
Summary
- Flexible Content is a feature of ACF PRO (or Secure Custom Fields) that lets editors arrange prepared layouts on each page
- Decide the layout names and sub field names, and set the image Return Format to "Image ID"
- In templates, get values with
have_rows(),the_row(),get_row_layout()andget_sub_field(), and escape output withesc_html()andwp_kses_post() - When layouts increase, split them into per-layout files with
get_template_part()
Related articles
- Basic usage of ACF (Advanced Custom Fields)
- How to manage ACF field groups as JSON
- How to display a list with the ACF Repeater field
Questions about WordPress? The publisher of this site is based in Japan and replies in Japanese. Contact (Japanese)