1

My blog posts are saved in a DB in text format and I can't find the way of displaying HTML code between the paragraphs as you can see in the image below.

I'm using Prismjs and <pre><code></code></pre> tags..

enter image description here

Inside the code block there should be two <div> tags which are not displayed.

Looks like this in the database table

Laravel is a web application framework with expressive, elegant syntax. A web framework provides a structure and starting point for creating your application, allowing you to focus on creating something amazing while we sweat the details.

Laravel strives to provide an amazing developer experience while providing powerful features such as thorough dependency injection, an expressive database abstraction layer, queues and scheduled jobs, unit and integration testing, and more.

Whether you are new to PHP or web frameworks or have years of experience, Laravel is a framework that can grow with you. We'll help you take your first steps as a web developer or give you a boost as you take your expertise to the next level. We can't wait to see what you build.

<pre><code class="lang-html">
<div>test</div>
</code></pre>

In my post_body.blade.php view I'm using {!! nl2br($post->body) !!} to display the content of the post.

If I use <pre><code class="lang-html">{{ $post->body }}</code></pre> on the blade view the code is visible but I have no way of including the text of the post. It would only work to show code.

I'm facing the problem of not been able to do both things, is one or the other.

Gass
  • 7,536
  • 3
  • 37
  • 41

1 Answers1

2

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

iivannov
  • 4,341
  • 1
  • 18
  • 24
  • Thank you for your well thought answer. I will try to solve it with your approaches. – Gass Aug 24 '21 at 15:27
  • Sorry, there were some errors in the PHP code, that I fixed now. If you have any troubles share your progress, if I can help any further. – iivannov Aug 24 '21 at 15:47