Preface: I don't often work with Drupal, so I may not be using the correct terminology or fully understand the stack. Please bear with me, I'll do my best to be as clear as possible.

I want to filter the rendered output of the primary "Body" field on a "Basic Page" (or "Article," any content type really) to add some classes to various elements. This would be the field labeled "Body" at /node/add/page. I'd like to achieve this using DOMDocument in my .theme file, but I'm having trouble figuring out what the correct "hook" is to tie in to.

So ultimately the goal would be a function something like the following (which is partially psuedo code):

function my_theme_body_alter(&$content) {
    $DOM = new DOMDocument();

    $DOM->loadHTML(mb_convert_encoding($content, "HTML-ENTITIES", "UTF-8"), LIBXML_HTML_NODEFDTD);

    $anchors = $DOM->getElementsByTagName("a");

    foreach ($anchors as $anchor) {
        $existing_classes = $anchor->getAttribute("class") ? $anchor->getAttribute("class") : "";

        $anchor->setAttribute("class", "button {$existing_classes}");

    $content = $DOM->saveHTML($content);

    return $content;

To be absolutely clear, I want to modify the output (on the front end) of this field:


What is the name of the hook I'm looking for, or how can I locate it myself?

  • Are you trying to add classes to the form widget, or to the rendered output?
    – Jaypan
    Commented Jun 2, 2020 at 16:13
  • The rendered output Commented Jun 2, 2020 at 16:13
  • 2
    Does this answer your question? How to alter the output of a formatter plugin?
    – Jaypan
    Commented Jun 2, 2020 at 16:31
  • @Jaypan it may be enough to get me going, I'll report back later today... Commented Jun 2, 2020 at 16:34
  • 1
    A good way to do this for CKEditor content is to add to allowed tags and allowed classes, where the classes are mapped to html elements and css names. No DOMDocument needed for this. Note that the above code will apply button class to any and all a tags found, which may not be the desired outcome.
    – Kevin
    Commented Jun 2, 2020 at 16:58

1 Answer 1


note:I have tested it in my machine and it works 100%

  1. the Hook_preprocess_node is gonna be executed before the rendering of any node of any content-type, you have to apply your logic here but be sure to apply it only of the body field exist otherwise you'll get an error if some content type doesn't have this field, then inject the updated dom into the node.html.twig template using the $varaibles that has been passed by ref to the current hook:
* Implements  hook_preprocess_hook
function test_preprocess_node(&$variables){
 // 1. Getting the current node.
 $node = $variables['node'];

 //2. Apply this logic to all nodes that have a body field
 if( $node->hasField('body')){

   //3.Get the body field
    $body = $node->body->value;

    //4.Apply som logic on the body field
     $body = updateBodyDom($body);

   //5.injecting the result into the node template (ex: node.html.twig)
   $variables['body'] =  $body ;


function updateBodyDom($body){
 $DOM = new DOMDocument();

 $DOM->loadHTML(mb_convert_encoding($body, "HTML-ENTITIES", "UTF-8"), LIBXML_HTML_NODEFDTD);

 $anchors = $DOM->getElementsByTagName("a");

 foreach ($anchors as $anchor) {
   $existing_classes = $anchor->getAttribute("class") ? $anchor->getAttribute("class") : "";
   $anchor->setAttribute("class", "button {$existing_classes}");

   //kint($anchor-> getAttribute('class')); die();

 $content = $DOM->saveHTML( );
 return   $content;

  1. in your templates folder create node.html.twig, to render the injected body :
{{ body }}
  • You should not use the raw filter if the variable could contain user input, which is clearly the case here. See drupal.org/docs/theming-drupal/twig-in-drupal/…
    – 4uk4
    Commented Jun 3, 2020 at 6:53
  • @4K4 so what is the best solution you think, to render the WYSIWYG field into HTML inside our twig template? Commented Jun 3, 2020 at 7:38
  • Use '#type' => 'processed_text', see drupal.stackexchange.com/a/238780/47547
    – 4uk4
    Commented Jun 3, 2020 at 7:50
  • But normally you don't need a code solution. The output of formatted text fields is configured in UI, see the comment from @Kevin. If core doesn't provide the config option you need then install additional text filters.
    – 4uk4
    Commented Jun 3, 2020 at 9:09
  • This lead me down the right path, accpeted. Commented Jun 3, 2020 at 16:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.