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