Skip to content
Ultivo Toolkit 1.0 is here! Get 10% off your first year with LAUNCH10 until September 30. See pricing
Documentation menu

Repeater

Creating a repeater#

Add a Repeater field and define its Sub Fields: any field types, including another repeater. The other settings:

  • Minimum / Maximum Rows: bounds on how many rows editors can add.
  • Layout: how rows render in the admin: Block, Table or Row.
  • Button Label: the text on the add button (defaults to "Add Row").

Editors drag rows to reorder, and duplicate or remove them per row.

Looping in templates#

The classic loop, familiar from WordPress meta APIs:

if ( ultivo_have_rows( 'team' ) ) :
    while ( ultivo_have_rows( 'team' ) ) : ultivo_the_row();
        $name = ultivo_get_sub_field( 'name' );
    endwhile;
endif;

Or the Template API: ultivo_rows() returns an iterable, countable object with no global loop state, and an empty repeater simply iterates zero times:

foreach ( ultivo_rows( 'team' ) as $member ) {
    echo esc_html( $member['name'] );
}

Inside the classic loop, ultivo_get_row_index() returns the zero-based index of the current row. ultivo_the_sub_field( 'name' ) echoes a sub-field directly.

Adding rows in code#

ultivo_add_row() appends a row programmatically, keyed by sub-field name, and returns the new row count:

ultivo_add_row( 'team', [ 'name' => 'Jane' ] );

Storage#

The repeater's own meta key stores the row count; each sub-field value is stored as {name}_{index}_{subname}. A team repeater with a name sub-field and two rows saves:

team          =>  2
team_0_name   =>  "Jane"
team_1_name   =>  "John"

This is the same pattern ACF uses, so migrated repeater data keeps working as-is.

Nested repeaters#

Repeaters nest: a sub-field can itself be a repeater. In the classic loop, call ultivo_have_rows() with the sub-repeater's name inside the outer loop. With the Template API, call ->rows( 'sub_name' ) on a row. Storage nests the same way: slides_0_buttons_1_label is the second button of the first slide.