loading...
Cover image for Gatsby with WPGraphQL, ACF and Gatbsy-Image
NeverNull

Gatsby with WPGraphQL, ACF and Gatbsy-Image

henrikwirth profile image Henrik Wirth Updated on ・3 min read

So, there is a lot happening around Gatsby with WordPress and WPGraphQL. At times, it can get confusing and a lot of given functionality is hard to find or figure out. I am working on a client project right now and somehow had to handle images, that I source through my WordPress backend.

After trying out all sorts of solutions and working through the plugin library of Gatsby, I ended up finding a little piece of documentation, that led me to a solution, that works for me. And, because some very helpful people in the WPGraphQL Slack Chat asked me to write about that solution ... here I am.

I simply wanted to have my WordPress Media as static files inside my Gatsby app and work with the gatsby-image plugin for transformation/optimization.

Libraries used


Gatsby Config

/* --------- gatsby-config.js --------- */

module.exports = {

  plugins: [

    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `images`,
        path: `${__dirname}/src/assets/images`,
      },
    },
    `gatsby-transformer-sharp`,
    `gatsby-plugin-sharp`,
    {
      resolve: "gatsby-source-graphql",
      options: {
        typeName: "WPGraphQL",
        fieldName: "wpgraphql",
        url: `https://${YOUR_DOMAIN}/graphql`,
      },
    },
  ]
}

  • Make sure all the plugins are mentioned correctly in your config file
  • For some reason, it can cause errors not having gatsby-source-filesystem used in the configs. Make sure it resolves to a valid path, even if there are no images inside the folder.

Gatsby Node


/* --------- gatsby-node.js --------- */

const { createRemoteFileNode } = require(`gatsby-source-filesystem`)

exports.createResolvers = async (
  {
    actions,
    cache,
    createNodeId,
    createResolvers,
    store,
    reporter,
  },
) => {
  const { createNode } = actions

  await createResolvers({
    WPGraphQL_MediaItem: {
      imageFile: {
        type: "File",
        async resolve(source) {
          let sourceUrl = source.sourceUrl

          if (source.mediaItemUrl !== undefined) {
            sourceUrl = source.mediaItemUrl
          }

          return await createRemoteFileNode({
            url: encodeURI(sourceUrl),
            store,
            cache,
            createNode,
            createNodeId,
            reporter,
          })
        },
      },
    },
  })
}

That's really all you need. Let's break it down a little:

  • WPGraphQL_MediaItem: This depends on your config. It starts with the typeName of your gatsby-source-graphql.
  • createRemoteFileNode gives you the ability to pull in remote files and automatically adds them to your schema.
  • imageFile: will be the type you can query (see below).
  • type: 'File': will add the MediaItems as Files, which is great, because now gatsby-image can make use of it.
  • url: encodeURI(sourceUrl): Here we encode the Url coming from WordPress, to make sure it is parsed correctly even if the image paths include umlauts.

Pages Query


# page.js

query {
  WPGraphQL {
    pages {
      nodes {
        featuredImage {
          sourceUrl
          imageFile {
            childImageSharp {
              fixed {
              ...GatsbyImageSharpFixed
              }
            }
          }
        }
      }
    }
  }
}

Important: Always query sourceUrl, otherwise it doesn't work, because the resolver would miss that data.

Final thoughts

Thats all there is to it. And it works with ACF Media files too. Same same.

Almost ... I think it is important to mention, that with this method all available Media-Files coming from WordPress will be pulled in the cache. So, if there is, for some reason, a clear of the cache happening, it would need to pull them in again I guess. For performance, it could still be more useful to somehow fetch all the Media-Files apart from the Gatbsy-Cache. That would mean though, you have to do the hard work of creating the schema yourself. I'm sure there will be great solutions for that too. Would be happy if someone has some experience with that and would share their thoughts :)

Caching

If your server doesn't support etags, the default caching of the gatsby-source-filsystem won't work.

You can checkout the custom solution by Robert Marshall here, which should be slightly faster and doesn't rely on etags: https://thoughtsandstuff.com/gatsby-with-wordpress-caching-downloaded-media-images-to-reduce-build-time/

Coming Up

I plan on writing up a big article about setting up Gatbsy + WordPress + ACF + Polylang for a client ready project with Multilanguage-Support and dynamic content creation through ACF's flexible content fields. I wonder if that would be of interest. Any thoughts and suggestions are highly appreciated.

References

See the Gatsby documentation of it here: https://www.gatsbyjs.org/docs/schema-customization/#feeding-remote-images-into-gatsby-image

Posted on by:

henrikwirth profile

Henrik Wirth

@henrikwirth

Web, App, Software, AR, Design ... I am a Developer and sometimes a little bit of everything, at nevernull.io

NeverNull

