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}