[{"data":1,"prerenderedAt":118},["ShallowReactive",2],{"article-\u002Fwriting\u002Fcustom-formatters-410-20260731":3},{"id":4,"title":5,"articleType":6,"categories":7,"date":10,"description":11,"extension":12,"meta":13,"paragraphs":14,"path":113,"readingTime":114,"sitemap":115,"stem":116,"__hash__":117},"articleEntries\u002Farticles-data\u002Fcustom-formatters-410-20260731.json","Custom Formatters 4.1.0","Blog post",[8,9],"Drupal","Planet Drupal","2026-07-31T13:30:00+10:00","Nearly a decade after stepping away, 4.1.0 picks the module back up and brings back formatter settings, live preview, a CodeMirror editor, and Devel Generate support, with more to come.","json",{},[15,25,52,64,70,81,87,100],{"type":16,"layout":17,"regions":18},"section","layout_onecol",{"content":19},[20,23],{"type":21,"html":22},"text_formatted","\u003Cp>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.\u003C\u002Fp>\n\n\u003Cp>It didn't die, though, and that's almost entirely down to one person. \u003Ca href=\"https:\u002F\u002Fwww.drupal.org\u002Fu\u002Fpodarok\">Andrii Podanenko\u003C\u002Fa> (\u003Cem>podarok\u003C\u002Fem>), backed by \u003Ca href=\"https:\u002F\u002Fwww.drupal.org\u002Fitcare\">ITCare\u003C\u002Fa> and the \u003Ca href=\"https:\u002F\u002Fwww.drupal.org\u002Fopen-y\">Open Y\u003C\u002Fa> 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.\u003C\u002Fp>",{"type":21,"html":24},"\u003Cp>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.\u003C\u002Fp>",{"type":16,"title":26,"layout":17,"regions":27},"Formatter settings",{"content":28},[29,31,38,40,46,48],{"type":21,"html":30},"\u003Cp>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 \u003Ccode>eval()\u003C\u002Fcode>'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.\u003C\u002Fp>\n\n\u003Cp>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 \u003Ccode>settings.field_name\u003C\u002Fcode> for the rendered value, or \u003Ccode>raw_settings.field_name\u003C\u002Fcode> if you want it unformatted.\u003C\u002Fp>",{"type":32,"src":33,"alt":34,"caption":35,"width":36,"height":37},"media","\u002Fimages\u002Fwriting\u002Fcustom-formatters-settings-fields.png","The Manage Fields tab on a Custom Formatters formatter, listing two attached fields: CSS class (Short text) and Link to entity (Boolean)","Attached like any other field.",1198,298,{"type":21,"html":39},"\u003Cp>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:\u003C\u002Fp>",{"type":32,"src":41,"alt":42,"caption":43,"width":44,"height":45},"\u002Fimages\u002Fwriting\u002Fcustom-formatters-settings-manage-display.png","The inline formatter settings on a Manage Display row for the Linkable title formatter, with a CSS class field set to text-lg and a Link to entity toggle switched on","Configured the same way as an image style.",810,463,{"type":21,"html":47},"\u003Cp>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:\u003C\u002Fp>",{"type":49,"title":50,"code":51},"code","Example: Linkable title (Twig + settings)","{% for item in items %}\n  {% set class = settings.field_css_class ? ' class=\"' ~ settings.field_css_class|clean_class ~ '\"' : '' %}\n  {% if settings.field_link and settings.field_link|lower not in ['no', 'off', 'false', '0', ''] %}\n    \u003Ca href=\"{{ entity.id ? path('entity.node.canonical', {'node': entity.id}) : '#' }}\"{{ class|raw }}>{{ item.value }}\u003C\u002Fa>\n  {% else %}\n    \u003Cspan{{ class|raw }}>{{ item.value }}\u003C\u002Fspan>\n  {% endif %}\n{% endfor %}",{"type":16,"title":53,"layout":17,"regions":54},"Live preview",{"content":55},[56,58],{"type":21,"html":57},"\u003Cp>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.\u003C\u002Fp>",{"type":32,"src":59,"alt":60,"caption":61,"width":62,"height":63},"\u002Fimages\u002Fwriting\u002Fcustom-formatters-settings-hero.png","The formatter edit form showing the syntax-highlighted CodeMirror editor for the Linkable title Twig template above a live preview panel, with CSS class set to text-lg and Link to entity enabled, a rendered link to a node, and a debug dump showing the settings and raw_settings values","Fill in the settings, see it render.",1312,1656,{"type":16,"title":65,"layout":17,"regions":66},"Devel Generate",{"content":67},[68],{"type":21,"html":69},"\u003Cp>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.\u003C\u002Fp>",{"type":16,"title":71,"layout":17,"regions":72},"A real code editor",{"content":73},[74,76],{"type":21,"html":75},"\u003Cp>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 \u003Ccode>{{\u003C\u002Fcode> in a Twig formatter and it offers the variables in scope; type \u003Ccode>[\u003C\u002Fcode> in an HTML+Token formatter and it offers Drupal tokens, including the \u003Ccode>[formatter_setting:...]\u003C\u002Fcode> ones; \u003Ccode>Ctrl+Space\u003C\u002Fcode> gives you context-appropriate suggestions in any engine.\u003C\u002Fp>",{"type":32,"src":77,"alt":78,"caption":79,"width":36,"height":80},"\u002Fimages\u002Fwriting\u002Fcustom-formatters-autocomplete.png","The CodeMirror editor on a Twig formatter with the autocomplete dropdown open after typing {{, offering the in-scope variables items, entity, langcode, settings and raw_settings","Type {{ in a Twig formatter: autocomplete knows what's in scope.",633,{"type":16,"title":82,"layout":17,"regions":83},"Also back",{"content":84},[85],{"type":21,"html":86},"\u003Cp>A few smaller things are back as well: a Save &amp; Edit button, so you're not bounced back to the formatter list every time you tweak something; and an \u003Ccode>entity\u003C\u002Fcode> 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.\u003C\u002Fp>\n\n\u003Cp>Integration with the \u003Ca href=\"https:\u002F\u002Fwww.drupal.org\u002Fproject\u002Finsert\">Insert\u003C\u002Fa> 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.\u003C\u002Fp>",{"type":16,"title":88,"layout":17,"regions":89},"Connected to Field Tokens",{"content":90},[91,93],{"type":21,"html":92},"\u003Cp>If you're running Field Tokens as well, this connects to something I fixed there too. The \u003Ccode>[formatted_field-*]\u003C\u002Fcode> 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.\u003C\u002Fp>",{"type":94,"title":95,"description":96,"link":97},"card","Field Tokens 2.0.0","Wildcard deltas, dot notation for nested formatter settings, and a restored Custom Formatters integration.",{"href":98,"label":99},"\u002Fwriting\u002Ffield-tokens-200-20260722","Read the Field Tokens 2.0.0 post",{"type":16,"layout":17,"regions":101},{"content":102},[103,105,107],{"type":21,"html":104},"\u003Cp>If any of this is useful to you, 4.1.0 is out now:\u003C\u002Fp>",{"type":49,"code":106},"composer require 'drupal\u002Fcustom_formatters:^4.1'",{"type":108,"description":109,"url":110,"gitpod":111,"drupalUrl":112},"repository","Source on GitHub, the full project page on Drupal.org, and if it's saved you some time, sponsorship is always appreciated.","https:\u002F\u002Fgithub.com\u002FDecipher\u002Fcustom_formatters",false,"https:\u002F\u002Fwww.drupal.org\u002Fproject\u002Fcustom_formatters","\u002Fwriting\u002Fcustom-formatters-410-20260731","4 min",{"loc":113},"articles-data\u002Fcustom-formatters-410-20260731","b94HneyZbDy5y7s94XfcKeA2cLF4sAIZQ_Wkloh7mv8",1786598540752]