Creating Blocks

In order to add a block editor to your module, add the block editor field to your module form:

1BlockEditor::make()
2 
3BlockEditor::make()
4 ->blocks(['title', 'quote', 'text'])
1<x-twill::block-editor />
2 
3@php
4 $blocks = [
5 'title',
6 'quote',
7 'text'
8 ];
9@endphp
10 
11<x-twill::block-editor
12 :blocks="$blocks"
13/>
14 
15@php
16 $excludeBlocks = [
17 'title',
18 'quote'
19 ];
20@endphp
21 
22<x-twill::block-editor
23 :excludeBlocks="$excludeBlocks"
24/>
1@formField('block_editor', [
2 'blocks' => ['title', 'quote', 'text', 'image', 'grid', 'test', 'publications', 'news']
3])
4 
5@formField('block_editor', [
6 'excludeBlocks' => ['title', 'quote']
7])

Block component class

As of Twill 3, you can make use of Block component classes.

These are essentially regular Blade components, but they are also responsible for your Block's form and rendering!

You can generate Block components using the command:

1php artisan twill:make:componentBlock Namespace/Name
2php artisan twill:make:componentBlock namespace.name
3php artisan twill:make:componentBlock name

These blocks will be placed under App\View\Components\Twill\Blocks.

While the rendering blade file looks the same, there is no longer a form blade file.

Instead, you define the form in your component class, the same way you can do module forms!

1<?php
2 
3namespace App\View\Components\Twill\Blocks;
4 
5use A17\Twill\Services\Forms\Fields\Wysiwyg;
6use A17\Twill\Services\Forms\Form;
7use A17\Twill\Services\Forms\Fields\Input;
8use A17\Twill\View\Components\Blocks\TwillBlockComponent;
9use Illuminate\Contracts\View\View;
10 
11class Example extends TwillBlockComponent
12{
13 public function render(): View
14 {
15 return view('components.twill.blocks.example');
16 }
17 
18 public function getForm(): Form
19 {
20 return Form::make([
21 Input::make()->name('title'),
22 Wysiwyg::make()->name('text')
23 ]);
24 }
25}

Block helpers

By default, the class name will be used as your block name, and 'app' will be the default group.

These can be overwritten by overriding the following methods:

1public static function getBlockTitle(?Block $block = null): string
2{
3 return Str::replace('Block', '', Str::afterLast(static::class, '\\'));
4}
5 
6public static function getBlockGroup(): string
7{
8 return 'app';
9}
10 
11public static function getBlockIcon(): string
12{
13 return 'text';
14}

Crops

Usually we would define image crop's in the block_editor config, but with block components you can define them inline in your component like this:

1public static function getCrops(): array
2{
3 return [
4 'content_image' => [
5 'default' => [
6 [
7 'name' => 'default',
8 'ratio' => 16 / 9,
9 'minValues' => [
10 'width' => 100,
11 'height' => 100,
12 ],
13 ],
14 ]
15 ]
16 ];
17}

Validation

As with default blocks, you can also validate fields:

1public function getValidationRules(): array
2{
3 return [];
4}
5 
6public function getTranslatableValidationRules(): array
7{
8 return [];
9}

Rendering helpers

You have access to all the same variables as in a regular block, however with the components you have some additional helpers:

input and translated input

With components, you can directly access input values like this:

1{{ $input('title') }}
2{{ $translatedInput('title') }}

Image url

Getting an image url:

