You Say Custom Field Formatter I Say Template Preprocess Field

Submitted by Marc on Sat, 05/19/2018 - 13:31
Darth Maul doing Crossfit

I must admit that in all the time I've spend developing Drupal 7 modules, I've never quite fully understood render arrays. Oh, I understand that it's basically an array of stuff with some objects mixed in for chaos and I've used preprocess functions to change some of the array adding custom functionality prior to it being rendered in the DOM. But, when it really came down to brass tax, I sort of always felt as if I were "hacking" it a little. Almost like I thought there was some Drupal API call that I was missing to get at the values, set custom values, etc. And perhaps I wasn't looking deep enough?

When I started focusing my attention on Drupal 8 development, I told myself "Self! You're going to do things the correct way this time!" Ha. Little did I know that the documentation for Drupal 8 stuff is:

  1. All over the map in terms of the proper way to do something - there's pre-release stuff that's no longer relevant and there's other folks like me trying to recreate Drupal 7 ideas in Drupal 8
  2. Difficult to read! I really tried to read the documentation on but it's tough! I wish there were more examples on the API documentation pages
  3. When there is a tutorial I seem to second guess if what they are doing is what I should be doing for my project?

Here's where I was stuck last week. I've got a call to an external web service that pulls in some HTML. I'd like to place this HTML into a node (that can't be changed by the user editing the node so no placing the html into the body field...). My first thought was that Drupal 8 has a different way to handle HTML templates with twig. And the way to implement this would be with a custom field formatter. Unfortunately, it seems that twig is being smart and strips out many of the HTML tags for safety reasons. I get that, but ultimately I know the HTML is safe and I just want to spit it out on the page instead of the field that was set.

So, my second thought was to go back to the way I did it in Drupal 7 - to use a template_preprocess_field hook and simply override the #markup part of the render array. That sort of worked, but again, many of the tags were stripped out as (I think this is new in D8) that #markup is run through a filter to help weed out possible security issues.

Finally, I found this post where one of the lower comments says this:

return [
  '#children' => $html,

So simple, and yet it worked. No tags were stripped and all went well. And I have no idea why. I've tried looking up what that "#children" element is in the array and what it does but I can't really find anything that really explains it! I'm back to "well, I suppose I just hacked it?" For now, I'll leave it in as it appears to be doing the job. In the future, I hope to really try and explore the "correct" way to do this, even though there probably isn't just one way to alter Drupal markup!