Syntax Highlighting in SilverStripe

I just realized that I never committed my syntax highlighting setup in git or documented it in any way. The former is now fixed, and this post resolves the latter.

Download PrismJS for whatever languages you want to highlight.

SilverStripe uses TinyMCE, so we start by enabling TinyMCE's codesample plugin. In app/_config.php, add the following:

use SilverStripe\Forms\HTMLEditor\HtmlEditorConfig;

HtmlEditorConfig::get('cms')->enablePlugins('codesample');
HtmlEditorConfig::get('cms')->addButtonsToLine(1, 'codesample');

/* Use whatever languages you got from PrismJS here. */
HtmlEditorConfig::get('cms')->setOption(
    'codesample_languages',
    array(
        array('text' => 'Bash', 'value' => 'bash'),
        array('text' => 'C', 'value' => 'c'),
        array('text' => 'D', 'value' => 'd'),
        array('text' => 'Pug/Diet', 'value' => 'pug')
    )
);

In the array, you can make the "text" whatever you want TinyMCE to display; "value" needs to match the PrismJS language identifier. addButtonsToLine(1, ...) adds the button to the end of the first line (unless you've added other plugins, it will be right after the "Increase Indent" button).

By default, SilverStripe doesn't let you insert <code> tags; fix this with (still in app/_config.php):

/* Add code tags; the rest is to preserve the defaults. */
HtmlEditorConfig::get('cms')->setOption(
    'extended_valid_elements',
    'img[class|src|alt|title|hspace|vspace|width|height' .
        '|align|onmouseover|onmouseout|name|usemap],' .
    'iframe[src|name|width|height|title|align|' .
        'allowfullscreen|frameborder|marginwidth|marginheight|scrolling],' .
    'param[name|value],' .
    'area[shape|coords|href|target|alt],' .
    'code'
);

Note that if you use some of the PrismJS plugins, you may need to add more here (e.g., 'pre[data-line]' for line highlighting).

Upload the PrismJS files into your static directory; e.g., public/js/prism.js and public/style/prism.css. If you like to keep everything in your app directory, you can do so and use composer to push it into the public directory.

Now modify app/PageController.php to inject the Prism files:

namespace {

    use SilverStripe\CMS\Controllers\ContentController;
    use SilverStripe\View\Requirements;

    class PageController extends ContentController
    {
        private static $allowed_actions = [];

        protected function init()
        {
            parent::init();
            Requirements::css('style/prism.css');
            Requirements::javascript('js/prism.js');
        }
    }
}

I didn't have to flush my cache, but that's no guarantee that you won't: yoursite.tld/?flush=1

Now you'll have a button to open a code editor when editing pages:

Insert code button

You have to manage inline code (auto like = "this";) via the view source button, though.