Code Syntax Highlighter

In this example, our goal is to extend the Code Block to provide syntax highlighting using the Highlight JS library. Aside from the specific functionality, this is an example of integrating a 3rd Party JavaScript library into a block.

View the full source on GitHub.
pluginarchitect/wp-block-code-syntax-highlighter

For brevity, the embedded code example are shortened. See the full source for  an installable version.

The Code Block

function highlight( code ){
    var highlightedCode = hljs.highlightAuto( code );
    return el( 'pre', { className: 'javascript hljs' },
        el( RawHTML, {}, highlightedCode.value )
    );
}

The Code Block with Syntax Highlighting

function highlight( code ){
    var highlightedCode = hljs.highlightAuto( code );
    return el( 'pre', { className: 'javascript hljs' },
        el( RawHTML, {}, highlightedCode.value )
    );
}

Base Elements

In this example we'll use the base PlainText block as well as the RawHTML element.

The PlainText block is a wrapper for an "auto-growing textarea" allowing for "any textual content" – which is used here to provide an un-highlighted version of the content for editing.

The RawHTML element is a wrapper for React's "dangerouslySetInnerHTML" – which is used here because the 3rd Party library generates the HTML for us. In this case we are choosing to trust the content generated by the library.

Un-styled "Focus" State

From a user experience perspective it would be beneficial to edit with syntax highlighting, however, in this example I've chosen to demonstrate the use of a "focus" state.

The edit() function of the block is passed an object of properties, which includes props.focus as a boolean value. This value can be used to conditionally return a "focus" state of the editer.

edit: function( props ) {
    return ( props.focus ) ? 'Focused' : 'Not focused';
}

For an un-styled focus state of the code block we return a PlainText element containing the content provided by the user as a value property of the element.

var code = props.attributes.code;
if( props.focus ){
    return el( PlainText, { value: code } );
}

Integrating Syntax Highlighting

For this example I have chose to implement the HighlightJS syntax highlighter which supports multiple languages and customizable themes.

The first step is to enqueue the 3rd Party library source. Scripts for the block editor are enqueued on the enqueue_block_editor_assets hook.

<?php
add_action( 'enqueue_block_editor_assets', function () {
    wp_enqueue_script(
      'kbj-code-block-highlight-js',
      '//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js'
    );
});

With the 3rd Party library enqueued, we now have access to the hljs.highlight() and hljs.highlightAuto() functions which are used to generate the syntax highlighted version of the content.

Being that this functionality is shared between the edit() and save() methods of the block, I have extracted a wrapper function.

function highlight( code ){
    var highlightedCode = hljs.highlightAuto( code );
    return el( 'pre', { className: 'javascript hljs' },
      el( RawHTML, {}, highlightedCode.value )
    );
}

HighlightJS requires a <pre> tag with the class hljs in order to apply styles. In React, classes are passed as a className property – as show in the above example. Finally, we pass the generated HTML as a RawHTML as previously mentioned.

edit: function( props ) {
    if( props.focus ) {
        return el( PlainText, { value: props.attributes.code } );
    }
    return highlight( props.attributes.code );
},
save: function( props ) {
    return highlight( props.attributes.code );
}

Next Steps

This is a basic example of introducing a 3rd Party JavaScript library into a WordPress block – which is not intended to be a fully featured product. From here we could add a setting for selecting a specific language as well as specifying a specific theme for the highlighting.