This is probably an unusual scenario, but let me explain where I am.... I have a custom module that processes a feed from an external source and generates content (creates nodes). For some reason <br /> tags are coming through 'converted' rather than as raw HTML. In Drupal 7 I used PHP str_replace() to rectify this like:
File: node--video.tpl.php (where 'video' is my content type.
<?php
$filteredDescription = str_replace('<br />', '<br />', $content['body'][0]['#markup']);
$content['body'][0]['#markup'] = $filteredDescription;
?>
<div class="content"<?php print $content_attributes; ?>>
<?php print render($content); ?>
</div>
This worked well and was nice and simple, however in Drupal 9 (D8 too) we use TWIG and none of the replace functions I tried worked.
I figured the solution lied in using THEME_preprocess_node() where I could check the node type, filter the body field and create a new variable, then use that variable in the TWIG template.
This kind of worked but the body field also had some filtering that converted a url to a link, for example a facebook.com link would be converted to a working link. Therefore I needed the body field filtered to correct any links and then the <br /> tags to be fixed.
This took me a while to figure out but is actually quite simple and uses a function called check_markup(). The function needs two arguments i.e.
$filteredBody = check_markup($node->body->value, $node->body->format);
Let's say my theme is called myD9theme and my content type is called videoto make this easier to read.
File: myD9theme.theme
function myD9theme_preprocess_node(&$variables) {
$nodeType = $variables['node']->getType();
if($nodeType == 'video'){
$nodeBody = check_markup($variables['node']->body->value, $variables['node']->body->format); // Filtered HTML
$variables['videoBodyStripped'] = str_replace('<br />', '
', $nodeBody); // String replace
}
}
$variables['videoBodyStripped'] creates a new variable (videoBodyStripped) that can be used in the TWIG template like {{ videoBodyStripped }}.
File: node--video.html.twig
<div id="node-{{ node.id }}" {{ attributes.addClass(nodevideo') }}>
<div {{ content_attributes.addClass('content') }}>
{# content.body #}
{# node.body.value|raw #}
{# content.body|replace({'<br />' : '<br />'}) #}
{#
{% set twig_content_variable = node.body.value %}
{% set replace_value_var = '<br />' %}
{% set replace_with_value_var = '<br />' %}
{{ twig_content_variable|replace({ (replace_value_var): replace_with_value_var }) }}
#}
{# Seems to be a lot of ways to do this, that don't work. Eventually did it in myD9theme_preprocess_node() #}
{{ videoBodyStripped|raw }}
</div>
</div>
I've left my original workings in place so you can see the TWIG solutions, but the main line to pay attention to is: {{ videoBodyStripped|raw }} where I output my new variable using the |raw filter.
Remember to rebuild the cache or your new code won't be read!