FieldtypeRepeaterMatrix class
Stores a collection of repeating groups of fields where each item can be one of several configurable types
Extends FieldtypeRepeater — all Repeater features apply. Each item is a
RepeaterMatrixPage (extends RepeaterPage, extends Page), and the collection is a
RepeaterMatrixPageArray (extends RepeaterPageArray, extends PageArray). Items are stored as
real pages in the ProcessWire admin page tree under page/repeaters/.
RepeaterMatrixPageArray (extends RepeaterPageArray, extends PageArray). Each item is a
RepeaterMatrixPage (extends RepeaterPage, extends Page). Each item has a matrix type — an
integer stored in a system field called repeater_matrix_type — that determines which sub-fields
are available on it.
When output formatting is on (default), only published/visible items are returned.
When off ($page->of(false)), all items including unpublished/hidden "ready" items are included.
// Iterate items
foreach($page->matrix_field as $item) {
echo $item->type; // matrix type name (string)
echo $item->matrix('n'); // matrix type number (int)
echo $item->some_field; // sub-field value for this item's type
}
// Check if populated
if($page->matrix_field->count()) { ... }
// Get first item
$first = $page->matrix_field->first();
// Get item by index (0-based)
$item = $page->matrix_field->eq(0);
// Add a new item (specify type name or number)
$item = $page->matrix_field->getNewItem('type-name');
$item->title = 'New item';
$item->save();
$page->save('matrix_field');
// Add an item and set type afterwards
$item = $page->matrix_field->getNewItem();
$item->setMatrixType('type-name'); // or pass type number: setMatrixType(2)
$item->save();
$page->save('matrix_field');
// Remove an item
$page->matrix_field->remove($item);
$page->save('matrix_field');
// Get the owner page and field from a matrix item
$ownerPage = $item->getForPage();
$ownerField = $item->getForField();// Always turn off output formatting when manipulating items
$page->of(false);
// Add a new item of a specific type
$item = $page->matrix_field->getNewItem('type-name'); // by type name
$item = $page->matrix_field->getNewItem(2); // by type number
$item->title = 'Hello';
$item->save();
$page->save('matrix_field'); // saves item order, count, and membership
// Remove an item
$page->matrix_field->remove($item);
$page->save('matrix_field');
// Change the type of an existing item
$item = $page->matrix_field->first();
$item->setMatrixType('new-type-name'); // or by number: setMatrixType(2)
$item->save();
// Unpublish an item (excludes it from formatted output, keeps it in unformatted output)
$item->addStatus(Page::statusUnpublished);
$item->save();
// Re-publish a previously unpublished item
$item->removeStatus(Page::statusUnpublished);
$item->save();
// Reorder items: manipulate the PageArray, then save the parent page
// The order of the RepeaterMatrixPageArray is what determines saved order.
$page->of(false);
$items = $page->matrix_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('matrix_field'); // persists the new order
// Add multiple items, then save the parent page once at the end
$items = [
[ 'type' => 'banner', 'title' => 'Top banner' ],
[ 'type' => 'text', 'body' => '<p>Hello</p>' ],
];
foreach($items as $data) {
$type = $data['type'];
unset($data['type']);
$item = $page->matrix_field->getNewItem($type);
foreach($data as $key => $value) $item->set($key, $value);
$item->save();
}
$page->save('matrix_field');Save workflow:
$item->save()writes the item's field values to the database.$page->save('matrix_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 type on each item controls which sub-fields are available. Access type info from an item:
// Get type name (string) — all three are equivalent
$typeName = $item->type;
$typeName = $item->getMatrixType();
$typeName = $item->matrix('name');
// Get type number (int)
$typeN = $item->getMatrixType(true); // pass true to get number instead of name
$typeN = $item->matrix('n');
$typeN = $item->repeater_matrix_type; // direct access to the type field value
// Get the type label (localized to user language in multi-language installs)
$label = $item->getMatrixLabel();
$label = $item->matrix('label');
// Get fields available for this item's type (FieldsArray)
$fields = $item->getFields();
$fields = $item->matrix('fields');
// Check if a field is valid for this item's type
if($item->hasField('some_field')) { ... }
// Get a full info array for this item
$info = $item->getMatrixInfo();
// Includes: n, id, type, sort, label, status, fields, context, forPage, forField
// Also per-language labels (label1234 etc.) in multi-language installsAccessing type information from the field (RepeaterMatrixField):
/** @var RepeaterMatrixField $field */
$field = $wire->fields->get('matrix_field');
// Get all types as [ typeName => typeNumber ]
$types = $field->getMatrixTypes(); // e.g. [ 'banner' => 1, 'text' => 2, 'gallery' => 3 ]
// Get type number from name, or false if not found
$n = $field->getMatrixTypeByName('banner'); // 1
// Get type name from number, or false if not found
$name = $field->getMatrixTypeName(1); // 'banner'
// Get the label for a type (by name or number), localized to user language
$label = $field->getMatrixTypeLabel('banner');
$label = $field->getMatrixTypeLabel(1); // same, by number
// Get verbose info for all types, indexed by name
$info = $field->getMatrixTypesInfo();
/*
[
'banner' => [
'type' => 1,
'name' => 'banner',
'label' => 'Banner',
'prefix' => 'matrix1_',
'sort' => 0,
'head' => '',
'file' => '/path/to/site/templates/fields/matrix_field/banner.php',
'field' => RepeaterMatrixField,
'fields' => [ 'title' => Field, 'image' => Field ],
'fieldIDs' => [ 123, 456 ],
],
...
]
*/
// Get verbose info for a single type (by name or number)
$info = $field->getMatrixTypesInfo([ 'type' => 'banner' ]);
// Get a single property for all types
$labels = $field->getMatrixTypesInfo([ 'get' => 'label' ]); // [ 'banner' => 'Banner', ... ]
// Index by type number instead of name
$info = $field->getMatrixTypesInfo([ 'index' => 'type' ]); // [ 1 => [...], 2 => [...] ]$fields = $wire->fields;
$templates = $wire->templates;
// 1. Create and save the repeater matrix field
/** @var RepeaterMatrixField $field */
$field = $fields->new('RepeaterMatrix', 'my_matrix', 'My Matrix');
// 2. Get/create the field's internal template and fieldgroup
$fieldgroup = $field->getRepeaterFieldgroup();
// 3. Add ALL sub-fields (for all types) to the repeater's fieldgroup
$fieldgroup->add('title');
$fieldgroup->add('image');
$fieldgroup->add('body');
$fieldgroup->save();
// 4. Define matrix types (field names, IDs, or Field objects accepted in 'fields')
$field->addMatrixType('banner', [
'label' => 'Banner',
'fields' => [ 'title', 'image' ],
]);
$field->addMatrixType('text', [
'label' => 'Text Block',
'fields' => [ 'title', 'body' ],
]);
$field->save();
// 5. Add the field to your template
$template = $templates->get('your-template');
$template->fieldgroup->add($field);
$template->fieldgroup->save();Notes on programmatic creation:
- All sub-fields across all types must be added to the fieldgroup (step 3) first. The per-type
fieldsarrays in step 4 are subsets of those. addMatrixType($name, $options)accepts the following options:label(string): human-readable label shown in the editor (defaults toucfirst($name)).fields(array): field names, IDs, or Field objects for this type.sort(int): sort order in the add-item UI (auto-increments if omitted).head(string): item header format string in the editor. Supports{field_name}placeholders,icon-{name}for a FontAwesome icon, and#rrggbbfor a color accent.
- Throws
WireExceptionif the name is empty or already in use. The field must be saved after callingaddMatrixType()to commit the type definition to the database.
Supports all selectors from FieldtypeRepeater, plus matrix type filtering:
// Has at least one item
$pages->find('matrix_field.count>0');
// Has no items
$pages->find('matrix_field.count=0');
// Match by matrix type name (auto-converted to integer internally)
$pages->find('matrix_field.type=banner');
$pages->find('matrix_field.type!=banner');
// Match by matrix type number
$pages->find('matrix_field.repeater_matrix_type=1');
// Match by a sub-field value
$pages->find('matrix_field.title*=keyword');
$pages->find('matrix_field.some_field=value');
$pages->find('matrix_field.some_date>2024-01-01');Subfield matching performs an internal
$pages->find()on the repeater template, then checks which pages reference those results. This is powerful but can be slower on large datasets. Type matching (type=name) is handled natively and does not carry this overhead.
// Iterate and output manually, branching on type
// This is the most common strategy for outputting matrix fields
foreach($page->matrix_field as $item) {
if($item->type === 'banner') {
echo "<div class='banner'>{$item->headline}</div>";
} else if($item->type === 'text') {
echo "<div class='text'>{$item->body}</div>";
}
}
// Render via PHP render files
// Primary path: site/templates/fields/{template_name}/{field_name}/{type_name}.php
// Fallback path: site/templates/fields/{field_name}/{type_name}.php
// In the render file, $page is the RepeaterMatrixPage item.
foreach($page->matrix_field as $item) {
echo $item->render();
}
// Render just one sub-field (delegates to Page::renderField())
echo $item->render('body');
// Render a sub-field using a specific file
echo $item->render('body', '/path/to/file.php');
// Template syntax using each()
echo $page->matrix_field->each(function($item) {
return $item->render();
});
// Using each with string and {placeholders}
echo $page->matrix_field->each('<h3>{title}</h3><p>{summary}</p>');- Extends
FieldtypeRepeater:depth, lazy parents, ready items,getForPage(),getForPageRoot(),getForField(),getForFieldRoot(), andrepeaterLoading/repeaterCollapsesettings all apply. Note:repeaterLoading = loadingOffis not supported and falls back toloadingNew. - Items are stored as real pages under
/admin-url/page/repeaters/. Each matrix field gets a dedicated parent page and template. The template always includes therepeater_matrix_typesystem field. - Each item's type is stored as an integer in the
repeater_matrix_typesystem field.$item->typereturns the type name string as a shortcut. getNewItem($type): accepts an optional type name or number. Recycles existing ready items rather than always creating new pages. Call$item->save()then$page->save('field_name').allowChangeTypesetting (int): 0 = type locked after creation, 1 = type changeable (no "none/undefined"), 2 = type changeable including "none/undefined" (default=2).addTypeconstants (how the add-item UI works in the page editor):InputfieldRepeaterMatrix::addTypeSelect(0) — dropdown select (default)InputfieldRepeaterMatrix::addTypeLinks(1) — link per typeInputfieldRepeaterMatrix::addTypeImages(2) — image thumbnail per typeInputfieldRepeaterMatrix::addTypeCustom(3) — custom markup (hookable viarenderAddMatrixCustom)
- Type label groups: a label like
"Layout > Banner"splits into group"Layout"and type label"Banner". Groups appear as<optgroup>entries in the add-type select and are accessible as$item->matrix('groupLabel'). repeaterLoadingconstants (fromFieldtypeRepeater):FieldtypeRepeater::loadingNew(0) — ajax-load newly added items onlyFieldtypeRepeater::loadingAll(1) — ajax-load all items
repeaterCollapseconstants (fromFieldtypeRepeater):FieldtypeRepeater::collapseExisting(0) — collapse existing items (default)FieldtypeRepeater::collapseAll(1) — collapse all items including newFieldtypeRepeater::collapseNone(3) — do not collapse any items
- Database columns:
pages_id INT,data TEXT(CSV of item page IDs),count INT,parent_id INT— same asFieldtypeRepeater. - Compatible fieldtypes:
Fieldtypeand extending types only.Repeater Matrix
Click any linked item for full usage details and examples. Hookable methods are indicated with the icon. In addition to those shown below, the Fieldtype class also inherits all the methods and properties of: FieldtypeRepeater, Fieldtype, WireData and Wire.
Common
Additional methods and properties
In addition to the methods and properties above, Fieldtype
API reference based on ProcessWire core version 3.0.259