You can create custom Widgets for the front end (see the form generator)
or the back end (see DCA fields). In both cases, the custom widget
needs to extend from the abstract \Contao\Widget
class. The custom widget class
is then registered either via the $GLOBALS['BE_FFL']
array (back end widgets)
or the $GLOBALS['TL_FFL']
array (front end widgets).
Also in both cases, the abstract method generate()
needs to be implemented. However,
when the widget is rendered, Contao will execute the parse()
method of the widget
(also both in the front and back end). It is then up to each widget’s implementation
how the output is delivered.
The abstract class also contains some member variables that control the output and behavior of the widget. The default value of these member variables will need to be set in the custom child class accordingly. Typically, the following member variables are adjusted:
$blnSubmitInput
: controls whether this widget actually submits any input.$blnForAttribute
: controls whether a for
attribute should be used for the widget’s label.$strTemplate
: the Contao template for the widget.$strPrefix
: controls the CSS class prefix for front end widgets.The following example creates a simple text input widget for the back end. The input
is allowed to be submitted and the generated label should contain the for
attribute.
The template is set to be_widget
, which most back end widgets commonly use. It
contains the label as a headline and executes $this->generateWithError(true)
,
which in turn will execute $this->generate()
.
// src/Widget/Backend/CustomWidget.php
namespace App\Widget\Backend;
use Contao\StringUtil;
use Contao\Widget;
class CustomWidget extends Widget
{
protected $blnSubmitInput = true;
protected $blnForAttribute = true;
protected $strTemplate = 'be_widget';
public function generate(): string
{
return sprintf(
'<input type="text" name="%s" id="ctrl_%s" class="tl_custom_widget%s" value="%s">',
$this->name,
$this->id,
($this->class ? ' ' . $this->class : ''),
StringUtil::specialchars($this->value)
);
}
}
To get a better idea on the implementation details and possibilities for back end widgets, have a look at the source of the core’s widgets.
The widget is registered in the $GLOBALS['BE_FFL']
array with its own key:
// contao/config/config.php
use App\Widget\Backend\CustomWidget;
$GLOBALS['BE_FFL']['custom_widget'] = CustomWidget::class;
Now the widget can be used as an inputType
in your DCA.
Similar to the back end example, the following example creates a simple text input
widget (form field) for the form generator. The input is allowed to be submitted
and the generated label should contain the for
attribute. The template is set to
form_custom_field
and the CSS class prefix is set to widget widget-custom-field
.
// src/Widget/Frontend/CustomField.php
namespace App\Widget\Frontend;
use Contao\Widget;
class CustomField extends Widget
{
protected $blnSubmitInput = true;
protected $blnForAttribute = true;
protected $strTemplate = 'form_custom_field';
protected $strPrefix = 'widget widget-custom-field';
public function generate(): string
{
// Not actually used
return '';
}
}
This time the widget’s HTML output is done in the template file where we extend
the form_row
template (see template inheritance).
<?php $this->extend('form_row'); ?>
<?php $this->block('label'); ?>
<?= $this->generateLabel() ?>
<?php $this->endblock(); ?>
<?php $this->block('field'); ?>
<?php if ($this->hasErrors()): ?>
<p class="error"><?= $this->getErrorAsString(); ?></p>
<?php endif; ?>
<input
type="text"
name="<?= $this->name ?>"
id="ctrl_<?= $this->id ?>"
class="text<?php if ($this->class): ?> <?= $this->class ?><?php endif; ?>"
value="<?= Contao\StringUtil::specialchars($this->value) ?>"
>
<?php $this->endblock(); ?>
To get a better idea on the implementation details and possibilities for front end widgets, have a look at the source of the core’s form fields and their templates.
The widget is registered in the $GLOBALS['TL_FFL']
array with its own key:
// contao/config/config.php
use App\Widget\Frontend\CustomField;
$GLOBALS['TL_FFL']['custom_field'] = CustomField::class;
Now the widget can be selected as an additional form field in the form generator.
To translate the form field’s name, use the FFL.custom_field.0
& FFL.custom_field.1
key
in the contao_default
domain, e.g.
// contao/languages/en/default.php
$GLOBALS['TL_LANG']['FFL']['custom_field'] = [
'My custom form field',
'Provides a custom form field.'
];
Lastly our new field will still need a palette in the DCA of tl_form_field
, otherwise
you will not be able to set any options for the field within the form generator
(like the field’s name and label for example).
// contao/dca/tl_form_field.php
$GLOBALS['TL_DCA']['tl_form_field']['palettes']['custom_field'] =
'{type_legend},type,name,label;{fconfig_legend},mandatory;{expert_legend:hide},class,accesskey,tabindex;{template_legend:hide},customTpl;{invisible_legend:hide},invisible'
;