I'm having some trouble adding a row to a table field programmatically. I'm iterating over a table inside a Matrix field and would like to save those values to another table (if that makes sense.)

foreach ($blocks as $block) {
    $items = $block->items;
    foreach ($items as $item) {
        $itemType = $itemEvents['type'];
        $itemTime = $itemEvents['time'];
        $itemsTable = array(
                'col2' => $itemType,
                'col3' => $itemTime,
    ## I understand this is wrong, but this is what I want to do:
    $match->setFieldValue('itemEvents', json_encode($itemsTable));

Can anyone help with the last part of actually updating the itemEvents table field/adding a row to it?

1 Answer 1


You shouldn't JSON-encode the table field values; Craft handles that internally. Simply give it a multi-dimensional array.

The below would save one row with two columns to the table field itemEvents, belonging to an element $match:

$itemsTable = [[
    'col1' => $itemType,
    'col2' => $itemTime,

$match->setFieldValue('itemEvents', $itemsTable);


  • Thanks for this one too! I saw some other answers saying it needed to be JSON-encoded, thanks for clarifying. I have a question about the last line of saving the element; I'm using Event::on(Entry::class,Element::EVENT_BEFORE_SAVE, (and have tried EVENT_AFTER_SAVE too) for this and it seems to create an infinite loop. Any advice on how to do that properly?
    – supazu
    Commented Jan 15, 2023 at 1:38
  • 1
    @brynli64 Right, you shouldn't explicitly save the entry (using \Craft::$app->getElements->saveElement() in an EVENT_BEFORE_SAVE or EVENT_AFTER_SAVE event handler. In this case, you probably want to use the EVENT_BEFORE_SAVE event handler, and just $match->setFieldValue('itemEvents', $itemsTable); inside that (assuming $match is the entry being saved). The complicating factor is that the source for your table is in a Matrix block; I'm not sure if that data is even available before the entry has been saved (Matrix blocks are saved as separate elements). Commented Jan 15, 2023 at 13:59
  • 1
    So it's actually working with EVENT_BEFORE_SAVE now, however, it's only adding one row (presumably it's going throw each row and overwriting the previous one.) Any thoughts on how I can just add a row, rather than resave the whole table? Apologies for the trouble, I appreciate your help!
    – supazu
    Commented Jan 17, 2023 at 6:20
  • 1
    @brynli64 Great! The table field returns an array, so if you want to add new rows without overwriting existing data, you'll need to push or merge the new rows to the array the field returns. I.e. something like $match->setFieldValue('itemEvents', array_merge($match->itemEvents ?? [], $itemsTable)); Commented Jan 17, 2023 at 8:33
  • 1
    Brilliant - I think that's done it! Thank you!
    – supazu
    Commented Jan 17, 2023 at 12:19

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.