Update blocks field programmatically if we use Layout?

@texnixe In the Discord, you point me to this cookbook : Quicktip: Add blocks to a blocks field programmatically | Kirby

It’s ok for a block type

fields:
  text:
    type: blocks
    pretty: true

but what if I use a layout type

fields:
  layout:
    type: layout

I tried this in the config file but it remove all my blocks

'hooks' => [
        'page.update:after' => function ($newPage, $oldPage) {
            foreach ( $newPage->layout()->toLayouts() as $layout ):
                foreach ( $layout->columns() as $column ):
                    foreach ( $column->blocks() as $block ):
                        if ( $block->type() === 'image' ) :
                            $image = new Kirby\Cms\Block([
                                'content' => [
                                    'url' => $block->image()->toFile()->url()
                                ],
                                'type' => 'image',
                            ]);
                            $newblocks = $column->blocks()->add(new Kirby\Cms\Blocks([$image]));
                            $kirby = kirby();
                            $kirby->impersonate('kirby');
                            $newPage->update([
                                'layout' => $newblocks,
                            ]);
                        endif;
                    endforeach;
                endforeach;
            endforeach;
        }
    ]
1 Like

You would have to create a new Layout object…

Could you please show me a code example ?

I’m afraid I can’t for the moment. You could have a look at the source code, how to construct a new layout object.

@bastianallgeier or @distantnative, could you please help out with this?

The easiest way to create blocks and layouts looks like this:

$blocks = Kirby\Cms\Blocks::factory([
    [
        'content' => [
            'text' => 'Nice heading'
        ],
        'type' => 'heading'
    ],
    [
        'content' => [
            'text' => 'This is some text'
        ],
        'type' => 'text'
    ]
]);

$layouts = Kirby\Cms\Layouts::factory([
    [
        'columns' => [
            [
                'width' => '1/2',
                'blocks' => [
                    [
                        'content' => [
                            'text' => 'Nice heading'
                        ],
                        'type' => 'heading'
                    ]
                ]
            ],
            [
                'width' => '1/2',
                'blocks' => [
                    [
                        'content' => [
                            'text' => 'This is some text'
                        ],
                        'type' => 'text'
                    ]
                ]
            ]
        ],
    ]
]);

Ok so if I want to update a field that belongs to all my image type block, I need to rebuild an entire layout object based on my current layout and just change the field concerned then do :

$newlayout = Kirby\Cms\Layouts::factory([
                                [
                                    'columns' => [
                                        [
                                            'width' => '1/2',
                                            'blocks' => [
                                                [
                                                    'content' => [
                                                        'text' => 'Nice heading'
                                                    ],
                                                    'type' => 'heading'
                                                ] .... ;
$kirby = kirby();
$kirby->impersonate('kirby');
$newPage->update([
 'layout' => $newlayout,
]);

I am right ?

Yes, you would basically merge what you have with what you want to change, then update the field with the result.

1 Like

Bringing this thread up instead of a new one. I am updating some values in some blocks which are also inside a Layouts field and am using the above technique to convert an array that holds the layout data structure to a Layouts object.

When doing var_dump all I get is:

object(Kirby\Cms\Layouts)#6106 (1) { [0]=> string(36) "d7fd1505-431c-4926-999f-8cbd6060714b" }

whereas when I am doing the same with the Layouts before processing it I get:

object(Kirby\Cms\Field)#6150 (1) { ["layout"]=> string(666) "[{"attrs":[],"columns":[{"blocks":[{"content":{"text":" ...

Sometimes though I get a full Layouts object through var_dump also for the first case (post-processing the blocks inside the Layouts field).

Is this a var_dump oddity?

I am making sure this part works fine as I am then passing the Layouts object to new Kirby\Cms\Blocks to combine all blocks part of the Builder into one object. If I don’t process the Layouts block then my plugin updates correctly the article, if I pass it the plugin fails to write the blocks collection altogether.

resolved, Programatically update blocks in a layout - #8 by afincato.