GCY and GCW (Global Citizen Year + Gatsby, Contentful, and Wordpress)

by Jeff Williams and Braden Witherwax

The Gatsby-Wordpress-Contentful Combo

Just about any website built these days involves numerous integral parts: javascript frameworks, 3rd party apis, a photo of your dog eating a popsicle, you name it…

So when the non-profit Global Citizen Year ( www.globalcitizenyear.org ) approached us about working on their new Gatsby (v1) site and their desire to pull roughly 5,000 blog posts, news articles and press releases from Wordpress, into a Contentful managed Gatsby site, we knew what would ensue was going to be something very unique and special.

Pulling the data

Between the Contentful and Wordpress api calls, there was a ton of data to pull. As every superhero knows, with great (amounts of) data comes great… headache.

Initially we ran into memory issues, with hang-ups that appeared to error out even when launching into our development cycle.

Thanks to the wonderful folks who came before us, we were able to increase the memory cap with a node ‘max-size’ command.

node --max-old-space-size=1200000 ./node_modules/.bin/gatsby develop

Even after the ‘max-size’ fix, Gatsby builds were still taking way too long, and we knew we couldn’t develop in that kind of environment (or at least, we didn’t have the patience too!).

We didn’t need all the data provided by Wordpress, but our attempts at the ‘excludedRoutes’ option in the gatsby-source-wordpress plugin were not working. Our solution — reduce the amount of data returned from Wordpress.

add_filter( 'rest_endpoints', function( $endpoints ) {
if (isset( $endpoints['/wp/v2/users'])) {
unset( $endpoints['/wp/v2/users'] );
}
if (isset( $endpoints['/wp/v2/users/(?P<id>[\d]+)']) ) {
unset( $endpoints['/wp/v2/users/(?P<id>[\d]+)'] );
}
if (isset( $endpoints['/wp/v2/media'])) {
unset( $endpoints['/wp/v2/media'] );
}
if (isset( $endpoints['/wp/v2/media/(?P<id>[\d]+)'])'])) {
unset( $endpoints['/wp/v2/media/(?P<id>[\d]+)'])'] );
}
})

This greatly decreased build times and allowed us to work in a much more streamlined manner. We did lose some of the benefit of pulling the images in and using tools such as gastby-image-sharp, however we were unable to find a work around with the existing version.*

*Changes to the handling of such large amounts of data is said to have changed with the release of Gatsby v2.0 and we’re excited to explore it more.

Gatsby Templates

Setting up template pages in Gatsby is fairly straightforward. In gatsby-node.js, we pulled the data (from WP or Contentful), then used the ‘createPage’ function to create a page for each ‘edge’ of data.

allWordpressWpPress {
edges {
node {
slug
title
date(formatString: "DD MMMM, YYYY")
content
excerpt
featured_media
}
}
}
.
.
.
if(result.data && result.data.allWordpressWpPress) {
result.data.allWordpressWpPress.edges.forEach( edge => {
createPage({
path: `/press/${edge.node.slug}/`,
component: slash(pressTemplate),
context: {
id: edge.node.id,
slug: edge.node.slug
},
})
})
}

Wordpress & Contentful Sync

Global Citizen Year had opted to use Contentful to handle all their data except for blogs due to the volume of previous posts.. This meant needing to sync Contentful controlled author data with its associated Wordpress posts.

The solve: Inject author info data into the Wordpress blog feed through a custom filter. Once the data was pulled into Gatsby, we could use the author slug to match up with Contentful’s author data, and render the appropriate post.

Author name from Wordpress was passed via context.

if(result.data && result.data.allWordpressWpUpdates) {
result.data.allWordpressWpUpdates.edges.map( edge => {
createPage({
path: `/updates/${edge.node.slug}/`,
component: slash(singlePost),
context: {
id: edge.node.id
slug: edge.node.slug,
data: edge.node,
name: `${edge.node.author_info.first_name} ${edge.node.author_info.last_name}`
}
})
})
}

Inside a single post component the name from context was then used to filter the authors data provided by Contentful.

export const query = graphql`
query FellowsUpdateQuery($name: String!) {
allContentfulFellowsProfile(filter: {name: {eq: $name}}) {
edges {
node {
id
name
bio {
id
bio
}
}
}
}
}`

This is going to be HUGE…

We had built several Gatsby sites in the past, but none this big. Not even close. All in all, the Global Citizen Year site is over 5000 pages, all of which needed to be created during the Gatsby build process. The full production build process, in the end, took around 30 minutes.

Gatsby pulling data from Wordpress during a build.

Pros

  • Blazing fast speeds
  • Optimization
  • Easy to manipulate data

Cons

  • Slow build and restart times — Due to the amount of data, it required us to either turn off the sections of the site we weren’t currently working on, or sit through long rebuilds whenever data needed to change.

Conclusion

There are some solutions to problems that we would have liked to avoid, such as relying on pulling images from Wordpress. But overall we are extremely excited about this project and the future of static sites.

As build and deploy speeds continue to decrease and Gatsby continues to grow, we anticipate seeing many more static react sites in the future.

Have you had any ‘unique’ builds recently that don’t fit into the ‘norm’? We’d love to hear from you!