Adding Tags to a Gridsome Project with NetlifyCMS
Adding tags to posts in a Gridsome project has a few configuration quirks but once you are up-and-running the workflow is relatively straightforward.
This post builds on top of the previous post and has a demo here.
Prerequisites
If you don't have the @gridsome/transformer-remark
package added to your Gridsome project you will need it installed.
npm install @gridsome/transformer-remark
Adding the tag field to the config.yml
fields:
- {label: "Title", name: "title", widget: "string"}
- {label: "Body", name: "body", widget: "markdown"}
- {label: "Tags", name: "tags", widget: "list"}
The last line is what needs to be added. The list widget in the NetlifyCMS will allow us to generate a list of tags in our CMS for each post.
Adjusting gridsome.config.js
Next, we'll need to add a remark
and refs
section to our source filesystem section. This section tells Gridsome how to create the reference based on the tags field and what the route should be.
module.exports = {
siteName: "Cat Blog",
plugins: [
{
use: "@gridsome/source-filesystem",
options: {
path: "post/**/*.md",
typeName: "Post",
remark: {
plugins: []
},
refs: {
tags: {
typeName: "Tag",
route: "/tag/:id",
create: true
}
}
}
}
// Other Plugins
]
// Other configuration options
};
Create the template
For a list of items Gridsome uses templates. The tags page is a collection of posts based around a tag id therefore we'll need to use a template to query, filter and display them all.
Let's go over the various parts of the Tag.vue
template file.
Page Query
The page query is a little different than your standard query. Using the id passed in by the route and made available from Gridsome we can query for the tag. Using the belongsTo
relationship allows us to get all of the posts that have the specified tag attached.
<page-query>
query Tag ($id: String!) {
tag (id: $id) {
title
belongsTo {
edges {
node {
...on Post {
id
title
path
content
}
}
}
}
}
}
</page-query>
Script
This section is fairly straightforward. Set the title of the page to be the tag name and create a little helper computed property that will simplify the template.
<script>
export default {
metaInfo() {
return {
title: this.$route.params.id
};
},
computed: {
posts() {
return this.$page.tag.belongsTo.edges.map(e => e.node);
}
}
};
</script>
Template
We now have everything we need to render out a list of the filterd posts in our template. All that is left is to loop through the list of posts and display the glorious cat pictures that match our specified tag.
<template>
<Layout :title="this.$route.params.id">
<div class="container">
<main>
<h1>All {{ $route.params.id }} posts</h1>
<article v-for="post in posts" :key="post.id">
<h2>{{post.title}}</h2>
<div v-html="post.content"/>
</article>
</main>
</div>
</Layout>
</template>
Note: It is important when setting a v-html
on an elemnt that you use a div
and not a p
tag as it can confuse hydration when deploying to production.
Showing tags
Any place we want to show the tags we'll need to update our query to include the tags. For example, on the home page Index.vue
we now want to show a list of the tags below the title of the post.
query Posts {
posts: allPost {
edges {
node {
id
title
content
tags {
id
path
}
}
}
}
}
This query adds the tags
section to the node and gets the id and path for each tag. The id will be the text of the tag and the path will be the slugified tag name.
<div v-for="post in $page.posts.edges" :key="post.node.id">
<h2>{{post.node.title}}</h2>
<div class="badge" v-for="tag in post.node.tags" :key="tag.id">
<g-link class="badge-link" :to="tag.path">{{tag.id}}</g-link>
</div>
</div>
Looping the tags is now as easy as a v-for
loop and passing the necessary components to the g-link
component.
See the full source in the demo repository.