1{{ $image('cover', 'default', ['h' => 100) }}

Repeaters

Looping over a repeater:

1@foreach ($repeater('slider-item') as $repeaterItem)
2 <li>
3 <img src="{{ $repeaterItem->renderData->block->image('slider', 'desktop', ['h' => 850]) }}" alt="">
4 {{ $repeaterItem->renderData->block->input('title') }}
5 </li>
6@endforeach

Block component in packages or domain specific directories

If you want to register blocks from your package you can add:

1\A17\Twill\Facades\TwillBlocks::registerComponentBlocks('\\Your\\Namespace\\Components\\Twill\\Blocks', __DIR__ . '/../../path/to/namespace');

This will register the namespace in your package or domain and load them!

Using blade files

Blocks and Repeaters are built on the same Block model and are created and defined in their respective folders. By default, Twill will look for Blade templates in views/twill/blocks for blocks and views/twill/repeaters for repeaters.

Blocks (and Repeaters) are exactly like a regular form, without any Blade layout or section. The templates take special annotations to add further customization. The title annotation is mandatory and Twill will throw an error if it is not defined.

Available annotations:

  • Provide a title with @twillPropTitle or @twillBlockTitle or @twillRepeaterTitle (mandatory)
  • Provide a dynamic title with @twillPropTitleField or @twillBlockTitleField or @twillRepeaterTitleField
  • Provide an icon with @twillPropIcon or @twillBlockIcon or @twillRepeaterIcon
  • Provide a group with @twillPropGroup or @twillBlockGroup or @twillRepeaterGroup (defaults to app)
  • Provide a repeater trigger label with @twillPropTrigger or @twillRepeaterTrigger
  • Provide a repeater max items with @twillPropMax or @twillRepeaterMax, @twillRepeaterMax can also be defined from the formField. See Repeater form field
  • Define a block or repeater as compiled with @twillPropCompiled or @twillBlockCompiled or @twillRepeaterCompiled
  • Define a block or repeater component with @twillPropComponent or @twillBlockComponent or @twillRepeaterComponent

e.g.:

File:

views/twill/blocks/quote.blade.php

1@twillBlockTitle('Quote')
2@twillBlockIcon('text')
3 
4<x-twill::input
5 name="quote"
6 type="textarea"
7 label="Quote text"
8 :maxlength="250"
9 :rows="4"
10/>

A more complex example would look like this:

File:

views/twill/blocks/media.blade.php

1@twillBlockTitle('Media')
2@twillBlockIcon('image')
3 
4<x-twill::medias
5 name="image"
6 label="Images"
7 :max="20"
8/>
9 
10<x-twill:files
11 name="video"
12 label="video"
13 note="Video will overwrite previously selected images"
14 :max="1"
15/>
16 
17<x-twill::input
18 name="caption"
19 label="Caption"
20 :maxlength="250"
21 :translated="true"
22/>
23 
24@php
25 $options = [
26 [
27 'value' => 'cut',
28 'label' => 'Cut'
29 ],
30 [
31 'value' => 'fade',
32 'label' => 'Fade In/Out'
33 ]
34 ];
35@endphp
36 
37<x-twill::select
38 name="effect"
39 label="Transition effect"
40 placeholder="Select transition effect"
41 default="cut"
42 :options="$options"
43/>
44 
45<x-twill::color
46 name="bg"
47 label="Background color"
48 note="Default is light grey (#E6E6E6)"
49/>
50 
51<x-twill::input
52 name="timing"
53 label="Timing"
54 note="Timing in ms (default is 4000ms)"
55/>

Dynamic block titles

In Twill >= 2.5, you can use the @twillBlockTitleField directive to include the value of a given field in the title area of the blocks. This directive also accepts a hidePrefix option to hide the generic block title:

1@twillBlockTitle('Section')
2@twillBlockTitleField('title', ['hidePrefix' => true])
3@twillBlockIcon('text')
4@twillBlockGroup('app')
5 
6<x-twill::input
7 name="title"
8 label="Title"
9 :required="true"
10/>
11...

Create a block from an existing block template

Using php artisan twill:make:block {name} {baseBlock} {icon}, you can generate a new block based on a provided block as a base.

This example would create views/twill/blocks/exceptional-media.blade.php from views/twill/blocks/media.blade.php:

1$ php artisan twill:make:block ExceptionalMedia media image

List existing blocks and repeaters

Using php artisan twill:list:blocks will list all blocks and repeaters. There are a few options:

  • -s|--shorter for a shorter table,
  • -b|--blocks for blocks only,
  • -r|--repeaters for repeaters only,
  • -a|--app for app blocks/repeaters only,
  • -c|--custom for app blocks/repeaters overriding Twill blocks/repeaters only,
  • -t|--twill for Twill blocks/repeaters only

List existing icons

php artisan twill:list:icons will list all icons available.

Using custom icons

Custom icons need to be named differently from default icons to avoid issues when creating the SVG sprites.

If you want to use custom icons in a block, you have to define the source directory's path in config/twill.php. Add it under block_editor.directories.source.icons key:

File:

config/twill.php

1<?php
2 
3return [
4 ...
5 'block_editor' => [
6 'directories' => [
7 'source' => [
8 'icons' => [
9 base_path('vendor/area17/twill/frontend/icons'),
10 resource_path('assets/admin/icons'), // or any other path of your choice
11 ],
12 ],
13 ],
14 ],
15 ...
16];

See also Default Configuration.

If the resource_path('assets/admin/icons') directory contains a my-custom-icon.svg file, you can use this icon in your block by using its basename: @twillBlockIcon('my-custom-icon').

Use Block traits in your Model and Repository

Now, to handle the block data you must integrate it with your module. Use the Blocks traits in the Model and Repository associated with your module. If you generated that module from the CLI and did respond yes to the question asking you about using blocks, this should already be the case for you.

In your model, use HasBlocks:

File:

app/Models/Article.php

1<?php
2 
3namespace App\Models;
4 
5use A17\Twill\Models\Behaviors\HasBlocks;
6use A17\Twill\Models\Model;
7 
8class Article extends Model
9{
10 use HasBlocks;
11 
12 ...
13}

In your repository, use HandleBlocks:

File:

app/Repositories/ArticleRepository.php

1<?php
2 
3namespace App\Repositories;
4 
5use A17\Twill\Repositories\Behaviors\HandleBlocks;
6use A17\Twill\Repositories\ModuleRepository;
7use App\Models\Article;
8 
9class ArticleRepository extends ModuleRepository
10{
11 use HandleBlocks;
12 
13 ...
14}