I have a Matrix field, and blocks have a Table field inside of them, with two columns: event and category.

I want to now set anything with category 'A' to category 'B' via a module (listening to Entry::EVENT_BEFORE_SAVE). I've got it updating the value correctly, but it adds it as a new row, rather than replacing the existing row.

I think I might need to use unset, to remove the row that matches, but I'm struggling to get that part working. Does anyone have any thoughts?

$blocks = $entry->matrixField->all();
foreach ($blocks as $block) {
    $table = $block->table;
    foreach ($table as $row) {
        $event = $row['event'];
        $category = $row['category'];
        if ($category === 'A') {
            $category = 'B';
        $updatedTable = [[
            'event' => $event,
            'category' => $category,
        $block->setFieldValue('table', array_merge($table ?? [], $updatedTable));

1 Answer 1


You're setting the field value and saving the matrix block once for every row in your table, you only need to do that once. The actual problem is that you're merging a new array into $table for every existing row, so essentially you're duplicating every row. However, that error is obscured by all the procedural code.

All you want is to get the same table, but with some values replaced. This is a simple map operation.

Something like this should work better:

$blocks = $entry->matrixField->all();
foreach ($blocks as $block) {
    $newTable = array_map(
        fn(array $row) => [
            'category' => $row['category'] !== 'A' ? $row['category'] : 'B',
            'event' => $row['event'],
    $block->setFieldValue('table', $newTable);
  • 1
    This is great, thank you!
    – supazu
    Commented Jan 28 at 1:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.