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).

Value type

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.

Getting and setting values
// 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;
Adding, removing, and saving items
// 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.

Creating a repeater field programmatically

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 stores template_id on 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 through getNewItem().
Selectors

Supports the same subfield selectors as FieldtypeRepeater:

$pages->find('fieldset_field.title*=keyword');
$pages->find('fieldset_field.some_field=value');
Output / markup
// 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";
}
Notes
  • The value is always a single FieldsetPage instance, never a PageArray.
  • Fields on the fieldset page exist in their own namespace, so title on one fieldset is independent of title on 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: FieldtypeFieldsetPage only.
API reference: methods, properties, hooks

For documentation about how Fieldtypes work, see: wire/core/Fieldtype.php wire/core/FieldtypeMulti.php

Page status notes for repeater items:

  • Unpublished & Hidden: Ready page, not yet used. Appears in unformatted repeater PageArray but user has not saved it.
  • Unpublished & On: Publish requested and can be published as long as no input errors.
  • Unpublished & NOT On: Item has been unpublished.

Unpublished or hidden pages do not appear in formatted PageArray value, only in unformatted.


Click any linked item for full usage details and examples. Hookable methods are indicated with the icon. In addition to those shown below, the FieldtypeRepeater class also inherits all the methods and properties of: Fieldtype, WireData and Wire.

Show class?     Show args?       Only hookable?    

Common

NameReturnSummary 
FieldtypeRepeater::cloneField(Field $field)
None

Create a cloned copy of Field

FieldtypeRepeater::countOldReadyPages(Field $field)
int

Count or delete old ready pages that are just taking up space

 
FieldtypeRepeater::deleteField(Field $field)
bool

Delete the given field, which implies: drop the table $field->table

FieldtypeRepeater::deletePageField(Page $page, Field $field)
bool

Delete the given Field from the given Page

FieldtypeRepeater::deleteRepeaterPage(Page $page)
int

Delete a repeater page, removing system statuses first

 
FieldtypeRepeater::exportValue(Page $page, Field $field, RepeaterPageArray $value)
array

Export repeater value

FieldtypeRepeater::findUnnecessaryParents(Field $field)
PageArray

Find unnecessary parent pages that may be deleted

 
FieldtypeRepeater::formatValue(Page $page, Field $field, PageArray $value)
PageArray

Perform output formatting on the value delivered to the API

FieldtypeRepeater::getBlankRepeaterPage(Page $page, Field $field)
Page

Returns a blank page ready for use as a repeater

 
FieldtypeRepeater::getBlankValue(Page $page, Field $field)
PageArray RepeaterPageArray

Get a blank value of this type, i.e. return a blank PageArray

 
FieldtypeRepeater::getCompatibleFieldtypes(Field $field)
WireArray

FieldtypeRepeater instances are only compatible with other FieldtypeRepeater derived classes.

FieldtypeRepeater::getConfigAdvancedInputfields(Field $field)
InputfieldWrapper

Remove advanced options that aren't supposed with repeaters

FieldtypeRepeater::getConfigInputfields(Field $field)
InputfieldWrapper

Return configuration fields definable for each FieldtypePage

FieldtypeRepeater::getCustomPageClass(Field $field)
string

Get custom RepeaterPage class for given repeater field

 
FieldtypeRepeater::getDatabaseSchema(Field $field)
array

Return the database schema in predefined format

 
FieldtypeRepeater::getFieldClass()
string

Get class name to use Field objects of this type (must be class that extends Field class)

 
FieldtypeRepeater::getInputfield(Page $page, Field $field)
Inputfield

Return an InputfieldRepeater, ready to be used

 
FieldtypeRepeater::getMatchQuery(PageFinderDatabaseQuerySelect $query, string $table, string $subfield, string $operator, string $value)
PageFinderDatabaseQuerySelect

Update a DatabaseQuerySelect object to match a Page

 
FieldtypeRepeater::getNextReadyPage(Page $page, Field $field)
Page

Get next page ready to be used as a new repeater item, creating it if it doesn't already exist

 
FieldtypeRepeater::getPageArrayClass()
string

Get the class used for repeater PageArray objects

 
FieldtypeRepeater::getPageClass()
string

Get the class used for repeater Page objects

 
FieldtypeRepeater::getRepeaterConfigHelper(Field $field)
FieldtypeRepeaterConfigHelper

@param Field $field

 
FieldtypeRepeater::getRepeaterPageParent(Page $page, Field $field)
Page NullPage

Return the parent used by the repeater pages for the given Page and Field

 
FieldtypeRepeater::getRepeaterParent(Field $field)
Page

Return the repeater parent used by $field, i.e. /processwire/repeaters/for-field-123/

 
FieldtypeRepeater::getRepeatersRootPage()
Page

Get repeaters root page

 
FieldtypeRepeater::getSelectorInfo(Field $field)
array

Get information used by selectors for querying this field

FieldtypeRepeater::getUniqueRepeaterPageName()
string

Returns a unique name for a repeater page

 
FieldtypeRepeater::importValue(Page $page, Field $field, array $value)
bool PageArray

Import repeater value previously exported by exportValue()

FieldtypeRepeater::initAllFields()
None

Force initialize of all repeater fields, confirming their configuration settings are correct

 
FieldtypeRepeater::porter()
FieldtypeRepeaterPorter

@return FieldtypeRepeaterPorter

 
FieldtypeRepeater::sanitizeValue(Page $page, Field $field, mixed $value)
PageArray RepeaterPageArray

Handles the sanitization and convertion to PageArray value

 
FieldtypeRepeater::sanitizeValueString(Page $page, Field $field, string $value)
Page PageArray

Given a string value return a Page or PageArray

 
FieldtypeRepeater::savePageField(Page $page, Field $field)
bool

Save the given field from page

FieldtypeRepeater::setCustomPageClass(Field $field, string $class)
None

Set custom RepeaterPage class for given field

 
FieldtypeRepeater::sleepValue(Page $page, Field $field, $value)
array

Given an 'awake' value, as set by wakeupValue, convert the value back to a basic type for storage in DB.

FieldtypeRepeater::useLazyParents($field)
bool

Use lazy parents mode?

 
FieldtypeRepeater::wakeupValue(Page $page, Field $field, array $value)
PageArray

Given a raw value (value as stored in DB), return the value as it would appear in a Page object

Properties

NameReturnSummary 
FieldtypeRepeater::repeatersRootPageID int 

Additional methods and properties

In addition to the methods and properties above, FieldtypeRepeater also inherits the methods and properties of these classes:

API reference based on ProcessWire core version 3.0.259