How to add support for multiple authors per page on GatsbyJS

Table of contents

While working on a Gatsby site, we have a requirement to provide support for multiple authors/contributors per page. We got this working by following the excellent Gatsby documentation Mapping node types.

In this post, I will be describing the steps we followed.

Adding gatsby-transformer-yaml dependency using npm

Run this on your Gatsby project within the root directory.


npm install --save gatsby-transformer-yaml

Configuring the plugins

For this example, we are going to have a contributor.yaml file located at src/data.


- id: jane_doe
  name: Jane Doe
  twitter: jane_doe github: //github.com/jane_doe
  drupal: //www.drupal.org/u/jane_doe
  wordpress: //profiles.wordpress.org/jane_doe
  linkedin: //www.linkedin.com/in/jane_doe
  bio: CEO
- id: john_doe
  name: John Doe
  twitter: john_doe
  linkedin: //www.linkedin.com/in/john_doe
  github: //github.com/john_doe
  bio: Technical Manager, Training and Certification

To make sure Gatsby can read this file, we need to have the gatsby-source-filesystem installed and configured to point to a path where our YAML files are.


plugins:
  [ { resolve: `gatsby-source-filesystem`,
      options: { path: `${__dirname}/src/data`, name: `data`, },
    },
    `gatsby-transformer-yaml`,
    ]

Adding a map between the author field in frontmatter to the id in the contributor.yaml objects by adding to your gatsby-config.js:


mapping:
  { "Mdx.frontmatter.author": "ContributorYaml", },

Fetching the data

After implementing this, we can fetch get all the linked authors per page using this GraphQL query.


export const pageQuery = graphql` query DocBySlug($slug: String!) { mdx(fields: { slug: { eq: $slug } }) { id code { body } fields { slug } frontmatter { title description getfeedbackform contributors { id name twitter bio avatar url } featuredcontributor } fileAbsolutePath } } `

As you can see on this query, the property contributors within frontmatter contain each one the properties of the contributor relation even when is saved as an array of string values on the markdown file.


contributors:
  ['contributor-id']

Showing the contributor data

We created the Contributors component to render the data on the page template. javascript this is the content of that component.


import React from 'react';
import { Link } from 'gatsby';

const Contributors = ({ contributors }) => {
    if (contributors == null || contributors.length < 1) {
        return null;
        }
    return (
        <p><em>
        Contributors:{' '} {
            contributors.map((contributor, i, arr) => {
                let lastCharacter = '.';
                if (arr.length - 1 !== i) {
                    lastCharacter = ', ';
                    }
                return ( {contributor.name} {lastCharacter} );
                })
            }
        </em></p>); 
    };

export default Contributors;

Display all the posts by a contributor

Create a page template at src/templates/contributor.js and add the following GraphQL query to pull all of the posts by contributor/author. Theme as desired.


export const pageQuery = graphql` query ContributorById($id: String!) { contributorYaml(id: { eq: $id }) { id name avatar url github drupal wordpress twitter linkedin } allDocs: allMdx( filter: { frontmatter: { contributors: { elemMatch: { id: { eq: $id } } } } } ) { edges { node { id frontmatter { title } fields { slug } } } } }

In those queries, we are filtering the data using the id context variable. Filtering the contributorYaml query by the contributor equal to the id


contributorYaml(id: { eq: $id })

Filtering allDocs when the contributors frontmatter field matches and contains id in one of then values.


allDocs: allMdx( filter: { frontmatter: { contributors: { elemMatch: { id: { eq: $id } } } } } )

Add a GraphQL query on create-node.js to pull all of the contributors


allContributorYaml { edges { node { id } } }

Create the contributor pages and passing the contributor id as a context variable.


const contributors = result.data.allContributorYaml.edges

contributors.forEach(contributor => {
    createPage({
        path: `contributors/${contributor.node.id}`,
        component: path.resolve(`./src/templates/contributor.js`),
        context: { id: contributor.node.id, },
        })
    })

Are you interested in knowing more about GatsbyJS?

This series does not end here, so we invite you to visit our site frequently as we continue. We will be sharing some nice tips & tricks that we have learned during the development of this project.

We will be sharing with you:

  • How to load templates based on your front-matter field.
  • How to create page navigation based on directory structure.
  • How to use the parent directory as the base.
  • Finally, how to show all of the children files as clickable links to separate pages.

So stay tuned and keep on learning with us. If you want to learn more about what we do and how we may help your business, don’t think about it twice and reach out to us!