Software Coding in WordPress Blog Posts Deserves Better: Syntax Highlighting, Live Links to GitHub, and Mermaid Diagrams
Good code in a WordPress post needs syntax highlighting for readability, live links or embeds that pull snippets from GitHub so the repository stays the source of truth, and Mermaid diagrams written as text instead of images. WordPress supports these through plugins and blocks, though few tools combine all three well today.
Most technical blogs treat code as an afterthought. They paste a block of monospaced text into a post, perhaps add a screenshot of an IDE, and leave the reader to guess which version of the repository it came from, whether it still compiles and how it fits into the wider system. Live embeds look like the cure, but they swap one problem for another: the code changes underneath the explanation, and nobody is told.
This post argues for a different model. A post should preserve the exact code it explains, record where that code came from, and change only when the author decides it should. It covers what good code markup looks like, how to tie a snippet to a specific version of a repository, why diagrams should be kept as text, and whether anything in the WordPress ecosystem supports all of this today.
The thesis is simple. A trustworthy technical article preserves the code it explains and makes updates deliberate. Syntax highlighting and diagrams support that goal, but the publication and revision model is what makes the difference.
1. What good code markup actually means
Good code markup starts from the assumption that a reader will copy what you show them and run it. So every block should:
- declare its language explicitly
- use real syntax highlighting rather than a theme’s default grey box
- preserve indentation exactly
- offer a copy button that copies the code and nothing else
- keep line numbers out of the clipboard
Screenshots of code fail almost every one of these tests. They cannot be copied or selected, screen readers cannot read them, and they silently go stale the moment the underlying file changes. OCR can recover some text from an image, but that makes a screenshot a poor substitute for accessible, selectable source text, not an equivalent.
The second requirement is that highlighting should, where possible, happen on the server when the post is saved or rendered rather than in the reader’s browser. A page that ships a large JavaScript highlighter to colour twenty lines of Python pays a performance cost on every view. Server rendered markup also keeps the code intact in RSS readers, email newsletters and AI summarisers that never execute your scripts. It does not guarantee how the code looks there: colours and styling still depend on the receiving application, and many feed readers and email clients strip or override them. What it guarantees is that the code itself arrives without needing JavaScript.
The third requirement is restraint. A snippet should show the smallest piece of code that makes the point. Line highlighting should draw the eye to the two or three lines that matter, and a link should let the curious reader see the full file in context.
import random
def backoff(attempt: int, base: float = 0.1, cap: float = 10.0) -> float:
# Full jitter: spread retries so clients do not synchronise
return random.uniform(0, min(cap, base * (2 ** attempt)))That link is where most posts fall down. It is usually missing, or it points at a branch that has moved on since the post was written.
2. Linking code in a post back to the GitHub repository
The repository should be the source of truth for any code that appears in a post, and the post should say exactly which version it is showing. GitHub makes this straightforward. Selecting a range of lines in a file gives a URL ending in a fragment such as #L15-L29. Pressing y on a file page rewrites the URL from a branch name to the full commit SHA, so the link permanently refers to those exact lines at that exact commit. When you post a permalink to a line range in an issue or pull request, GitHub renders it as an embedded code snippet, which is a good model for what a blog should do.
Traceable and fresh are different properties
Before comparing approaches, it helps to separate two properties that are often blurred together:
- Traceable means the reader sees exactly the code the author explained, and can follow it back to a specific commit.
- Fresh means the example still reflects the current state of the project.
A snippet is there to illustrate a point, not to stand in for a complete project. The link back to the repository is where the reader goes for the full context.
Traceability and freshness pull in different directions. A pinned example stays traceable forever but can quietly become outdated. A branch embed stays current, but the moment the code changes, the prose around it may become wrong. Neither is enough on its own. A good design keeps the published version intact, detects when it may have become stale, and lets the author decide what to do about it.
Three ways to bring code into a post
There are three reasonable approaches, and each makes a different trade.
- Paste and link. Paste the snippet into a highlighted code block and add a caption linking to the pinned permalink. This is fast, renders on the server and is honest about its age. It is traceable but has no freshness signal at all. Nobody will know when it goes out of date.
- Embed live. Embed the file from GitHub at view time using a script. Pointed at a branch, this is always current, but it fails in two ways. Lines added above your range make the embed show the wrong code with no warning. Even when the range stays correct, the code can change underneath an explanation that no longer matches it.
- Fetch from a pinned commit and save a snapshot. This is the one I would argue for wherever accuracy matters. At publish time, fetch the snippet from a pinned commit and save it as part of the article revision, so the published post stays readable even if GitHub is unavailable or the repository disappears. Show a small footer naming the repository, file path and short SHA, linking to the same lines on GitHub. Then tell the author, not the reader, when the selected code has changed upstream, so they can review the code and the prose together before updating.
Named regions help, but do not finish the job
Line drift is the reason live embeds are less useful than they first appear. The more robust fix is to anchor snippets to named regions in the source rather than to line numbers, using comment markers such as // region: retry-policy and // endregion. The post then asks for a named block of code, and keeps working as the file around it changes. Documentation tools have done this for years, and the idea has been raised against at least one of the popular GitHub embed services, but it is still rare in blogging tools.
Named regions solve line movement. They do not stop the behaviour inside the region from changing. So the staleness check should compare the content of the selected snippet at the pinned commit with the same region on the default branch. Warning whenever the repository receives any commit would bury the author in noise about unrelated changes and teach them to ignore the warning.
The check is a prompt to look again, not a guarantee. Code outside the region can still change what it does, which is one more reason the footer links to the repository.
3. Diagrams as code with Mermaid
The argument that applies to code applies equally to architecture diagrams. A diagram exported as a PNG can still be reviewed in a pull request and compared visually, but the comparison only shows that pixels moved. Text gives a meaningful diff of what changed and can be edited without finding the original drawing file, which in practice is often lost. Mermaid describes flowcharts, sequence diagrams, state machines, entity relationships and Gantt charts as plain text in a fenced code block. GitHub renders it natively, and it can live in the same repository as the code it describes, so the diagram in the post and the diagram in the README can be the same file.
sequenceDiagram
accTitle: Publishing a pinned code snippet
accDescr: The author commits code and diagram source to GitHub, then publishes a post referencing a file, region and commit. WordPress fetches the snippet once at publish time and saves it with the article revision. Readers are served the saved snapshot and never wait on GitHub.
participant Author
participant Repo as GitHub repo
participant Blog as WordPress
participant Reader
Author->>Repo: commit code and diagram source
Author->>Blog: publish post referencing file, region and SHA
Blog->>Repo: fetch snippet at publish time
Blog-->>Blog: save source, SHA, path and range with the revision
Reader->>Blog: view post
Blog-->>Reader: highlighted code, diagram, link to exact linesKeep the source, choose where to render it
The portable pattern, which the F# documentation tooling describes well, is to keep the diagram as an ordinary fenced block tagged mermaid. Viewers with Mermaid support, GitHub among them, will render it. Other Markdown viewers will show the source text, which at least stays readable. GitHub also advises checking which Mermaid version it supports, because syntax added in newer releases may not render there yet.
There is a tension here with section 1. I argued that code should be rendered before readers arrive, and Mermaid is usually rendered in the reader’s browser, with all the same costs: a large script, a blank space until it loads, and nothing at all in feeds and email. Browser rendering is accepted mainly because it is easy. It needs no build step and no rendering infrastructure on the server.
Where your hosting allows it, pre-rendering is the better option. Mermaid’s official CLI generates SVG, PNG and PDF from the same source. That lets you serve SVG on the website, where it stays sharp and keeps its text, and a PNG fallback to email clients that will not display SVG. The cost is extra infrastructure: the CLI runs a headless browser, which not every WordPress host will let you run.
The principle that matters is not “never use images”. It is to keep the diagram’s source as versioned text and generate whatever image you display from it. Images are a perfectly good output format. The problem is losing the editable source.
Accessibility, theming and loading
A properly done diagram also needs:
- A text explanation. Write a short paragraph saying what the diagram shows, not just a caption naming it.
- Mermaid’s
accTitleandaccDescrmetadata. Mermaid turns these into accessible title and description attributes on the generated SVG. - Selective loading. Load the Mermaid library only on pages that actually contain a diagram.
- Dark mode. Respect the reader’s preference rather than drawing a bright white rectangle in the middle of a dark page.
4. Does anyone support this in WordPress?
Every individual piece exists, but I could not find a single, actively maintained plugin that handles all three together in the block editor. Several of the pieces that do exist are showing their age, and one should no longer be used at all.
Syntax highlighting
Here the ecosystem is healthy:
- Code Block Pro uses the same rendering engine as VS Code, supports line highlighting and a copy button, and is tested against WordPress 7.0. Its themes are set per block rather than site wide.
- Syntax-highlighting Code Block extends the core Code block with server side highlighting and loads no external scripts, which suits the performance argument above.
- Enlighter, Prismatic and Highlighting Code Block are all credible alternatives, depending on whether you favour the classic or block editor.
Linking to GitHub
Support thins out sharply here. It helps to assess three capabilities separately, because they are often conflated:
- Fetch at publication: the code is captured once, when the author publishes.
- Commit pinning: the snippet is tied to a specific SHA.
- Caching: repeated views avoid repeated fetches.
| Tool | Fetch at publication | Commit pinning | Caching |
|---|---|---|---|
| GetGit | Not documented | Not documented | Yes, advertised |
| WP Github Gist | No, uses gist-it | Not documented | Not documented |
| emgithub | No, in browser | Yes, via permalink | Browser only |
None of the three supports named regions. For emgithub it has been requested in an open issue.
GetGit offers a shortcode that pulls a file from a public repository with start and end lines and basic highlighting, and it explicitly advertises content caching. Caching alone does not make it a publication workflow, though. A cache is a performance measure that can expire or be cleared. It is not a record of what the article showed when it was published. GetGit’s directory listing also warns that it has not been tested with the last three major WordPress releases.
WP Github Gist supports line ranges too, but relies on the external gist-it service to fetch files, so it is only as reliable as that service.
emgithub, outside WordPress, embeds a file or a sliced line range from a permalink via a script or iframe, fetching and highlighting in the reader’s browser. Its own documentation suggests self hosting a fork in case the public service is compromised or changes. That tells you something about the trust model of loading third party script into your posts.
I did not find any of these combining fetching at publication, commit pinning, a saved snapshot and named regions.
Mermaid
Mermaid support is similarly fragmented.
- WP Mermaid was the best known option, but it is no longer a practical choice. Its WordPress.org listing states that the plugin was closed on 30 September 2024 because of a security issue and is not available for download. Sites still running it should remove it.
- CanaryBlue Diagrams for Mermaid offers live preview in the editor without calling an external rendering service. It is promising but very young.
- PlusMagi Blocks adds syntax error detection. It is also very young.
- WP Githuber MD comes closest to an all in one answer, combining a Markdown editor with Prism highlighting and Mermaid. It is a heavy price for an established site, though. It replaces the editing model entirely, stores Markdown in a separate column, recommends adopting it only on a new blog, and asks you to disable other Markdown plugins.
5. What the complete solution would look like
What this site does today
This site runs my own plugin, CloudScale Cyber DevTools, which provides the syntax highlighting and Mermaid rendering you see in this post. It does not yet implement the GitHub snapshot workflow described in section 2. That gap is why I went looking for an existing plugin, and the requirements below are what I would want from one, or what I would add to my own.
Requirements
Section 2 sets out why the snapshot model is right. These are the implementation details that make it work.
What the revision stores. An author pastes a GitHub permalink, or a repository, file path and named region, into a single block. At publish time the plugin saves, as part of the article revision:
- the fetched source text
- the full commit SHA
- the file path
- the resolved line range
The highlighted HTML is a derivative. It can be regenerated from the saved source whenever the theme or highlighter changes, and it should not be treated as the record.
Failure handling. If a later fetch fails, or the repository is renamed, made private or deleted, the plugin keeps serving the last successfully published content and shows the author an error in the editor.
Change review. When the selected region’s content differs from the pinned version, the editor shows the published code, the new code and the surrounding prose side by side. The author either updates the pin and edits the explanation together, or deliberately keeps the old version.
Diagrams and Markdown. The plugin would:
- render fenced Mermaid blocks with a current version of the library
- prefer pre-rendered SVG, with a PNG fallback for email, where the host can run the CLI, and fall back to browser rendering, loaded only where needed, where it cannot
- theme diagrams for light and dark mode
- require a text explanation and support
accTitleandaccDescr - accept Markdown pasted from a README without forcing the whole site onto a Markdown editor
Security. Pulling content from elsewhere into a published page needs a few firm rules:
- Imported code is escaped and displayed, never executed or interpreted as HTML.
- Remote fetching is limited to approved GitHub endpoints, and the restriction is checked again after every redirect, not just against the initial URL, so a block cannot be used to make the server request arbitrary addresses.
- Access tokens for private repositories stay in server side configuration and never appear in saved revisions, rendered markup or error messages.
- Code fetched from a private repository is not published until the author explicitly acknowledges that it will become public. Keeping the token secret is not enough if the code it fetched is confidential.
- Mermaid defaults to its
strictsecurity level, which encodes HTML in labels and disables click interactions.
Why it matters
That combination changes the relationship between a blog and the code it describes. Instead of a frozen copy that decays from the day it is published, or a live embed that changes without the author knowing, the post becomes a preserved, traceable view of a specific version of a real repository. Updates happen because the author chose to make them, with diagrams versioned alongside the code they explain. That is the standard technical writing on WordPress should be held to.
References
- Code Block Pro: https://wordpress.org/plugins/code-block-pro/
- Syntax-highlighting Code Block and other highlighters, Speckyboy round up: https://speckyboy.com/free-wordpress-plugin-display-edit-code/
- GetGit: https://wordpress.org/plugins/getgit/
- WP Github Gist: https://github.com/sudar/wp-github-gist
- emgithub: https://github.com/yusanshi/emgithub
- emgithub issue on marker based embedding: https://github.com/yusanshi/emgithub/issues/27
- WP Mermaid (closed listing): https://wordpress.org/plugins/wp-mermaid/
- CanaryBlue Diagrams for Mermaid: https://wordpress.org/plugins/canaryblue-diagrams-for-mermaid/
- WP Githuber MD: https://github.com/terrylinooo/githuber-md
- FSharp.Formatting Mermaid pattern: https://fsprojects.github.io/FSharp.Formatting/mermaid.html
- GitHub, getting permanent links to files: https://docs.github.com/en/repositories/working-with-files/using-files/getting-permanent-links-to-files
- GitHub, creating diagrams (Mermaid support and version): https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-diagrams
- Mermaid accessibility options (accTitle and accDescr): https://mermaid.js.org/config/accessibility.html
- Mermaid security level configuration: https://mermaid.js.org/config/usage.html#securitylevel
- Mermaid CLI: https://github.com/mermaid-js/mermaid-cli