Making Craft CMS work with Prism JS using pre and code blocks

You may (or may not) have noticed that my site had a massive overhaul. With that overhaul, I changed CMS from Anchor to Craft. Anchor was great, but didn't quite suit my needs. The nice thing about it is that you write your post in Markdown making code blocks quite easy. 

Craft is back to good old fashioned HTML and a WYSIWYG (Redactor) which is great in many ways but it doesn't seem to like having  <code>  tags (with a class on) inside <pre>  tag (which is how the syntax highlighter PrismJS likes it's HTML). When putting in the code, the WYSIWYG would mangle the HTML blocks.

Instead of trying to rip the editor apart, I came up with a javascript based solution (as the plugin needs JS anyway). What I created was a small bit of JS that which inserts the  <code> tags for me, with the correct classes.

Since making this change the code blocks have worked flawlessly. Allowing me to switch and re-edit with ease without worrying about the code messing up.

The below code is pure JS (doesn't require jQuery),

/**
 * PrismJS happy <pre> blocks
 */
// Check a pre tag exists
var elements = document.querySelectorAll('pre');
if(elements !== null) {
    // For each of the <pre> elements
    Array.prototype.forEach.call(elements, function(el, i){
        // Get the inner html
        var code = el.innerHTML;
        // Get the class name on the element
        var cssclass = el.className;
        // Make the inner html a <code> block with the class and code inside
        el.innerHTML = '<code class="' + cssclass + '">' + code + '</code>';
    });
}

Without the comments, that is 8 lines of (readable) code. I say readable as I'm sure it could be reduced somewhat!

The HTML I now put in Craft CMS is this:

<pre class="language-html">HTML Code here</pre>

With the JS, the resulting (colourful) code examples become:

<pre class="language-html"><code class="language-html">HTML Code here</code></pre>

Edit: In fact, while writing this I've spotted a way already and have got it down to 5 lines of (still) readable code!

var elements = document.querySelectorAll('pre');
if(elements !== null)
    Array.prototype.forEach.call(elements, function(el, i){
        el.innerHTML = '<code class="' + el.className + '">' +  el.innerHTML + '</code>';
    });
Mike Street

Written by Mike Street

Mike is a front-end developer from Brighton, UK. He spends his time writing, cycling and coding. You can find Mike on Twitter.