Twill: When blocks viewed in backend, possible to change block titles dynamically?

Created on 17 Dec 2018  路  10Comments  路  Source: area17/twill

Hi,

Is it possible to change the block titles that appear in the backend- eg in the example below, "Project preview" would be replaced with the title of each project?

screen shot 2018-12-17 at 12 33 27

question

All 10 comments

Hi Seb,

it is not possible with the current implementation but we could provide a hook in the form of a helper function you have to redefine. Here's the code that's currently pulling the title of each block from configuration:

https://github.com/area17/twill/blob/209e63f0d21e909cba6370d9d853c66a1b9fabf0/src/Repositories/Behaviors/HandleBlocks.php#L112-L125

I'm thinking we could replace line 123 by something like:

'title' => getBlockCustomTitle($block, $blockTypeConfig['title']),

where the first parameter is the block object itself, so you can access browsers data inside and use that information as the title, and the second is the default value, which is the current value being used from configuration. The default implementation of this function coming with Twill would only return the default value.

Thanks for going into so much detail. Where/how would I redefine this function? (Sorry if that's a bit of a beginner question!)

You could override the existing function in your Module Repository.

Example:

<?php

namespace App\Repositories;

use A17\Twill\Repositories\Behaviors\HandleBlocks;
use A17\Twill\Repositories\ModuleRepository;
use App\Models\Article;

class ArticleRepository extends ModuleRepository
{
    use HandleBlocks;

    //...

    public function getFormFieldsHandleBlocks($object, $fields)
    {
        $fields['blocks'] = null;
        if ($object->has('blocks')) {
            $blocksConfig = config('twill.block_editor');
            foreach ($object->blocks as $block) {
                $isInRepeater = isset($block->parent_id);
                $configKey = $isInRepeater ? 'repeaters' : 'blocks';
                $blockTypeConfig = $blocksConfig[$configKey][$block->type] ?? null;
                if (is_null($blockTypeConfig)) {
                    continue;
                }
                $blockItem = [
                    'id' => $block->id,
                    'type' => $blockTypeConfig['component'],
                    'title' => getBlockCustomTitle($block, $blockTypeConfig['title']),
                    'attributes' => $blockTypeConfig['attributes'] ?? [],
                ];
                if ($isInRepeater) {
                    $fields['blocksRepeaters']["blocks-{$block->parent_id}_{$block->child_key}"][] = $blockItem + [
                        'max' => $blockTypeConfig['max'],
                        'trigger' => $blockTypeConfig['trigger'],
                    ];
                } else {
                    $fields['blocks'][] = $blockItem + [
                        'icon' => $blockTypeConfig['icon'],
                    ];
                }
                $fields['blocksFields'][] = collect($block['content'])->filter(function ($value, $key) {
                    return $key !== "browsers";
                })->map(function ($value, $key) use ($block) {
                    return [
                        'name' => "blocks[$block->id][$key]",
                        'value' => $value,
                    ];
                })->filter()->values()->toArray();
                $blockFormFields = app(BlockRepository::class)->getFormFields($block);
                $medias = $blockFormFields['medias'];
                if ($medias) {
                    $fields['blocksMedias'][] = collect($medias)->mapWithKeys(function ($value, $key) use ($block) {
                        return [
                            "blocks[$block->id][$key]" => $value,
                        ];
                    })->filter()->toArray();
                }
                $files = $blockFormFields['files'];
                if ($files) {
                    collect($files)->each(function ($rolesWithFiles, $locale) use (&$fields, $block) {
                        $fields['blocksFiles'][] = collect($rolesWithFiles)->mapWithKeys(function ($files, $role) use ($locale, $block) {
                            return [
                                "blocks[$block->id][$role][$locale]" => $files,
                            ];
                        })->toArray();
                    });
                }
                if (isset($block['content']['browsers'])) {
                    $fields['blocksBrowsers'][] = $this->getBlockBrowsers($block);
                }
            }
            if ($fields['blocksFields'] ?? false) {
                $fields['blocksFields'] = call_user_func_array('array_merge', $fields['blocksFields'] ?? []);
            }
            if ($fields['blocksMedias'] ?? false) {
                $fields['blocksMedias'] = call_user_func_array('array_merge', $fields['blocksMedias'] ?? []);
            }
            if ($fields['blocksFiles'] ?? false) {
                $fields['blocksFiles'] = call_user_func_array('array_merge', $fields['blocksFiles'] ?? []);
            }
            if ($fields['blocksBrowsers'] ?? false) {
                $fields['blocksBrowsers'] = call_user_func_array('array_merge', $fields['blocksBrowsers'] ?? []);
            }
        }
        return $fields;
    }
}

@sebastianlenton & @ifox - The idea is good, but which title should be shown if you have more then one entry in the Browser block?

image

Thanks @noxify for taking the time to explain that to me- much appreciated, looks like I'm on the right track now.

In my case I'm only allowing one item to be selected in the browser field, but aside from that you raise a very good point!

If you have some minutes, I can give you a running version ;)

Here my running version.

https://gist.github.com/noxify/237b7ee4b5cecffa1feaf5fb5be033fc

In Line 127 i've added a first() to have a unique value for my title, you can modify as you want :)
If there is no element in the browser block, it will show the default block title.

Example with block title:
image

Example with custom title (and two relations):
image

If you change the order from the projects, the title will be updated also :)
image

Nice @noxify! However I would not recommend overriding the entire getFormFieldsHandleBlocks function as it is pretty complex and critical (which tells me we should probably split it for better extensibility). This is the only solution for now though, so thanks for sharing, but I think we should update Twill to call that function if it is defined instead.

@ifox - absolutely!
As a temporary solution the code snippet should be good enough to continue, but it's not maintainable :) looking forward how this could be solved in the future.

Idea: maybe it's possible to create a "flat browser list" or "simple relation list" where the selected relations are shown directly without the "accordion".

Closing for inactivity.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

newvladimirov picture newvladimirov  路  3Comments

noxify picture noxify  路  4Comments

jayhaluska picture jayhaluska  路  4Comments

milewski picture milewski  路  4Comments

sebastianlenton picture sebastianlenton  路  4Comments