Skip to content
/ Michaël Hompus

As I continue migrating from WordPress to Astro, I am rebuilding key plugin features without third-party dependencies. In this post, I will show how I replaced syntax highlighting, recent post widgets, and external link management using Astro’s flexible ecosystem.

This post is a continuation of my migration journey from WordPress to Astro. If you have not read the previous posts, you might want to start with Why I Switched from WordPress to Astro, How I Moved My Blog Content and how I am Replacing WordPress Plugins with Astro: Acronyms, Meta Tags & Tag Clouds.

In this post, I cover how I replaced the next set of WordPress plugins with equivalent functionality in Astro:

  1. Enlighter
  2. Recent Post Widget Extended
  3. WP External Links

Enlighter

The Enlighter plugin provided syntax highlighting for code blocks in WordPress, allowing custom styles and line numbers.

Astro Implementation

I replaced Enlighter with Expressive Code. It is a powerful and flexible replacement for syntax highlighting in Astro.

Here’s how I set it up:

astro.config.mjs
import { defineConfig } from "astro/config";
import expressiveCode from "astro-expressive-code";
export default defineConfig({
integrations: [
expressiveCode({
plugins: [pluginLineNumbers()],
defaultProps: {
wrap: true,
showLineNumbers: false,
},
styleOverrides: {
codeFontFamily: "var(--font-monospace)",
codeFontSize: "0.78125rem",
codeLineHeight: "1.6",
uiFontSize: "0.78125rem",
lineNumbers: {
highlightForeground: "#85c7ebb3",
},
},
}),
],
});

I configured it to wrap long lines by default and disabled line numbers unless explicitly enabled. Additionally, I set the font family, size, and other styles to match the styling of my blog.

Using My Visual Studio Code Theme

I prefer the syntax highlighting theme in Visual Studio Code over the default GitHub styling.

Expressive Code allows you to define custom themes based on VS Code exports. So, I exported my theme and applied it in Expressive Code!

src/config/vscode-theme.jsonc
{
"$schema": "vscode://schemas/color-theme",
"type": "dark",
"colors": {
"actionBar.toggledBackground": "#383a49",
"activityBar.activeBorder": "#0078d4",
"activityBar.background": "#181818",
...
},
"tokenColors": []
}

Full VS Code theme available here: vscode-theme.jsonc

Because the theme file is a jsonc file. I had to load it in a specific manner in the astro.config.mjs file:

astro.config.mjs
import { defineConfig } from "astro/config";
import { readFileSync } from "fs";
import expressiveCode, { ExpressiveCodeTheme } from "astro-expressive-code";
const jsoncString = readFileSync(new URL(`./src/config/vscode-theme.jsonc`, import.meta.url), 'utf-8')
const vscodeTheme = ExpressiveCodeTheme.fromJSONString(jsoncString)
export default defineConfig({
integrations: [
expressiveCode({
...
themes: [vscodeTheme]
})
],
})

As you can already see in all the code samples in my posts, the syntax highlighting is working beautifully.

Full implementation on GitHub: astro.config.mjs.

Recent Post Widget Extended

The Recent Post Widget Extended plugin displayed recent posts dynamically.

Astro Implementation

In Astro, I created a simple loop using Astro’s Content Collection API.

src/components/Sidebar.astro
---
import { getCollection } from 'astro:content';
const unsortedPosts = await getCollection('posts')
const posts: { data: { permalink: string; title: string } }[] = sortedPosts(unsortedPosts);

Next, I render the recent posts in the sidebar while filtering out the current post (if applicable):

src/components/Sidebar.astro
<aside id="recent-posts">
<h2>Recent Posts</h2>
<div>
<nav>
<ol>
{
posts
.slice(0, 6)
.filter((p) => p.data.permalink !== Astro.url.pathname)
.slice(0, 5)
.map((post) => (
<li>
<a href={post.data.permalink} target="_self">
{post.data.title}
</a>
</li>
))
}
</ol>
</nav>
</div>
</aside>

Full implementation on GitHub: Sidebar.astro.

The External Links plugin manages external links, adding icons and SEO attributes.

Astro Implementation

I replaced this with rehype-external-links, configuring it in astro.config.mjs:

astro.config.mjs
import rehypeExternalLinks from "rehype-external-links";
export default defineConfig({
markdown: {
rehypePlugins: [
[
rehypeExternalLinks,
{
content: {},
rel: ["noopener", "noreferrer", "external"],
target: "_blank"
}
]
],
},
});

Now every link that contains an external URL will open in a new tab with the noopener, noreferrer, and external attributes.

Using CSS on a tags where the rel attribute contains external, I added an external link icon:

global.css
a[rel~="external"] span {
width: 10px;
height: 10px;
display: inline-block;
margin-left: 0.3em;
background-image: url(/icon-13.png);
}

You can see this implementation in action with various external links on this page.

If you want to exclude certain domains from being treated as external links, you can use a test function in the configuration. I used this to exclude LinkedIn links.

View the full code on GitHub: astro.config.mjs and global.css.


This was the next set of 3 plugins I replaced with Astro functionality.

In the next post, I will cover more plugins, including paging, related posts, and more.

Filed under Azure
Last update: