For a while now I have been working with WordPress as a back end CMS (one of the many micro services) and Gatsby to generate websites for my clients. To connect the two I am use a WordPress plugin called WP GraphQL, and a Gatsby plugin called Gatsby Source GraphQL. Everything always works brilliantly, apart from being able to use any images from the media libary!

This was an issue. I needed to get images from the WordPress media library into Gatsby.

After much searching I found an article by Henrik Wirth from NeverNull explaining how to use the createResolvers function provided by Gatsby. His article walks though the process of getting all media items from the WordPress media library into Gatsby. Perfect, now they can be used throughout the build. Unfortunately this solution doesn’t cache the images, meaning everything is downloaded again. Putting pressure on both the Gatsby host – increased build time, and the WordPress host.

My solution builds on top of Henriks, adding that little bit of essential caching.

In the Gatsby Node File:

exports.createResolvers = ({ actions, cache, createNodeId, createResolvers, getNode, store, reporter }) => { const { createNode, touchNode } = actions; // Add all media libary images so they can be queried by // childImageSharp createResolvers({ WPGraphQL_MediaItem: { imageFile: { type: `File`, async resolve(source, args, context, info) { if (source.sourceUrl) { let fileNodeID; let fileNode; let sourceModified; // Set the file cacheID, get it (if it has already been set) const mediaDataCacheKey = `wordpress-media-${source.mediaItemId}`; const cacheMediaData = await cache.get(mediaDataCacheKey); if (source.modified) { sourceModified = source.modified; } // If we have cached media data and it wasn't modified, reuse // previously created file node to not try to redownload if (cacheMediaData && sourceModified === cacheMediaData.modified) { fileNode = getNode(cacheMediaData.fileNodeID); // check if node still exists in cache // it could be removed if image was made private if (fileNode) { fileNodeID = cacheMediaData.fileNodeID; // https://www.gatsbyjs.org/docs/node-creation/#freshstale-nodes touchNode({ nodeId: fileNodeID }); } } // If we don't have cached data, download the file if (!fileNodeID) { try { // Get the filenode fileNode = await createRemoteFileNode({ url: source.sourceUrl, store, cache, createNode, createNodeId, reporter }); if (fileNode) { fileNodeID = fileNode.id; await cache.set(mediaDataCacheKey, { fileNodeID, modified: sourceModified }); } } catch (e) { // Ignore console.log(e); return null; } } if (fileNode) { return fileNode; } } return null; } } } });

This works by:

Finding the WP GraphQL Media Item Node – WPGraphQL_MediaItem – and moves through all of the imageFile nodes within this. Checks to make sure there is a source URL for the image. Creates a cache ID based on the image and checks to see if an ID already exists. If one does, checks to see if this image is newer. If an image exists that isn’t newer, just give is a quick node refresh (so it isn’t deleted). If an image doesn’t exist, get the image and make a new cache ID. Return the node of the pre-existing or new image

A few things are required when using this resolver. When querying an image in the GraphQL query the following options need to be included:

sourceUrl

mediaItemId

modified

This means that a query to get a posts featured image would be written like this:

query GET_POSTS { posts { edges { node { featuredImage { sourceUrl mediaItemId modified imageFile { childImageSharp { fluid(maxWidth: 650) { base64 aspectRatio src srcSet sizes } } } } } } } }

Hopefully this helps you if you come across the same issue I did! This process can be altered to work with Author Avatars as well, save that precious bit of bandwidth.