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@endphp10 11<x-twill::block-editor12 :blocks="$blocks"13/>14 15@php16 $excludeBlocks = [17 'title',18 'quote'19 ];20@endphp21 22<x-twill::block-editor23 :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])
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/Name2php artisan twill:make:componentBlock namespace.name3php 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 TwillBlockComponent12{13 public function render(): View14 {15 return view('components.twill.blocks.example');16 }17 18 public function getForm(): Form19 {20 return Form::make([21 Input::make()->name('title'),22 Wysiwyg::make()->name('text')23 ]);24 }25}
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(): string12{13 return 'text';14}
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}
As with default blocks, you can also validate fields:
1public function getValidationRules(): array2{3 return [];4}5 6public function getTranslatableValidationRules(): array7{8 return [];9}
You have access to all the same variables as in a regular block, however with the components you have some additional helpers:
With components, you can directly access input values like this:
1{{ $input('title') }}2{{ $translatedInput('title') }}
Getting an image url:
1{{ $image('cover', 'default', ['h' => 100) }}
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
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!
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:
@twillPropTitle or @twillBlockTitle or @twillRepeaterTitle (mandatory)@twillPropTitleField or @twillBlockTitleField or @twillRepeaterTitleField
@twillPropIcon or @twillBlockIcon or @twillRepeaterIcon
@twillPropGroup or @twillBlockGroup or @twillRepeaterGroup (defaults to app)@twillPropTrigger or @twillRepeaterTrigger
@twillPropMax or @twillRepeaterMax, @twillRepeaterMax can also be defined from the formField. See Repeater form field
@twillPropCompiled or @twillBlockCompiled or @twillRepeaterCompiled
@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:files11 name="video"12 label="video"13 note="Video will overwrite previously selected images"14 :max="1"15/>16 17<x-twill::input18 name="caption"19 label="Caption"20 :maxlength="250"21 :translated="true"22/>23 24@php25 $options = [26 [27 'value' => 'cut',28 'label' => 'Cut'29 ],30 [31 'value' => 'fade',32 'label' => 'Fade In/Out'33 ]34 ];35@endphp36 37<x-twill::select38 name="effect"39 label="Transition effect"40 placeholder="Select transition effect"41 default="cut"42 :options="$options"43/>44 45<x-twill::color46 name="bg"47 label="Background color"48 note="Default is light grey (#E6E6E6)"49/>50 51<x-twill::input52 name="timing"53 label="Timing"54 note="Timing in ms (default is 4000ms)"55/>
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...
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
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 onlyphp artisan twill:list:icons will list all icons available.
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 choice11 ],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').
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 ModuleRepository10{11 use HandleBlocks;12 13 ...14}