Skip to content
/ Michaël Hompus

Moving from WordPress to Astro meant rethinking how I implemented various features that were previously handled by plugins. In this post, I explain how I replaced key WordPress plugin functionalities in Astro, including acronyms, metadata, and tag clouds.

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:

In this post, I explain how I replaced 3 WordPress plugin functionalities in Astro.

  1. Acronyms 2
  2. Add Meta Tags
  3. Better Tag Cloud

Acronyms 2

The Acronyms 2 plugin allowed me to define a list of acronyms, and automatically generated tooltips with their meanings when they appeared in posts.

Astro Implementation

In Astro, I created a rehype plugin that processes text and wraps recognized acronyms with an <abbr> tag containing the full text of the acronym as the title attribute.

Note

rehype is an ecosystem of plugins that work with HTML as structured data, specifically ASTs.
This allows for easy manipulation, or extension, of HTML content.

The first time an abbreviation is encountered on a page, the plugin will also wrap the <abbr> tag with an <dfn> tag. This semantic tag is used to indicate the defining instance of a term.

A special case is when an acronym is used in a <code> or <pre> block. In this case, the plugin will not wrap the acronym with an <abbr> tag.

src/plugins/rehypeAbbreviate.js
if (current.tagName === 'code' || current.tagName === 'pre') {
return; // Skip this node
}

See the full code on GitHub: rehypeAbbreviate.js.

Because there is no database to store the acronyms, I defined them in a YAML file and imported them into the plugin.

src/config/acronyms.yaml
ACRONYMS:
AST: Abstract Syntax Tree
HTML: HyperText Markup Language

The YAML file is loaded in the astro.config.mjs file and passed to the rehypeAbbreviate plugin.

astro.config.mjs
import { defineConfig } from "astro/config";
import yaml from "@rollup/plugin-yaml";
import yamlParser from "yaml";
import { readFileSync } from "fs";
import rehypeAbbreviate from "./src/plugins/rehypeAbbreviate.js";
export default defineConfig({
markdown: {
rehypePlugins: [
[
rehypeAbbreviate,
{ acronyms: yamlParser.parse(readFileSync("./src/config/acronyms.yaml", "utf8")).ACRONYMS}
],
],
},
vite: {
plugins: [yaml()],
},
});

I expect that loading the acronyms from a YAML file could be improved, but for now, it works well enough.

Add Meta Tags

The Add Meta Tags plugin generated metadata for search engines and social media previews.

Astro Implementation

Most of the metadata is defined in the BaseHead.astro file, which is included in one of the layout files that pass on contextual values.

src/layouts/BaseHead.astro
<meta property="og:url" content={Astro.url}>
<meta property="og:title" content={title}>
<meta property="og:description" content={description}>

Some properties are conditionally included based on availability. For example, the article object is passed to the layout when rendering a blog post.

Sections and tags can even occur multiple times, so I use the Array map function to generate multiple <meta> tags.

src/layouts/BaseHead.astro
{article && (
<meta property="og:type" content="article" />
<meta property="article:published_time" content={article.published} />
<meta property="article:modified_time" content={article.modified} />
)}
{article && article.sections && article.sections.map((section) =>
<meta property="article:section" content={section}>
)}
{article && article.tags && article.tags.map((tag) =>
<meta property="article:tag" content={tag}>
)}

View the full code on GitHub: BaseHead.astro.

Better Tag Cloud

The Better Tag Cloud plugin displayed a tag cloud where tags were weighted based on post frequency.

Astro Implementation

I used the PHP code from the plugin as a reference and, with some help from ChatGPT, created a function that:

  1. Gets a map of tags and their posts.

    src/js/util.js
    export function getTagsWithPosts(paths) {
    const posts = sortedPosts(paths);
    const tagsMap = new Map();
    posts.forEach(post => {
    post.data.tags?.forEach(tag => {
    if (!tagsMap.has(tag)) {
    tagsMap.set(tag, []);
    }
    tagsMap.get(tag).push(post);
    });
    });
    return tagsMap;
    }
  2. Sorts the tags by post count.

  3. Get the top 50 tags.

  4. Sort the tags alphabetically.

  5. Calculate the weight of each tag based on the post count. Using 8pt as the smallest font size and 22pt as the largest font size.

    src/components/Sidebar.astro
    return tagArray
    .sort(([tagA], [tagB]) => tagA.localeCompare(tagB))
    .map(([tag, tagPosts]) => ({
    tag,
    count: tagPosts.length,
    fontSize: calculateFontSize(tagPosts.length),
    }));
  6. Render the tags in the sidebar.

    src/components/Sidebar.astro
    <aside id="tag-cloud">
    <h2>Tags</h2>
    <div>
    {
    tags.map(tagItem =>
    <a
    href={`/tag/${urlifyToken(tagItem.tag)}/`}
    title={`${tagItem.count} posts tagged with "${tagItem.tag}"`}
    rel="tag"
    style={`font-size: ${tagItem.fontSize}pt;`}>{tagItem.tag}</a>
    )
    }
    </div>
    </aside>

The full code can be found on GitHub: Sidebar.astro and util.js.


These are the first 3 plugins I replaced with Astro functionality.

In the next post, I will cover more plugins, including syntax highlighting, paging, and more.

Filed under Azure
Last update: