How can I *update* a block's field values programmatically?

Hi there!

I have a blocks field that contains several blocks, all of the same type.
Now I want to run a function on page update to “calculate” and update a field of each block.

For a simple example let’s say my blocks have a firstname() field and a lastname() field and whenever I change the page (for simplicity), I want to calculate all the values of a third (hidden) field that is fullname().

How could I do this. I know I need to use a page.update:after hook, but how exactly can I take the values of the existing blocks, alter one of these values and then write it back to the blocks field?

Thanks!

trych

Question: Why do want to do this instead of doing this on output?

Because I don’t need this on output, but in the panel, on the block’s label instead. Apparently I cannot use queries there (but can just read out plain field values instead), so I somehow need to write this information into a field directly.

I have done this with builder fields in the past, but since the builder plugin is now replaced by blocks, I need to get it to work with blocks. However, I have no idea how to convert them and update them.

Here is a recipe how to create blocks programmatically: Quicktip: Add blocks to a blocks field programmatically | Kirby CMS

I’d argue that it’s easier to create a custom block preview…

Yes, I have seen that one, as well as a few posts on creating blocks programmatically, hence why I am now asking how to update existing blocks programmatically.

There must be some way to update an existing block? I mean, how would I go about this theoretically? Read the blocks field in its entirety, convert it to … an array? … or YAML? Then replace one of the fields and use the page update method to write the result back to the field.

I just do not know: What format do I need to convert the blocks field to? How do I then update one of the fields? I am having a hard time imagining that this is harder then creating a custom block preview. Don’t really wanna deal with Vue.js.

Yes, right, basically you convert the blocks to an array, then go through each block, add you field and then write it all back to the blocks field.

Lot more code and work, then just a block preview with

panel.plugin("cookbook/block-factory", {
  blocks: {
    myblock: `
      <div>
        <div>
          {{ content.firstname }} {{content.lastname}}
        </div>
      </div>
    `
  }
});

But that’s of course up to you.

Ok, my specific scenario was more complex, but I managed to customize my block preview now and have now a result which is quite a bit more advanced than would have been possible with parsing some label text.

20230301-011128_Screenshot_GoogleChrome

However, I now have the problem that I would love to automatically sort the entries of this block field by date. So I’m afraid I do need to update the block fields contents via a hook after all (correct me, if my assumption is wrong).

However, I would just need to read the blocks contents, sort them by a field, and then write it back, which to me sounds a bit easier than updating a field value in the process. However, I still do not know how I have to convert the blocks.

I have tried this:

'page.update:after' => function ($newPage) {

  if ($newPage->intendedTemplate() == 'project') {

    $sortedBlocks = $newPage->eventblocks()->sort('date');

    $newPage->update([
      'eventblocks' => $sortedBlocks
    ]);

  }

}

But it does not change anything on updating the page. Any idea what formatting I have to do to make this work?

That doesn’t make sense, you need to convert to blocks object before sorting:

    $sortedBlocks = $newPage->eventblocks()->toBlocks()->sortBy('date', 'desc');

I found this threat looking for the same thing. My use case is that I built a very simple form editor using blocks where I want to store the input data in the block.

In this case the great how to update blocks programmatically quicktip didn’t help me but I found this cookbook section about updating content within blocks. It shows how to convert individual blocks to arrays, manipulate the content and convert them back to blocks.

Edit: Didn’t work. Fields turned into default text fields. Found this hint by @texnixe, that you have to covernt the blocks object into an array when storing it:

$page->update([
    'text' => $blocks→toArray()
]);
1 Like