Transformer plugins

In previous chapter we learned how to get data from sources with source plugins.

The data fetched by this plugin could have a lot of information, but often this information is not in the right format to build our pages.

For example, if we want to build a blog and use Markdown files as our data for every blog post, gatsby-source-filesystem is useful to retrieve the list of posts (all *.md files) but we cannot use the text inside of them to create our site pages.

Transformer plugins are used for this purpose: they take raw content from source plugins and transform it into something more usable.

First of all, we need to create some files inside a new folder blogposts:

src/blogposts/ploneconf_trainings.md

---
title: "Ploneconf trainings"
date: "2018-11-05"
---

The first two days of Ploneconf are dedicated to trainings.

There are a lot of interesting trainings.


src/blogposts/ploneconf_talks.md

---
title: "Ploneconf talks"
date: "2018-11-07"
---

From 7 to 9 November 2018, there will be a lot of interesting talks about Plone and web development in general.

There will be also cool t-shirts and a party!

If we try to go back to our files-list page, we will see that 2 new files are listed.

But we still do not have the right information.

To get more information to be queried (for example the title of the “blogposts” or their text), we need to add a new plugin:

npm install --save gatsby-transformer-remark

And add it into our gatsby-config.js file in the plugins list:

module.exports = {
    siteMetadata: {
        title: 'Gatsby Default Starter',
    },
    plugins: [
        'gatsby-plugin-react-helmet',
        {
            resolve: `gatsby-source-filesystem`,
            options: {
                name: `src`,
                path: `${__dirname}/src`,
            },
        },
        'gatsby-transformer-remark',
        'gatsby-transformer-sharp',
        'gatsby-plugin-sharp',

This plugin reads all the files generated by the gatsby-source-filesystem plugin and extracts data from the items that it can handle (Markdown files for example), generating new nodes in GraphQL model with more useful metadata.

If we restart our server and look at the available queries with GraphiQL, we will find out two new ones: allMarkdownRemark and markDownRemark.

Every source or transform plugin creates a set of new queries and nodes.

A node is a data entity generated by that plugin that exposes several attributes.

A node gets its name from its type attribute.

In this case, the Remark transformer creates a list of nodes called markDownRemark.

GatsbyJS automatically generates also a GraphQL query type. This query type gets all the nodes of a certain type, filtering them by their attribute values. It uses a standard name: “all”, appended by the node’s type name. In our case, its name is allMarkdownRemark.

Exercise

We want to create a blog, so we need to edit our pages/index.js to list all “blogposts” with the following information:

  • Total number of posts
  • For each post: title, date and description

Hints: try to play a bit with the allMarkdownRemark query and see how to retrieve all required information.

Solution

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

import Layout from '../components/layout'

const IndexPage = ({ data }) => (
    <Layout>
      <h1>A blog about The conference</h1>
      <h4>{data.allMarkdownRemark.totalCount} Posts</h4>
      {data.allMarkdownRemark.edges.map(({ node }) => (
        <div key={node.id}>
          <Link to={node.fields.slug}>
            <h3>
              {node.frontmatter.title}{" "}
              <span>
                {"- "}{node.frontmatter.date}
              </span>
            </h3>
          </Link>
          <p>{node.excerpt}</p>
        </div>
      ))}
    </Layout>
  )

export const query = graphql`
  query {
    allMarkdownRemark {
      totalCount
      edges {
        node {
          id
          frontmatter {
            title
            date(formatString: "DD MMMM, YYYY")
          }
          excerpt
          fields {
            slug
          }
        }
      }
    }
  }
`

export default IndexPage