Extending
Xplain asks a list of describers about each field. The first whose supports() answers true
fills in the explanation. Describers registered by plugins are asked before the built-in ones, so
you can describe your own field type or override Xplain on a core one.
use craft\base\FieldInterface;
use justinholtweb\xplain\describers\DescriberInterface;
use justinholtweb\xplain\events\RegisterDescribersEvent;
use justinholtweb\xplain\models\Explanation;
use justinholtweb\xplain\models\Placement;
use justinholtweb\xplain\services\Explainer;
use yii\base\Event;
class MapFieldDescriber implements DescriberInterface
{
public function supports(FieldInterface $field): bool
{
return $field instanceof \myplugin\fields\Map;
}
public function describe(FieldInterface $field, Explanation $x, string $ref, ?Placement $placement): void
{
$x->summary = 'Map — one location with a zoom level.';
$x->valueType = 'MapData|null';
$x->inline = "`{{ $ref.lat }}, {{ $ref.lng }}`";
$x->twig = "{% if $ref %}\n <div data-lat=\"{{ $ref.lat }}\" data-lng=\"{{ $ref.lng }}\"></div>\n{% endif %}";
$x->addTip("`$ref.zoom` is the zoom level the author chose.");
}
}
Event::on(Explainer::class, Explainer::EVENT_REGISTER_DESCRIBERS, function(RegisterDescribersEvent $e) {
$e->describers[] = new MapFieldDescriber();
});
$refis the Twig expression that holds the value in this layout —entry.map,block.map,category.map. Use it rather than building your own.$placementis null when Xplain explains the field on its own (its settings screen).inlinebecomes part of a one-paragraph tip. Keep it to one line of Markdown.- Tips added with
prependTip()go in front of type advice; Xplain uses that for layout renames and conditions.
Keep it deterministic
Xplain rewrites a tip only when the text it would write changes. A describer that includes a date, a count of entries or anything else that moves on its own will rewrite project config on every run.