Server-Side Rendering of Embedded Markdown Code Snippets in WordPress


Because I'm a grumpy old man, I don't use Gutenberg or Block themes on my WordPress. Instead, I write everything in Markdown.

When I write code snippets in Markdown, they look like this:

```php
$a = 1;
echo $a;
if ($a < 5) {
   // Do Something
   return thing( $a, true );
}
```

But I want to render that with code highlighting. I was using the Prismatic Plugin. It is excellent and very customisable. But it uses JavaScript to do the code highlighting. I want to respect my readers' time and battery life; so I'm trying to reduce my dependency on Client-Side rendering.

I've switched to a modified version of WP-GeSHi-Highlight. That turns the above Markdown into:

$a = 1;
echo $a;
if ($a < 5) {
   // Do Something
   return thing( $a, true );
}

Necessary Changes

When the JetPack Markdown pre-processor encounters a code block, it changes:

```php

into

<pre><code class="language-php">

This means the WP-GeSHi-Highlight detection needs to be changed.

Old version:

return preg_replace_callback(
    "/\s*<pre(?:lang=[\"']([\w-]+)[\"']|line=[\"'](\d*)[\"']"
   ."|escaped=[\"'](true|false)?[\"']|cssfile=[\"']([\S]+)[\"']|\s)+>".
    "(.*)<\/pre>\s*/siU",
   "wp_geshi_store_and_substitute",
   $s
);

New version:

return preg_replace_callback(
    "/\s*<code(?:class=[\"']language\-([\w-]+)[\"']|line=[\"'](\d*)[\"']"
   ."|escaped=[\"'](true|false)?[\"']|cssfile=[\"']([\S]+)[\"']|\s)+>".
    "(.*)<\/code>\s*/siU",
   "wp_geshi_store_and_substitute",
   $s
);

One of those matches looks for escaped= which can be true or false. I always want this to be true so, later in the code, I change a variable from:

$escaped = trim($match[3]);

To:

$escaped = true;

Style Changes

By default, everything looks pretty good - but there are a few changes I found necessary to make.

Firstly, there was something weird going on with the line-heights of my style, so I added this to my site's CSS:

/* GeSHI Highlighter Fixes */
pre:has(> .wp-geshi-highlight-wrap5) {
    line-height: 0;
    padding: 0;
    background: none;
    filter: invert(1);
}

The invert gives it a dark mode.

Secondly, in order to make any changes to the default styles of the highlighter, you need to add the bundled wp-geshi-highlight.css file into your style directory. The plugin will use that if it exists - so you can change font size and padding to be the same as your main theme.

Limitations

There are a few limitations with this approach.

No line-numbers. The plugin looks for something like line="13", but there's no way to add that in Markdown.

GeSHi hasn't received style updates on some languages for quite some time. It hasn't received any significant update since 2019. Which means bugs and security issues are likely.

Language definitions are quite strict. You can use javascript but not json.

The plugin doesn't have any options - nor an easy way to override its settings. So I've monkeypatched everything above. If the plugin updates, I'll need to change my code.

Demos

A few demos - just so you can see what it looks like.

Python

#!/usr/bin/env python
from datetime import datetime, timedelta
from mastodon import Mastodon
from bs4 import BeautifulSoup

import config

#  Set up access
mastodon = Mastodon( api_base_url=config.instance, access_token=config.access_token )

#  Get user's info
me = mastodon.me()
my_id = me["id"]
year_joined = me["created_at"].year

Bash

if [ "$(basename $2)" = "Image.gz" ] || [ "$(basename $2)" = "vmlinuz.efi" ]
then
# Compressed install
  echo "Installing compressed kernel"
  base=vmlinuz
else
# Normal install
  echo "Installing normal kernel"
  base=vmlinux
fi

if [ -f $4/$base-$1 ]; then
  mv $4/$base-$1 $4/$base-$1.old
fi

Rust

// This is the main function.
fn main() {
    // Print text to the console.
    println!("Hello World!");
}

JavaScript

if (hour < 18) {
  greeting = "Good day";
  alert( greeting );
}

Share this post on…

3 thoughts on “Server-Side Rendering of Embedded Markdown Code Snippets in WordPress”

  1. says:

    It seems to include an additional <pre> <pre> element with a few lines of whitespace, when rendering it in the RSS feed.

    In fact, it puts the div inside the pre, which is not allowed, and thus some user agents believe there is a pre with a few lines of whitespace, a forgotten close-pre tag, and then it starts the div. In other words, it doesn't look "right" when viewing on some browsers or RSS readers. (In my case, Inoreader.)

    Reply

What links here from around this blog?

What are your reckons?

All comments are moderated and may not be published immediately. Your email address will not be published.Allowed HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <p> <pre> <br> <img src="" alt="" title="" srcset="">