Working with Nested Repeaters

Last updated Mar 9, 2023


Creating and displaying nested repeater / flexible content fields is very easy using the Advanced Custom Fields plugin. This article will demonstrate how to build a simple to-do list that uses a nested repeater to output groups of items.

Field group

Below is a screenshot showing the field group used for this to-do list, and the location rules indicating when this field group should appear.

This screenshot shows the ACF field group used for this to-do list. It consists of a Repeater Field with two subfields: a Text field to indicate the name of the task and a True/False field to indicate whether or not the task has been completed.


Below is a screenshot showing a page which this field group appears on. As shown above, a page template of “To-do List” was used as a location rule to attach the field group to the page.

This screenshot shows a page in the WordPress admin on which the to-do list field group appears.


Now that we have created the field group and entered data for our to-do list, we can now loop over and display the data in our template. This tutorial assumes a template file for “To-do List” exists, so let’s edit that file. In the following code we will be using these functions:

  • have_rows() – allows us to loop through the available rows in a repeater / flexible content field
  • get_sub_field() – returns the value of a sub field (from the current repeater in “has_sub_field”)
  • the_sub_field() – displays the value of a sub field (from the current repeater in “has_sub_field”)

 * Template Name: To-do List

get_header(); ?>

    <div id="primary">
        <div id="content" role="main">

            <?php while ( have_posts() ) : the_post(); ?>

                <h1><?php the_title(); ?></h1>
                <?php the_content(); ?>


                // check for rows (parent repeater)
                if( have_rows('to-do_lists') ): ?>
                    <div id="to-do-lists">

                    // loop through rows (parent repeater)
                    while( have_rows('to-do_lists') ): the_row(); ?>
                            <h3><?php the_sub_field('title'); ?></h3>

                            // check for rows (sub repeater)
                            if( have_rows('items') ): ?>

                                // loop through rows (sub repeater)
                                while( have_rows('items') ): the_row();

                                    // display each item as a list - with a class of completed ( if completed )
                                    <li <?php if( get_sub_field('completed') ){ echo 'class="completed"'; } ?>><?php the_sub_field('name'); ?></li>
                                <?php endwhile; ?>
                            <?php endif; //if( get_sub_field('items') ): ?>

                    <?php endwhile; // while( has_sub_field('to-do_lists') ): ?>
                <?php endif; // if( get_field('to-do_lists') ): ?>

            <?php endwhile; // end of the loop. ?>

        </div><!-- #content -->
    </div><!-- #primary -->

<?php get_sidebar(); ?>
<?php get_footer(); ?>

Here is a screenshot showing the HTML produced from the above code.


Working with nested repeaters is easy, but can sometimes become confusing. To make life easier, try to use simple field names. Remember that sub fields can also use the same names as the ancestors so there’s no need to for long unique field names.