There is no straightforward way of doing this by using standard Laravel/Blade output options. However it's possible to accomplish it with a little bit of extra code.
1. Why is this happening
Neither <pre>
or <code>
is stopping the browser to interpret the text inside as html code. They have different purpose: one is to tell the browser that the whitespaces are important and the other to tell that the content is some computer code and needs to be shown with different styling. In both cases if valid HTML code is inside the tags it will be treated as HTML.
By the way it's mentioned in Prism documentation that you need to escape the content:
Note: You have to escape all < and & characters inside < code > elements
(code blocks and inline snippets) with < and & respectively, or
else the browser might interpret them as an HTML tag or entity. If you
have large portions of HTML code, you can use the Unescaped Markup
plugin to work around this.
2. Solutions
There are different ways of solving your issue. You can either modify the input before saving it to the database and then just print the unescaped contents or modify the output and make sure you have escaped only the text in the <code>
tag.
Because we don't know much about the input method you use let's focus on the second option to modify the output.
A. PrismJS
Their documentation points to a solution where you can use the Unescaped markup plugin to solve your issue. I don't have any experience with it, but the slogan says "Write markup without having to escape anything.", so it seems it will do the work.
You only need to include the plugin and then you have two options: to swap <pre><code>
for <script>
or to use HTML-comment to wrap your code (if you don't have other comments in the code
Just look at their examples for detailed information
B. PHP
You can use PHP to parse the text from the database and escape the content of the needed elements. In your case this is the code
element. You will need to write your own implementation or use the one that I wrote for your case.
Then you can just do:
{!! Houdini::escape($content) !!}
Include or autoload the following class:
class Houdini
{
/**
* Escape the html characters inside a given HTML element
*
* @param string $text The text we are trying to clean
* @param string $element The name of the elements to be escaped
* @param bool $fix Should we try to make the text a valid HTML by wrapping it with divs
*
* @return string
*/
public static function escape($text, $element = 'code', $fix = true) {
$dom = new DOMDocument;
$dom->loadXML($fix ? '<div>' . $text . '</div>' : $text);
$nodes = $dom->getElementsByTagName($element);
foreach ($nodes as $node) {
$content = '';
foreach ($node->childNodes as $child) {
$content .= self::escapeRecursively($child);
}
$node->nodeValue = htmlspecialchars($content);
}
return $dom->saveHTML();
}
/**
* Escape node and note contents
*
* @param $node
* @return string
*/
protected static function escapeRecursively($node) {
if ($node instanceof DOMText)
return $node->textContent;
$content = "<$node->nodeName>";
foreach ($node->childNodes as $child) {
$content .= self::escapeRecursively($child);
}
return "$content</$node->nodeName>";
}
}
C. JavaScript
You can include the following javascript code which will loop trough all the <code>
elements and set the innerHtml as the innerText.
document.querySelectorAll("code").forEach(el => el.innerText = el.innerHTML);
Note: If you keep the paragraphs in the database separated only with new lines and not wrapped in <p>
you will have issues using this solution and nl2br()
together.
D. Deprecated <xmp>
<pre><code class="lang-html">
<xmp><div>test</div></xmp>
</code></pre>
There WAS after all an HTML tag specifically to show example HTML code as it is, but it was deprecated in HTML 3.2, BUT it seems the tag is widely supported and wrapping the code contents can be a quick and dirty solution for your case. You can see the support tables here: https://caniuse.com/?search=xmp
Read more here: https://html.com/tags/xmp/#ixzz74T0AJctF
You can accomplish this by adding the tags before saving to the database or when printing the output with JavaScript on the client side or with PHP before passing it to the blade template.
3. Other StackOverflow posts that helped me for this answer