At NeverNull we run through a lot of projects and technologies. To give some content back to the community, we want to share some of our experience with everyone, hoping to help you out with your projects and ideas.

Discussion

pic
Editor guide
 

I needed my build to cache images so I adapted your resolver. I have written a walk through - hopefully it can help you like you helped me!

thoughtsandstuff.com/gatsby-with-w...

 

Anyhow, we can implement this kind of cache for posts as well? Rebuilding unchanged pages increases build time for larger blogs

 

You can use the new gatsby-source-wordpress@v4 which already does a lot of work for you when it comes to incremental builds.

github.com/gatsbyjs/gatsby-source-...

 

Super nice. If I may I'll reference your article, so people won't miss on this.

 

No worries. Just link back!

Hey Robert, I was wondering as I am trying your caching solution, isn't gatsby-source-filesystem already caching the images? I just tested it and for me it already caches the them.

I was contacted by Kyle Mathews saying the same thing. In the majority of situations Gatsby seems to cache and check itself. My version is 'slightly' faster, and handles the unlikely edge case of servers not using etags.

The conversation: twitter.com/robertmars/status/1172...

I suppose it depends on your environment. I quite like skipping the server checks, as it seems like an extra step.

Interesting. Also I guess it could be useful to write some custom caching, to persist the image-cache over gatsby. So if gatsby clears its cache, it will still be there. This would be interesting for peeps with gigabytes of Media-Files on their WordPress, who want to make sure, that they never ever have pull everything in again.

I'll update some info in this post. Thanks for the explanation.

 

I'm not exactly sure why but I did everything to the tee but my gatsby-nodes.js file loops over creating pages multiple times. I narrowed it down to the script you made. I'm a bit confused about it though.

 

Same here. I'm actually using this caching method.
gasby develop runs the same create post/download image tasks 4 or 5 times

gasby build runs only once (i.e. works ok)

Caching doesn't seem to work either, gatsby still downloads images but maybe not featuredImage ones as I'm also using gatsby-wpgraphql-inline-images

 

What versions are you using? I haven't tested it with the newest versions of all the plugins and Gatsby. So maybe something changed? Also the node Version could be interesting. If you have a reproduction on Github, that would help a lot.

I don't have so much time on my hands at the moment for the next two months. But I'll try to help as much as I can.

I forgot to mention I'm using this rather outdated demo from gatsby-wpgraphql-inline-images author (I believe). It's based on the official wpgraphql demo which is also outdated, as is their demo.wpgraphql.com, probably due to older wpgraphql plugin

I'm going to start over with your code @ part 6 as I don't need ACF stuff.
Looks good so far, apart from dealing with nonexistent isFrontPage field.

Thanks for your great work!

isFrontPage should be available in the newer versions of WPGraphQL. Make sure in WordPress, that there is a page actually set to be the front page.

wordpress.org/support/article/crea...

 

Great post. It helped us a lot to extract images. We were wondering if this could also be used for other types of binary files such as mp3, mp4 or pdf.

Interested in the Polylang too. We have a project where we will use WPML so I am sure it will help and if we find different points, we will share.

 

Heya, thanks. Glad it helped.

mp3, mp4 and pdf should be the same process. You just have to figure out what kind of media-type it is and then write a resolver for it.

I actually started of with WPML and for some reasons it got super messy. Thats why I switched to Polylang. Would be interesting to see a solution with WPML though.

 

Will sure share with you. Project should start in the next week.

 

I recently had to build this functionality, so wrote a short article on it. Hopefully can point you in the right direction!

thoughtsandstuff.com/pulling-ordin...

 

Hi, i've tried to get this working using the exact same code but am receiving the following error:

Error: Schema must contain uniquely named types but contains multiple types named "File".

Do you know why this might be happening at all? thanks

 

I remember someone having the same problem. He needed to make sure, that gatsby-source-filesystem is used in the config and the options contain a valid folder path.

If this is not the problem, feel free to come to the WPGraphQL Slack Chat. You can chat with me and others there and we can try to find the bug with you.

 
 

This is great. Thank you - working as expected!

I wonder how I can bring in author avatars in the same manner as well (instead of just 3rd-party calls to gravatar's servers at run time)?

 

I just tried this:

createResolvers({
    WPGraphQL_Avatar: {
      imageFile: {
        type: "File",
        resolve(source) {
          return createRemoteFileNode({
            url: source.url,
            store,
            cache,
            createNode,
            createNodeId,
            reporter,
          })
        },
      },
    },
  })

Seems to work for me. Obviously it will fetch gravatars at build time. Maybe another Avatar solution would be possible, if you want to avoid using Gravatars.

 

Definitely interested in the article on how to set up Gatbsy + WordPress + ACF + Polylang :)

 

Thanks so so much for this article! I had no idea how to go about this. Great write up!

(and yes, I am interested in Polylang)