FieldtypeRepeater
Stores a collection of repeating field groups
Each item in the collection is a RepeaterPage
(extends Page), and the collection is a RepeaterPageArray (extends PageArray). Items are stored as real pages in the ProcessWire admin page tree under page/repeaters/ (relative to your
admin root, which is /processwire/ by default but is configurable).
FieldsetPage (extends RepeaterPage, which extends Page). Always a single object —
never a PageArray. The fieldset page is created automatically when the field is first used.
// Access fields on the fieldset page
echo $page->fieldset_field->title;
echo $page->fieldset_field->some_other_field;
// Set a field value
$page->fieldset_field->title = 'New value';
$page->save('fieldset_field');
// Check if a subfield is populated
if($page->fieldset_field->title) { ... }
// Access the owner page and field
$ownerPage = $page->fieldset_field->getForPage();
$ownerField = $page->fieldset_field->getForField();
$ownerTitle = $page->fieldset_field->getForPage()->title;// Always turn off output formatting when manipulating items
$page->of(false);
// Add a new item
$item = $page->repeater_field->getNewItem();
$item->title = 'New item';
$item->save();
$page->save('repeater_field'); // saves item order, count, and membership
// Remove an item
$page->repeater_field->remove($item);
$page->save('repeater_field');
// Reorder items: manipulate the RepeaterPageArray, then save the parent page
// The order of the array is what determines saved order.
$items = $page->repeater_field;
$itemA = $items->first();
$itemB = $items->last();
$items->append($itemA); // move first item to end
$items->prepend($itemB); // move last item to beginning
$items->insertBefore($itemA, $itemB); // move $itemA to just before $itemB
$items->insertAfter($itemA, $itemB); // move $itemA to just after $itemB
$items->reverse(); // reverse the order of all items
$items->sort('title'); // sort items by a sub-field value
$page->save('repeater_field'); // persists the new order
// Add multiple items, then save the parent page once at the end
$rows = [
[ 'title' => 'First item', 'body' => '<p>Hello</p>' ],
[ 'title' => 'Second item', 'body' => '<p>World</p>' ],
];
foreach($rows as $data) {
$item = $page->repeater_field->getNewItem();
foreach($data as $key => $value) $item->set($key, $value);
$item->save();
}
$page->save('repeater_field');Save workflow:
$item->save()writes the item's field values to the database.$page->save('repeater_field')updates the parent page's field record (item order, count, and which items belong to it). Both calls are required when adding items; only$item->save()is needed for in-place edits to an existing item.
The non-obvious part is that a repeater field requires a dedicated template and fieldgroup
to hold its sub-fields. Call _getRepeaterTemplate() after saving the field — it creates
the template/fieldgroup automatically if they don't exist yet.
$fields = $wire->fields;
$templates = $wire->templates;
// 1. Create and save the repeater field
/** @var RepeaterField $field */
$field = $fields->new('repeater', 'my_repeater', 'My Repeater');
// ------------------- ^Fieldtype --- ^Name -------- ^Label
// 2. Get/create the repeater's internal template and fieldgroup
$fieldgroup = $field->getRepeaterFieldgroup();
// 3. Add sub-fields to the repeater's fieldgroup
$fieldgroup->add('title');
$fieldgroup->add('body');
$fieldgroup->save();
// 4. Add the repeater field to your template
$template = $templates->get('your-template');
$template->fieldgroup->add($field);
$template->fieldgroup->save();Notes on programmatic creation:
$field->getRepeaterTemplate()creates and returns the repeater's internal template and fieldgroup if they don't exist yet, and storestemplate_idon the field. Always call this after creating the field.- The repeater template is named
repeater_{field_name}automatically. - Sub-fields are added directly to
$repeaterTemplate->fieldgroup— the fieldgroup membership IS the field list. $field->getRepeaterParent()returns the parent page under which repeater item pages are stored (e.g./processwire/page/repeaters/for-field-123/).$field->getBlankRepeaterPage($page)returns a new unsaved repeater item page for the given owner page — useful when creating items without going throughgetNewItem().
Supports the same subfield selectors as Fieldtype
$pages->find('fieldset_field.title*=keyword');
$pages->find('fieldset_field.some_field=value');// Iterate and output
foreach($page->repeater_field as $item) {
echo "<h3>{$item->headline}</h3>";
echo "<p>{$item->body}</p>";
}
// Template syntax with each()
echo $page->repeater_field->each("<div><h3>{headline}</h3><p>{body}</p></div>");
// Depth-aware output (when repeaterDepth field setting is enabled)
foreach($page->repeater_field as $item) {
$indent = str_repeat(' ', $item->depth);
echo $indent . $item->title . "\n";
}- The value is always a single
FieldsetPageinstance, never aPageArray. - Fields on the fieldset page exist in their own namespace, so
titleon one fieldset is independent oftitleon another — even if both fieldsets use the same field. - The fieldset page mirrors the output formatting (
of()) state of its owner page automatically. - Compatible fieldtypes:
FieldtypeFieldsetPageonly.
Please see the Repeater Fieldtype for usage instructions. Click any linked item for full usage details and examples. Hookable methods are indicated with the icon. In addition to those shown below, the Returns a blank page ready for use as a repeater Return the repeater Fieldgroup used by this Field Return the parent used by the repeater pages for the given $page Return the repeater parent used by this Field Return the repeater Template used by this Field In addition to the methods and properties above, RepeaterField also inherits the methods and properties of these classes:RepeaterField is used instead of Field for fields of type FieldtypeRepeaterField class also inherits all the methods and properties of: Field, WireData and Wire.Common
Name Return Summary Page RepeaterPage Fieldgroup Page NullPage Page Template Properties
Name Return Summary RepeaterField::accordionMode bool int Allow only one item open at a time? RepeaterField::familyFriendly bool int Treat item depth as parent/child relationships in the editor? RepeaterField::familyToggle bool int Opening/closing an item also opens/closes its visual children (requires familyFriendly)? RepeaterField::lazyParents int bool Avoid creating parent pages when there are no items to store? RepeaterField::loudControls bool int Always show item controls regardless of hover state? RepeaterField::noScroll bool int Do not scroll to newly added items? RepeaterField::parent_id int Parent page ID for repeater items. RepeaterField::rememberOpen bool int Remember which items are open between page-edit requests? RepeaterField::repeaterAddLabel string Label to use for the "add item" button. RepeaterField::repeaterCollapse int Item collapse state; see Fieldtype constants. RepeaterField::repeaterDepth int Maximum allowed depth for repeater items (0=disabled). RepeaterField::repeaterFields array Array of field IDs used in repeater. RepeaterField::repeaterLoading int Dynamic (ajax) loading mode; see Fieldtype constants. RepeaterField::repeaterMaxItems int Maximum number of items allowed (0=no limit). RepeaterField::repeaterMinItems int Minimum number of items required (0=no minimum). RepeaterField::repeaterReadyItems int (deprecated) RepeaterField::repeaterTitle string Field name or {field} format string to use for repeater item labels. RepeaterField::template_id int Template ID used by repeater items. RepeaterField::type Fieldtype Additional methods and properties
API reference based on ProcessWire core version 3.0.259