Developapa
Blog logo


Gatsby: Add comments to your Blog

February 04, 2020

This is a little tutorial on how to add comment functionality to your existing Gatsby blog. This should be a beginner tutorial, so even if you are pretty new to Gatbsy you still should be able to get this running.
Your blog should be hosted on Netlify so we can make use of their forms functionality.
The comments will be truly static and saved in your repository - no additional data base or 3rd party is required.

Sample

The form

Netlify forms allow us to setup and more importantly collect data from forms without the need of any backend code or infrastructure.

Firt we need to add a netlify attribute to our form element. Netlify will look for this attribute and automatically sets everything up.

<form
  name="comment-form"
  method="post"
  data-netlify="true"
>
    <input type="hidden" name="form-name" value="comment-form" />
    <input type="hidden" name="slug" value={this.props.pageContext.slug} />
    // Add name input
    // Add comment input
    // I also added a checkbox for gdpr consent
    // Can be omitted, but you may need to adapt other things later
    // Workaround:  just add a hidden input that is always true ;)
</form>

The two hidden input fields are important. The first one is needed for the Netlify bots to properly recognize the form name (should be the same name as on the name attribute on the form). And the second should be a unique identifier to the respective site and is important so you can match the comments later to the correct blog page. In my case I use the URL slug.

Now it’s time for a test submission. If you set up everything correctly you can navigate to the forms tab in your Netlify project and should be able to see your current submission.
If you want to have a different success message you can provide the path in the action attribute of the form (Docs)

Get form submissions in your project

Now we need to get the form submissions from Netlify into our repository. For this I created a simple script - comment-approval.js. Put this script in the top level of your project. (By default your comments will be put in the content/comments directory. If you want to change that, change the commentPath variable in the top)
You need a couple of dependencies for this script to run. Install them with:

npm install -D clear dotenv handlebars netlify prompt

Create a .env file next to the script file and add the following content

NETLIFY_TOKEN=YOUR_TOKEN
NETLIFY_SITE_ID=YOUR_SITE_ID

Replace YOUR_SITE_ID with your site id. Go to Netlify —> Your project —> Site settings and in the Site information card you should see your API ID.
Replace YOUR_TOKEN with an access token for the Netlify-API. Click your profile picture on the top right on the Netlify page and go to User settings. Go to the Applications menu and create a new access token.

Important: Make sure your .env file is in your .gitignore to prevent it from being commited into your repository

Create a comment-template.md file with the following content next to the other two files

---
name: "{{name}}"
slug: "{{slug}}"
date: "{{date}}"
---
{{comment}}

Now everything is setup and we should be able to run the script with node comment-approval.js. You will be guided through each submission and can decide to ignore it, approve it (a file in your repository will be created) or remove it (will be removed from the Netlify server). Now approve your test submission from step one

Display comments

Quick recap, we are able to submit comments and download them from Netlify and put them in our project. Now we just need to display them in our blog post page.
Open your gatsby-config.js and look for a usage of gatsby-source-filesystem. This tells Gatsby where to look for your blog articles. It probably looks something like this

{
  resolve: `gatsby-source-filesystem`,
  options: {
    path: `${__dirname}/content/blog`,
    name: `blog`,
  },
},

The name is actually quite important and we will need this later. Now add a configuration block for the comments, for example

{
  resolve: 'gatsby-source-filesystem',
  options: {
    path: `${__dirname}/content/comments`,
    name: 'comments',
  },
},

Now open your gatsby-node.js and look for a onCreateNode and add the parts that are missing of the following snippet

exports.onCreateNode = ({ node, actions, getNode }) => {
  const { createNodeField } = actions;

  if (node.internal.type === `MarkdownRemark`) {
    const slug = createFilePath({ node, getNode });
    const collection = getNode(node.parent).sourceInstanceName;
    createNodeField({
      name: `slug`,
      node,
      value: slug,
    });
    createNodeField({
      name: `collection`,
      node,
      value: collection,
    });
  }
};

You probably already have something like the slug part in place, then just add the second paragraph. We now add the previous specified name, blog and comments, to each node so later we can query this specific field with GraphQL. Now open your file were you want to show your comments, in my case this is the post-entry.js. Update the GraphQL page query and add

comments: allMarkdownRemark(
  filter: {
    fields: { collection: { eq: "comments" } }
    frontmatter: { slug: { eq: $slug } }
  }
) {
  edges {
    node {
      id
      html
      frontmatter {
        date(formatString: "MMMM DD, YYYY")
        name
      }
    }
  }
}

Let me quickly explains what happens here. The first part comments is our parameter to get the data later (and prevents collisions if you already use the identifier allMarkdownRemark).

  • With the fields filter for the collection we can now specify were to look for our comments
  • The second row filters for our page identifier
  • And the rest are just the fields we want to display

We are almost done. Now access your comments in your render method and Array.map() through them to add all comments to your template. You can also specify a message if there are no comments available.

render() {
 const comments = this.props.data.comments.edges;
 return (
   <div>
     {comments.map(({ node }) => {
       return <div key={node.id}>
         <p>Define how your comment should look like</p>
         <p>Name: {node.frontmatter.name}</p>
         <p>Date: {node.frontmatter.date}</p>
         <div dangerouslySetInnerHTML={{ __html: node.html }}/>
         </div>;
     })}
     {comments.length === 0 ? (
       <div>
         There are no comments available for this blog post yet
       </div>
     ) : null}
 )
}

Conclusion

I hope you could follow along and now have a beautiful blog with awesome comments.
I know there are billions other approaches out there to get comments into your project, I even tested 2 different approaches before coming up with my own version.
What I like about this way is having everything in my repository. I had a previous version that automatically created Pull requests in GitHub (Example), but I don’t like this version anymore, since PRs can’t be deleted - just closed.
Every form submit will theoretically be visible forever and I can’t do anything about it. There are plenty of cases were this might be bad, e.g. submissions that accidentally contain sensitive data, rude/sexual spam, etc.

Let me know if you managed to get your comments running or on what steps you stumbled. I’m happy to rework any part of this tutorial and explain it more in depth.

References

I tried to provide the example really basic, so it is easier for you to implement in your own project. However if you want to see some real life examples you can check out the links below that point to this blog here


Nicolas Gehlert

Personal Blog written by Nicolas Gehlert, software developer from Freiburg im Breisgau. Developer & Papa. Github

Add a comment

Comments

There are no comments available for this blog post yet