Custom Formatters 4.1.0
Custom Formatters is old. I started it in 2009, my first year building seriously for Drupal, and shipped it through Drupal 6 and 7. Then in late 2016, not long after the first Drupal 8 alpha, I stepped away (work, life, the usual reasons) and for the best part of a decade it wasn't mine to ship.
It didn't die, though, and that's almost entirely down to one person. Andrii Podanenko (podarok), backed by ITCare and the Open Y distribution, carried it through the Drupal 8 beta, the Drupal 10 port, and the start of the Drupal 11 line, essentially single-handedly, for years. Huge thanks to Andrii for looking after it all that time. I've picked the 4.1.x line back up alongside him, and 4.1.0 is the first release to come out of that.
4.1.0 is, deliberately, a bit of a nostalgia trip. A handful of the things that made the module worth reaching for in the first place quietly went missing during the Drupal 8 port (formatter settings, live preview, a real code editor, Devel Generate support), and this release brings four of them back. There's new stuff too.
Formatter settings
The old approach leaned on the Form Builder module, a separate drag-and-drop form builder bolted on the side. You'd end up with a real settings form in theory, but what it actually generated behind the scenes was a block of PHP form arrays that got eval()'d at render time. Clever for 2011. Not exactly integrated, and it quietly disappeared in the Drupal 8 port along with a few other things.
4.1.0 finally replaces it. Formatter settings are just fields now, attached to a formatter the same way you'd attach fields to any content type: a text field for a CSS class, a boolean for whether to link to the entity, whatever the formatter needs. In the template it's settings.field_name for the rendered value, or raw_settings.field_name if you want it unformatted.
You attach the fields the normal way, and configure them per placement right from Manage Display, the same way you'd configure an image style:
The module ships its own example of this, a Twig formatter called "Linkable title" that wraps the field value in a link and applies whatever class you've given it:
{% for item in items %}
{% set class = settings.field_css_class ? ' class="' ~ settings.field_css_class|clean_class ~ '"' : '' %}
{% if settings.field_link and settings.field_link|lower not in ['no', 'off', 'false', '0', ''] %}
<a href="{{ entity.id ? path('entity.node.canonical', {'node': entity.id}) : '#' }}"{{ class|raw }}>{{ item.value }}</a>
{% else %}
<span{{ class|raw }}>{{ item.value }}</span>
{% endif %}
{% endfor %}Live preview
Settings only matter if you can see what they do, so live preview is back too, and it's wired into settings. Pick an entity, fill in the settings, and watch the output render right there on the edit form. The panel gives you per-engine debug output alongside the render itself (a variables dump for Twig and PHP, the raw HTML for HTML+Token), so you can see exactly what reached the template.
Devel Generate
And if nothing on the site has the right field type yet (say you're building an image formatter before any image field exists), Devel Generate support steps in. It builds a throwaway sample entity for the preview instead of leaving it blank, so you're never creating a dummy node just to see your formatter render.
A real code editor
The last of the four returning features is the one I'm most pleased with: a real code editor. The template field is now a CodeMirror editor, syntax-highlighted with HTML-aware auto-closing tags, instead of a plain textarea. More usefully, its autocomplete actually knows what each engine supports. Type {{ in a Twig formatter and it offers the variables in scope; type [ in an HTML+Token formatter and it offers Drupal tokens, including the [formatter_setting:...] ones; Ctrl+Space gives you context-appropriate suggestions in any engine.
Also back
A few smaller things are back as well: a Save & Edit button, so you're not bounced back to the formatter list every time you tweak something; and an entity variable in Twig templates, so a formatter can reach the parent entity directly instead of only the field it's attached to. Drupal 11 support is locked in.
Integration with the Insert module is back too. Any formatter targeting an image, file, or entity reference field is automatically exposed as an Insert style and can be dropped straight into a WYSIWYG.
Connected to Field Tokens
If you're running Field Tokens as well, this connects to something I fixed there too. The [formatted_field-*] integration, which lets a token render a field through one of these formatters, broke during Field Tokens' own Drupal 8 port and stayed broken for years. 2.0.0 rebuilt that data provider from scratch, so whatever you build here, settings included, is reachable from a token again.
Field Tokens 2.0.0
Wildcard deltas, dot notation for nested formatter settings, and a restored Custom Formatters integration.
If any of this is useful to you, 4.1.0 is out now:
composer require 'drupal/custom_formatters:^4.1'