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:
PHP$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:
PHPreturn 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:
PHPreturn 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:
PHP$escaped = trim($match[3]);
To:
PHP$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:
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
Python 3#!/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
BASHif [ "$(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
RUST// This is the main function.
fn main() {
// Print text to the console.
println!("Hello World!");
}
JavaScript
JAVASCRIPTif (hour < 18) {
greeting = "Good day";
alert( greeting );
}
Aslak Raanes says:
@blog For those who use blocks, the plugins with the name «Syntax-highlighting Code Block (with Server-side Rendering)» by a Weston Ruter https://wordpress.org/plugins/syntax-highlighting-code-block/ which uses https://github.com/scrivo/highlight.php (a hightligt.js port) might be an alternative @Edent
Ernie Smith said on writing.exchange:
@Edent I do something similar with Craft. Everything in Markdown.
I need to have a code-snippet solution. I’ve only run into the issue once but it caused some headaches for me when trying to publish my email.
Denilson 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 thepre
, which is not allowed, and thus some user agents believe there is apre
with a few lines of whitespace, a forgotten close-pre tag, and then it starts thediv
. In other words, it doesn't look "right" when viewing on some browsers or RSS readers. (In my case, Inoreader.)More comments on Mastodon.