The canonical pattern for iterating over ACF repeater field rows, including nested repeaters.
Basic repeater loop using have_rows():
<?php if ( have_rows( 'team_members' ) ) : ?>
<ul class="team-list">
<?php while ( have_rows( 'team_members' ) ) : the_row(); ?>
<li>
<h3><?php the_sub_field( 'name' ); ?></h3>
<p><?php the_sub_field( 'role' ); ?></p>
</li>
<?php endwhile; ?>
</ul>
<?php endif; ?>
Get all rows as an array for more control:
<?php
$rows = get_field( 'team_members' );
if ( $rows ) {
foreach ( $rows as $row ) {
echo '<h3>' . esc_html( $row['name'] ) . '</h3>';
echo '<p>' . esc_html( $row['role'] ) . '</p>';
}
}
Nested repeater (a repeater inside a repeater):
<?php if ( have_rows( 'departments' ) ) : ?>
<?php while ( have_rows( 'departments' ) ) : the_row(); ?>
<h2><?php the_sub_field( 'department_name' ); ?></h2>
<?php if ( have_rows( 'staff' ) ) : ?>
<ul>
<?php while ( have_rows( 'staff' ) ) : the_row(); ?>
<li><?php the_sub_field( 'name' ); ?></li>
<?php endwhile; ?>
</ul>
<?php endif; ?>
<?php endwhile; ?>
<?php endif; ?>
Get the row count without looping:
<?php
$count = count( get_field( 'team_members' ) ?: [] );
echo 'Total members: ' . $count;