Building this site #2: Enabling tags

First of all, I'm happy to say my personal domain now points to this site, making the move from WordPress complete. I'd been mindlessly putting off enabling tags but it turned it out to be very easy. If you click on any of the tags in this post, it should take you to a new page at /tags/[slug] with all the relevant posts listed. To make this happen, I first created a new function at /helpers/tags to deal with extracting unique tags from a given list of posts:

export default function getTags(posts) {
  const tags = [];
  for (let i = 0; i < posts.length; i++) {
    posts[i].tags.forEach((tag) => {
      if (!tags.includes(tag)) tags.push(tag);
    });
  }

  return tags.sort();
}

Then I created a new page at pages/tags/[slug].js, much like our other [slug].js page for individual posts. The logic is very similar, except in getStaticPaths we take the extra step of retrieving tags from all our posts to use them as paths; each tag is routed dynamically to its own page. Then in getStaticProps, we fetch all posts which carry one given tag, passing them into the TagPage component, which then displays it.

export default function TagPage(props) {
  // Do whatever with props
}

export async function getStaticProps(context) {
  const tag = context.params.slug;
  const posts = getPostsMetadata()
    .filter((post) => post.tags.includes(tag))
    .reverse();
  return {
    props: { tag, posts }
  }
}

export async function getStaticPaths(context) {
  const posts = getPostsMetadata();
  const tags = getTags(posts);
  return {
    paths: tags.map((tag) => {
      return {
        params: { slug: tag }
      }
    }),
    fallback: false
  }
}

I also created a reusable TagGroup component, which creates a group of clickable tags by wrapping each of them in a button (in this case, a React-Bootstrap Button). The component is used by both the blog page, which displays all tags that appear in all posts, and every individual blog post page, which displays only the tags specific to a post. The component simply takes a list of tags and handles the rest.

import { Button } from 'react-bootstrap';

export default function TagGroup({ tags }) {
  const tagGroup = tags.map((tag) => {
    return (
      <Button
        href={`/tags/${tag}`}
        size="sm"
        variant="light"
        className="mr-1 mb-1"
      >
        <strong>{tag.toUpperCase()}</strong>
      </Button>
    );
  });

  return(
    <div>{tagGroup}</div>
  );
}

From here, after about 20 minutes of work, my site has a new feature that puts it much closer to most respectable websites. Another thing I'd like to implement in the future is broader groupings of posts, particularly for posts that are part of a series—similar to WordPress's categories. Something for another day.