This package is a simple solution to add a template
field to your Twill Modules and do interesting things with it. It can help you make small variations to your forms based on the selected template, organize your form variations with Blade partials, and prefill the block editor with a selection of blocks when a record is created.
Table of contents
- Installation
- Getting Started
- Dedicated Form Templates
- Using JSON Field Groups
- Block Editor Templates
- Custom Template Field
- Working With Translations
- Extending the Package Views
- License
composer require pboivin/twill-form-templates
The following example will guide you through the steps to create a pages
module and implement a template
field.
php artisan twill:make:module pages --hasBlocks
For this example, make sure to enable the Blocks feature. Anything else is optional.
As usual, add the module to your routes/admin.php
and config/twill-navigation.php
.
Add the new template
field:
// update file: database/migrations/xxxx_xx_xx_xxxxxx_create_pages_tables.php
class CreatePagesTables extends Migration
{
public function up()
{
Schema::create('pages', function (Blueprint $table) {
// ...
$table->string('template', 50)->nullable();
});
// ...
}
}
Then run the migrations:
php artisan migrate
Add the HasFormTemplates
trait and the new field to $fillable
:
// update file: app/Models/Page.php
use Pboivin\TwillFormTemplates\HasFormTemplates;
class Page extends Model
{
use HasFormTemplates;
protected $fillable = [
// ...
'template',
];
// ...
}
In the same file, define the values needed for your template field:
public $formTemplates = [
'options' => [
[
'value' => 'home',
'label' => 'Home',
],
[
'value' => 'about',
'label' => 'About',
],
[
'value' => 'contact',
'label' => 'Contact',
],
[
'value' => 'custom_page',
'label' => 'Custom Page',
],
],
'default' => 'custom_page'
];
Here, we define 3 templates for the core pages of our site (home
, about
, contact
) and 1 that can be used more freely to create customized pages with the block editor (custom_page
).
Add the HandleFormTemplates
trait:
// update file: app/Repositories/PageRepository.php
use Pboivin\TwillFormTemplates\HandleFormTemplates;
class PageRepository extends ModuleRepository
{
use HandleFormTemplates;
// ...
}
To enable users to select a template when creating a new page, we need to extend Twill's built-in create.blade.php
view. Here is the original file for reference. Here is our extended version:
// add file: resources/views/admin/pages/create.blade.php
@formField('input', [
'name' => $titleFormKey ?? 'title',
'label' => $titleFormKey === 'title' ?
twillTrans('twill::lang.modal.title-field') : ucfirst($titleFormKey),
'translated' => $translateTitle ?? false,
'required' => true,
'onChange' => 'formatPermalink'
])
@twillFormTemplateField()
@if ($permalink ?? true)
@formField('input', [
'name' => 'slug',
'label' => twillTrans('twill::lang.modal.permalink-field'),
'translated' => true,
'ref' => 'permalink',
'prefix' => $permalinkPrefix ?? ''
])
@endif
This uses a new @twillFormTemplateField
directive to render the template field.
If you don't need to customize this further, you can use the shortcut provided by this package, instead of the above view:
// update file: resources/views/admin/pages/create.blade.php
@include('twill-form-templates::create')
The fun starts here :)
We can customize our form fields according to the selected template:
// update file: resources/views/admin/pages/form.blade.php
@extends('twill::layouts.form')
@section('contentFields')
@formField('input', [
'name' => 'description',
'label' => 'Description',
'translated' => true,
'maxlength' => 100
])
@if ($item->template === 'custom_page')
@formField('block_editor')
@endif
@stop
Here, all pages would contain a common description
field, and the custom_page
template would allow the full use of the block editor. This is obviously a simplified example but it should give you an insight on how to add variations to your forms based on a selection of templates.
The method presented above helps you introduce minor variations in your forms for each template. If you find that your form is starting to contain too many conditionals and you are trying to handle too many variations, consider using a dedicated partial for each template.
// update file: resources/views/admin/pages/form.blade.php
@extends('twill::layouts.form')
@twillFormTemplate()
This uses a new @twillFormTemplate
directive to select the appropriate partial.
Then, all that's left is to create the partials:
resources/views/admin/pages/_home.blade.php
resources/views/admin/pages/_about.blade.php
resources/views/admin/pages/_contact.blade.php
resources/views/admin/pages/_custom_page.blade.php
The file names should follow this format: _{$template}.blade.php
If you don't want to create one partial for every template, you can add a default partial that will be used as a fallback:
resources/views/admin/pages/_default.blade.php
With this approach, your pages
database table need to contain all possible columns for the pages
module. Again, this works well for a small number of variations but can start to feel ugly when all your pages have a different set of fields.
For this, you can use a built-in Twill feature to group all your form fields into a single JSON column in your table.
Along with the template
field, define a content
field:
// update file: database/migrations/xxxx_xx_xx_xxxxxx_create_pages_tables.php
Schema::create('pages', function (Blueprint $table) {
// ...
$table->string('template', 50)->nullable();
$table->json('content')->nullable();
});
// ...
Add the new field to $fillable
:
// update file: app/Models/Page.php
use HasFormTemplates;
protected $fillable = [
// ...
'template',
'content',
];
Define all your form fields in $fieldsGroups
:
// update file: app/Repositories/PageRepository.php
use HandleFormTemplates;
protected $fieldsGroups = [
'content' => [
'page_title',
'page_subtitle',
'home_call_to_action',
'about_footer_text',
// ...
]
];
To keep things organized, you can prefix common fields with page_
, and page-specific fields with the template name.
You can use JSON fields like regular fields in your forms:
// update file: resources/views/admin/pages/form.blade.php
@formField('input', [
'name' => 'page_title',
'label' => 'Page Title',
])
@formField('input', [
'name' => 'page_subtitle',
'label' => 'Page Subtitle',
])
@if ($item->template === 'home')
@formField('input', [
'name' => 'home_call_to_action',
'label' => 'Call to Action',
])
@endif
@if ($item->template === 'about')
@formField('input', [
'name' => 'about_footer_text',
'label' => 'Footer Text',
])
@endif
// ...
Form templates are a great fit for pages that share a lot of common fields. However, some pages are better served exclusively by the block editor to allow full customization. To help with this type of content, this package offers a way to prefill the block editor with a fixed selection of blocks, when a page is created.
Let's create some blocks to complete this example:
php artisan twill:make:block page-header
php artisan twill:make:block text
php artisan twill:make:block banner
In our $formTemplates
configuration, we'll add a new template (legal
) for text-only pages such as Terms & Conditions. Then, we'll define a block selection for our 2 templates that support a block editor:
// update file: app/Models/Page.php
public $formTemplates = [
'options' => [
[
'value' => 'home',
'label' => 'Home',
],
[
'value' => 'about',
'label' => 'About',
],
[
'value' => 'contact',
'label' => 'Contact',
],
[
'value' => 'legal',
'label' => 'Legal',
'block_selection' => ['text'],
],
[
'value' => 'custom_page',
'label' => 'Custom Page',
'block_selection' => ['page-header', 'text', 'banner', 'text'],
],
],
'default' => 'custom_page'
];
When we create a page with the legal
template, the block editor will be prefilled with 1 text
block.
When we create a page with the custom_page
template, the block editor will be prefilled with 4 blocks.
We want to show the block_editor
field on legal
pages as well as custom pages:
// update file: resources/views/admin/pages/form.blade.php
@section('contentFields')
...
@if (in_array($item->template, ['custom_page', 'legal']))
@formField('block_editor')
@endif
@stop
The above configuration is used for modules with a single block editor (default
). Use the following configuration for multiple block editors:
// ...
[
'value' => 'custom_page',
'label' => 'Custom Page',
'block_selection' => [
'default' => ['text', 'banner', 'text'], // Prefill the default block editor.
'header' => ['page-header'], // Prefill the `header` named block editor.
],
],
// ...
You can customize the template
field name and label with the $templateField
property in your Model:
// update file: app/Models/Page.php
public $templateField = [
'name' => 'page_template',
'label' => 'Page Template',
];
Of course, the field name also has to be modified in the migration.
Through the constructor, you can use the twillTrans()
helper to translate all labels according to the user's language preference in the CMS:
// update file: app/Models/Page.php
public function __construct(array $attributes = [])
{
$this->templateField = [
'name' => 'template',
'label' => twillTrans('app.template_label'),
];
$this->formTemplates = [
'options' => [
[
'value' => 'home',
'label' => twillTrans('app.home_page'),
],
[
'value' => 'about',
'label' => twillTrans('app.about_page'),
],
// ...
],
];
parent::__construct($attributes);
}
You can find more information on string translations in the Laravel Documentation.
If you wish to customize the built-in views from this package, you can publish them to your project by running:
php artisan vendor:publish --provider='Pboivin\TwillFormTemplates\TwillFormTemplatesServiceProvider' --tag=views
The MIT License (MIT). Please see LICENSE.md for more information.