Advanced Custom Fields is a plugin that extends the functionality of WordPress by using custom fields to build websites faster and more flexible. Advanced Custom Fields, also known as ACF, has a field type called Flexible Content that is used to add an unlimited number of layouts which can be reordered and reused to populate your posts/pages with content in a structured manner.

ACF provides documentation that explains how to use their Flexible Content field using something called the Flexible Content Loop. Their Flexible Content Loop is easy to use but we’ve figured out a way to simplify it even further and utilize its features in a more dynamic way; we like to refer to this as simplifying the Flexible Content Loop.

ACF’s Example of How to Use the Flexible Content Field

// check if the flexible content field has rows of data
if( have_rows('flexible_content_field_name') ):

    // loop through the rows of data
    while ( have_rows('flexible_content_field_name') ) : the_row();

        if( get_row_layout() == 'paragraph' ):

            the_sub_field('text');

        elseif( get_row_layout() == 'download' ):

            $file = get_sub_field('file');

        endif;

    endwhile;

else :

    // no layouts found

endif;

In the example above, you’ll notice that in each iteration of the loop we’re checking for the instance of specific layout types. Each layout type has code that is associated with it which will ultimately affect what is output on the front end.

ACF kept this example simple by either echoing the value of a field when the paragraph layout is used or assigning a file to a variable when the download layout is used. In more realistic use cases you would be outputting a lot more markup that is structured around the different layouts types that you’ve created.

Organizing Your Flexible Layouts Into Partials

// check if the flexible content field has rows of data
if( have_rows( 'flexible_content_field_name' ) ):

    // loop through the rows of data
    while ( have_rows( 'flexible_content_field_name' ) ) : the_row();

        if ( get_row_layout() == 'paragraph' ) :

            get_template_part( 'partials/flexible-layouts/flexible', 'paragraph' );

        elseif ( get_row_layout() == 'download' ) :

            get_template_part( 'partials/flexible-layouts/flexible', 'download' );

        endif;

    endwhile;

else :

    // no layouts found

endif;

As mentioned previously, you’re more than likely going to be doing a lot more than just echoing a simple field or assigning a value to a variable within your layouts; you’re going to be building out sections of pages that can be reused throughout the site so that you don’t have to redefine these layout multiple times. These layouts can become quite complex and can reach upwards of a few hundred lines of code. It’s for this reason that we prefer to break out our layouts into their own separate partials.

You’ll notice from the example above that we like to organize our flexible layouts into the partials/flexible-layouts/ directory. Each of our partials begin with flexible- and end in the name of the layout. Having our layouts separated into partials improves the readability of the loop and helps other developers understand what’s happening under the hood. It also makes for better management of our Flexible Content layouts.

Simplifying the Flexible Content Loop

// check if the flexible content field has rows of data
if( have_rows( 'flexible_content_field_name' ) ):

    // loop through the rows of data
    while ( have_rows( 'flexible_content_field_name' ) ) : the_row();

        if ( get_row_layout() == 'paragraph' ) :

            get_template_part( 'partials/flexible-layouts/flexible', 'paragraph' );

        elseif ( get_row_layout() == 'download' ) :

            get_template_part( 'partials/flexible-layouts/flexible', 'download' );

        endif;

    endwhile;

else :

    // no layouts found

endif;

Referring back to the previous code snippet, we can see that within each iteration of the loop we’re checking for every possible layout option. This is fine in the example provided since we’re only looking for 2 layout options; paragraph and download. But let’s say that you’re using the Flexible Content field to build your pages in a flexible nature and you have over 20 layout options available. Your loop has now grown out of control and has become somewhat unmanageable.

We were running into this scenario quite frequently so we came up with a dynamic way to pull in the correct Flexible Content partial by using a simple naming convention that involves matching up our partials to our layouts, one-for-one.

Basically, for each Flexible Content layout option that is created in ACF, an equivalent php partial is created within the theme.

If the Flexible Content field has a layout named flexible-two-column:

flexible content layout name

You would create a partial named flexible-two-column.php within your Flexible Content partials directory:

flexible content partial name

Now, instead of defining each of your layouts within your Flexible Content Loop, you would modify the loop so that it dynamically pulls in the correct partial based on the Flexible Content layout’s name:

// ID of the current item in the WordPress Loop
$id = get_the_ID();

// check if the flexible content field has rows of data
if ( have_rows( 'flexible_layouts', $id ) ) :

    // loop through the selected ACF layouts and display the matching partial
    while ( have_rows( 'flexible_layouts', $id ) ) : the_row();

        get_template_part( 'partials/flexible-layouts/' . get_row_layout() );

    endwhile;

elseif ( get_the_content() ) :

    // no layouts found

endif;

Using the Flexible Content Loop in this manner encourages code reusability and scalability by giving you the power to continually add to your library of Flexible Content layouts with minimal code adjustment.

Thanks!

If you have any questions, are having issues getting this to work with your setup, or are excited that you learned how to simplify the Flexible Content Loop, feel free to leave a comment below!

Originally published on

2 thoughts on “ACF Flexible Content: Simplifying the Flexible Content Loop

  1. This is really good stuff, thanks for sharing. Just FYI, I found this content whilst looking for help so that I could output content by selecting post objects from an ACF field in one of my flexible content rows. I wanted to use it to build default blocks of content, as CPT’s, that I could then pop into any other page, in the flow of the flex content. The problem was, the post object content uses the SAME Flexible Content Fields Groups & the same loop!

    Sounds confusing I know. At first this loop didn’t work as it called in all flex content for the main page as well. By switching to using $postID = $post->ID; instead of get_the_id, your loop is now working perfectly for my purposes. And I love the simplicity & stability of this approach! Thanks again

    1. Hey Mat!

      I’m glad that you found this example useful.

      I think that we’ve used the same approach of building out blocks of content in CPTs that could be used on various pages just like you’re explaining!

      Our setup involved having a CPT called CTA (Call to Actions) which used the same Flexible Content Fields Group to build out blocks of content.

      Our Flexible Content Fields Group included a layout named “Call To Action” which was a Relational Post Object Field Type. This field allowed the user to select a specific CTA post to display on the page. Since the blocks of content were defined on the CTA post itself, the same content could be reused in various places while only having to define it once.

      The Call To Action layout had a field name of “cta” which pulled in the partial called cta.php.

      I put the code that is in this partial into a snippet on BitBucket if you’re interested in checking it out:
      https://bitbucket.org/snippets/nvisionsolutionsdev/GeLr5n

      Thanks again for commenting 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *

Have Any Questions?

Speak with a
Digital Expert

  • Looking to increase leads?
  • Maximize profits?
  • Redesign your website?
  • Sell Online?
  • Build an App?

Let's Discuss Your Next Project

  • This field is for validation purposes and should be left unchanged.