Some Tags
Part of the Astro series
One of my site to-do items for a while now has been doing something with the keywords I add to each post’s front matter. Content in Astro can be different variations of Markdown, and front matter is a YAML section with metadata about the content, such as title, description, publish date, or really whatever you want to put in there. One of the things I add there is a YAML array of keywords which are really just tags. I called them keywords, they could have been called categories, tags, topics, whatever.
Here’s the YAML front matter for my last post, which was about podcasting software:
I thought it might be nice to add the ability to view posts associated with specific tags, to add a post-filtering option in addition to the site search. That way people could see everything I associated with “mac” or “podcast”, for example. I decided to show a subset of tags on my home page and have a tags index page that listed all of them. The tags in those tag lists would link to the specific tag’s page, with a list of posts using that tag.
Thanks to others who are a lot smarter than me who’ve already done this very thing with Astro, finding excellent examples to borrow and steal from didn’t take long at all.
I did a search for “astro tags” and found that the Astro documentation site has a tutorial that covers building a tag index page as well as individual tag pages, but I wanted some better examples of pulling the tags from the posts and sorting and filtering them rather than the array of tag objects used in the documentation examples.
One of my search results was a post from Sarah Rainsberger called Creating individual tag pages in Astro via dynamic routes. I know who Sarah is – she’s the lead-documentation-guru-in-chief for the Astro documentation, and she’s an amazing organizer, explainer, and community builder.
Tags Index Page and Tag Cloud
Sarah’s post does a great job of explaining static vs. dynamic routing, and the astro getStaticPaths()
function that’s used to generate dynamic routes. First, though, she builds her src/pages/tags/index.astro
page which serves as her tags list page (which you can see in action here).
I have a slightly different approach in that I use Astro Content Collections, which were introduced after Sarah’s blog post, rather than Astro.fetchContent()
, which she uses, which was in turn deprecated in favor of Astro.glob()
in Astro 2.0. For now, just think of Content Collections as another way of grabbing all associated documents, such as posts. You can still use Astro.glob()
. Content Collections have a few benefits that glob doesn’t, but require a little extra setup.
In any event, I wound up with this for a tags index page:
Well, that’s not very exciting. I don’t do any of the cool post grabbing stuff that Sarah does here. That’s because I put all that work into an Astro component I call TagCloud. You can see that I use my TagCloud component there in my tags index page. I did this because I also wanted to show a subset of my tag cloud on my home page and on my search page. Creating an Astro component to actually display the tag cloud makes all that logic and display markup reusable.
Also note that I pass two params to my TagCloud component – showCount="true"
and displayNumber="999"
. I’ll explain those pretty soon.
HERE is where the magic happens, in TagCloud.astro
itself:
Ok, that’s kind of a big chunk of code, but a lot of it is html and styling. But there are a few important parts, namely all that JavaScript in the front matter regarding allPosts
, allTags
, processedTags
, and sortedTags
.
Basically what this does is get my posts Content Collection, get the keywords arrays from the front matter, and then create a JavaScript object of key value pairs with each tag I’ve ever used as a key, and how many times I’ve used it as its value.
If you console.log(sortedTags)
, it looks like this:
You may be wondering why Sarah’s tags index page creates its array of tags very simply with this:
And why I’m making it super complex with this:
The reason is that I’m keeping count of how many times each tag is used and I’m displaying that in my tag cloud, as shown below.
That’s the only reason why instead of just sticking with a simple array of tags, I am creating a JavaScript Object of key value pairs, with the tag name being the key and the number of times its used being the value.
I am not clever enough nor good enough with JavaScript to have written that function. All of that JavaScript in that code block above is the work of Chris Pennington, who has a really great YouTube channel called Coding in Public. One of his videos is titled Astro Blog Course #12 - Tag cloud, and it’s about exactly what you think it’s about.
My whole TagCloud.astro component aside from styling comes straight from his CategoryCloud.astro component, with one minor change.
My minor change is the addition of a prop called displayNumber
. If I give it something real, like 11, it will display 11 tags plus a “All tags… ” link to the tags index page. If I give it 999, it shows all tags. On my tags index page, I call TagCloud.astro with displayNumber="999"
, while on my site home page and my site search page, I call TagCloud.astro with displayNumber="11"
. The result is that my tags index page looks like the picture immediately above, while my home page and search page tag clouds look like the following two images.
Individual Tag Pages
The tag pages for individual tags are where dynamic routing comes in. While the tags index page is at src/pages/tags/index.astro
, the fact that the individual tag page are dynamically created is evident by the Astro page name: src/pages/tags/[tag].astro
. The brackets around the name indicate a dynamic route page, one that generates an actual page for each item in an array of objects. In our case, our objects are tags.
As the Astro documentation on dynamic routes says,
Because all routes must be determined at build time, a dynamic route must export a
getStaticPaths()
that returns an array of objects with aparams
property. Each of these objects will generate a corresponding route.
My tag.astro
page looks just like Sarah’s as far as my getStaticPaths()
function, because hers is perfect. Like I said, people much smarter than me have already solved this problem and documented it for others. I’m glad too, because JavaScript isn’t really something I spend hours improving my skills at. I tend to learn enough to do what I need to and then move on. Unfortunately this means that correctly expressing things in JavaScript like mapping and filtering is sometimes a struggle for me.
Here’s [tag].astro
. It’s another long code block but here’s the full code dump anyway.
All of that in [tag].astro
equates to the following individual tag view.
I don’t know if you’re tired of tags yet, but I’m getting there. I do like how this turned out though. I think it looks pretty good considering my horrific lack of design skills, and I like how I can implement the partial cloud on the home page and the search page, and the full tag cloud on the tags index page, all from the same TagCloud.astro
component.
404, Scott Not Found
Oh, I also added the tag cloud along with a search field on my 404 page too.
And now I’m going to sleep, because it’s after 2 AM and I really need to be 404 myself right now.