When the burden of rendering is removed from WordPress, it becomes an open source API platform. With a few plugins like WPGraphQL, you can create an extensible backend for your React apps to consume which enables modern architectures and development practices in WordPress.
API-first Development with Headless WordPress
Transcription
Hello, React Summit. I'm Matt Landers, Head of Developer Relations at WP Engine. In this session, we're going to talk about API-first development with headless WordPress. Our agenda is really simple. I'm going to do some talky talk. I'm going to talk to you a little bit about what we're going to do, and then we're going to do a demo. We only have 20 minutes, so I don't want to spend too much time on talking. I want to show you how to actually do API-first development with WordPress. You may be thinking, why WordPress? There's a lot of different options out there for you to do API development. Why would I use WordPress? Well, one really good reason is that 40 percent of the web is WordPress and that is growing. What that means is that your users probably already know WordPress. They'll be comfortable in the admin panel, like your content producers and marketers will know how to get around WordPress, which is a benefit to you that they already know the software. It's also free and open source, so why not take advantage of that? There's a lot of extensions already built into WordPress that make it really great for headless. Headless WordPress is awesome, so you don't need to know PHP. I think that that's some people's fear, is like, I don't want to do PHP, so I'm not going to do WordPress, especially at an event like this where everyone's a React developer. Well, you'll be happy to know I don't know PHP and I do headless WordPress almost every day. I'm a TypeScript, JavaScript developer, and I spend my time in Node, TypeScript, Deno, those type of places. I don't do PHP. You don't have to either. For this session, there's a few resources that are available to you. The code that I'm going to be using and deploying in this session, it can be found on my GitHub, at matt-lander-follow.dev, that repository. The framework that we're going to be using for headless WordPress is from WP Engine. If you go to the WP Engine GitHub, you'll see a headless-framework open source project. That is what we're going to use to kick off our projects and get it going. You can also go to developers.wpengine.com and get a ton of resources from me and my team on headless WordPress and how to do specific things. Let's dive right in and do API development with WordPress. For this demo, we're going to build a site that lists out different developers on Twitter that we can go follow. We want to be able to find developers based on the language that they typically use. Because if I'm a developer and I want to follow another developer, I'm probably looking for somebody that works in the language and frameworks or technologies that I know so that I can get more information, learn more about it. That's what we're going to build on the site. We're going to use headless WordPress to be the platform that we use for our API, and also where our users will be able to go in and enter in the data for the website. What I've done is I've used local to spin up a WordPress site on my local machine. You can get this at localwp.com. It's really great for quickly spinning up sites in WordPress, and working on them locally, then you can push them up somewhere live. I've already got this running and I also have some plugins that I always use already installed. The number one plugin that I always use is WP GraphQL. You got to have that because you need a nice API whenever you're going to work with WordPress. There is a REST API already, but I find it much easier to use a GraphQL API, especially since there are so many relationships in our data. There's also two other plugins that really turn WordPress into an API building platform. That would be the custom post type UI and advanced custom fields. There's also extensions for those two for WP GraphQL that I have installed as well, and I have the headless framework from WP Engine installed as well, which is a plugin. Let's look at what that gives us first. If we go to the GraphQL playground here, we'll see that we can make GraphQL calls straight into our data and get content out. By default, WordPress has posts and pages. This content comes out as raw HTML as we can see here. On the front end and from an API, that's not really what I want to get all the time. For instance, in this case, I want to get a list of developers and some structured data about them. I want to build an API that's going to give me the data back on the front end that looks the way that I want it to look. Let's do that. The first thing we're going to do is create that custom content type which in WordPress is called a custom post type. We're going to call it developers. Our plural label will be developers and developer. We'll see why we need that in just a second. We'll scroll down and we're going to get rid of some of the default things that show up on this post. We only want the title. We want this to show up in GraphQL. I got to tell it how I want it to show up in GraphQL. I'm going to add that post type. As soon as I add that, you'll notice that there's a developer section in our menu now, which is cool. Now I have a way that I can go and see the developers that I've entered. Now I've had some from previously and they show back up, so I don't want to have to enter those in again. But if I click one, I can only see the name. This isn't very useful. Now we can go over to our graphical editor, and we can pull these out. We can say developers and just grab the title. We can get that data out now. So we have the title, but we need more data than this. We need to pull out. We want their GitHub, their Twitter handle, all of those things. So let's go ahead and add those. So we go to custom fields and we say developer fields. You can name that whatever you want. Then I only want these to show up on that developer custom post type. I don't want it to show up on my blog posts or my pages. I only want them to show up on my developer custom post type. Then we can just add fields really simply. So I'm going to add a name. I want that to show up in GraphQL, so I make sure I have that checked here. I also want to add Twitter. So I want their Twitter handle. That's just going to be text as well. Now I also want to know what languages they work in. So languages, and we'll do a taxonomy. So in WordPress, taxonomy are things like tags or categories. For this, we're going to use tags to do this. We also want to get their personal blog. This will be a URL. We'll see how that comes into play in a minute. We want their GitHub, be another URL, and that should be good. So we're going to go down to the bottom here, and we want to make sure this shows up in GraphQL again. I usually prefix the field group name with ACF, and then my developer, whatever I want to call it. We go back to the top and we will publish this. Now, let's go back to our editor. Now look, we have all of these fields and a nice editor for someone to come edit. So I could come in here and say, well, I know that Will also knows C-sharp, so I'll add a new tag here and call that. He doesn't have a blog, and then we're good, we can update that. So now I have a nice editor, I can go add a new developer and add all that in. Now what I'm going to get is a nice API. So if I go to my GraphQL IDE, I can pull all of these out, name, and we can scroll down over here, and we'll see that they're going to show up in that ACF developer group. We have their GitHub, name, personal blog, Twitter, what languages they have. So let's run this. Pretty cool. So now we're pulling all of that data out in a nice structured way. We're not getting raw content like we did with the post, we're getting real content like we would expect from an API. We can even rename this, so we'll just give it an alias, call it data instead of ACF. Now we've got something nice that we can use in our website. So the next step is to go build the website. So let's go do that. For the site, we're going to use the headless framework from WP Engine. It's an open-source project that makes connecting to WordPress and pulling down content really easy. So we're going to go ahead and use that. So if we go to the projects in GitHub and we scroll down, there's an NPS command that you can run that will go ahead and get that project set up for you. I've already run that in the interest of time and I've got it set up. So let's look at what it is right now. I pulled out a lot of the boilerplate that's in there. So there's this whole site there for you that shows posts and has a blog. Pull that out and put in some of my own CSS and some components. So this is what the site looks like right now. We have this cool light dark mode, which you did purely with CSS variables. Definitely check out the code if you think that's cool. Then let's get into the code and see what we're going to do here. So we have this environment variables file where we tell the framework where our WordPress instance is. So this is just looking at our local instance right now. We'll change that when we deploy it live to a live instance. Then we have our headless WordPress secret, which that comes out of WordPress itself. So if I come back over here, I go to settings, you can see this secret is in here. Can't hack me, this is local. You won't be able to see the real one. You can try. So we got that set up. That means that the framework is ready. It knows how to talk to WordPress. We just have to use the functionality from the framework to make those calls. So let's do it. The first thing that we want to do is to get GQL from Apollo. We're going to use this to save our query. So we'll say get all devs. We're going to grab that from here that we did earlier and just paste it in. So now we have our query, which is great. Now I need to make the query and provide that to the homepage. So let's determine what the homepage is going to need from a type standpoint. So we'll create an interface, home props, and it's going to have a developers. We need to pass in developers and it'll be the developers type which I've already defined and I can show you that. Right here, I have this type. This looks just like what we're going to get back from the query. So if you go over here, it's the same fields, just typed out in TypeScript, and then I have the array. Since it's under that data property like we have right here, we have it extended like that for the developers. Cool. That's what we're going to pass in here. So let's give this a type, react.fc, and we'll pass it in home props. Now we'll have those developers ready for us. Great. So let's go ahead and map this out. So developers.map, and we'll put those in a card component. I already have this component created. I'll show that in just a second. I would need a key which is going to be developer.data.twitter because that should be unique. Then the card just expects those developer props. So we're going to do developer.data. Let's take a look at that component real quick. We'll import that. It's just a pure component that just has some styling and stuff like that for us. So we don't have to type all this out for the demo, but it's just a pure component that will show a card of each of the developers. So we're looping through that, but we haven't provided this homepage any data yet. So we're using Next, and we can make this a static page if we just export, get static props. So let's do that. Get static props, and it has a context, and we're going to type that. Get static props context. Then we want to grab the Apollo client. So we can do that with a framework method called get Apollo client and we just pass in the context. When we pass in the context, it'll store the cache of that query on the context. So we don't end up making the call multiple times. The framework handles all that for us. We want to make the query. So we're going to grab the data from client.query. We need to wait this because it returns a promise, and we'll pass in get all devs. Great. Now we have our data. We need to return that. So we're going to return props, which is going to have developers, and it'll be data.developers.nodes. The reason for that is right here. So it's going to come back as developers.nodes. So that's why we're passing that in the way that we are. We also want to pass in revalidate one here, so that we constantly get new data as we add those developers to our headless WordPress site. There's one other thing I want to do here, which is make a framework call to get next static props. Now just pass in the context. This is the final thing that I need to do to make sure that I cache that query. I'm going to import that from the framework, from our next section of the framework. So now what we're doing is we're grabbing the client, which has been put onto our application by the framework. If we look in this app here, we have a headless provider, and this does all the magic in making sure that Apollo is set up and ready for us to go. We make the query to get all devs. We call this framework method just to save the cache from Apollo onto the context. Then we return our props, pass that into our home, and just show these cards. So let's see if it's working. We'll refresh this, and there they are. We have our developers coming out of headless WordPress. Let's go create another one just to show how this is working. Then come in here, add a new one. Let's say Dan Abramov. Pretty sure this is just Dan Abramov. Might not be. He works at Facebook and he knows React I'd say, and those things. We'll publish that, go back over here, refresh, I have to refresh twice. Not this time, and there's Dan. Cool. It was not the right handle. Now that we have our site up and running, the next step that we would want to do is to actually deploy this and make it live. So I'm excited to show off a little bit about what I've been working on WP Engine, which is the Atlas platform, where you can deploy your WordPress site and your Node front-end no matter what you've written it in. So in this case, we're using Nets, but we could use Gatsby or Vue or Angular or whatever, and we can deploy it to Atlas. So let's go ahead and do that. If I come over to my WP Engine portal, I have this site already running. So I have a WordPress site, and now I just want to deploy my app. So I go to Atlas, and I'm going to create a new app. I'm just going to name the app, follow a dev, and we're going to use our, our headless environment name is going to be production. Then we don't need anything else, right? Then we want follow a dev is our WordPress environment. We're going to run this in US Central. Now, GitHub settings, this is running at mat-lander-follow-a-dev, and it's on the main branch. Then we need to give it that environment variable that we created earlier right here, and we need to give it the URL to our site, which I've got this already running out here. So I just need to grab this URL. Got more developers already set up. We'll save that. We'll click Create App. It'll go out, pull our code from GitHub, download it, npm install, run a build script, npm run WP-build is the script that it runs. Once it does that, it will run next build, which will create all of our static pages, and then deploy it where it will run npm start, where we spin that up on port 8080, and then the platform knows how to run it. But once it's up and running, it'll be good to go. We'll see that that is over here building. When it's done, we'll come back and it'll be running. All right. So our site is up and running. We've given it a URL. I also attached a custom domain to it, and now we can go out and check it out. So it's actually on follow a dev. You saw how fast that is. It's just running. It's instant. It's running static. We also added some more functionality in here. You can check it out in the code, but we can filter by different keywords here or different languages, and it's super fast and quick. So check that out. Check out the code. Check out Atlas, and let me know what you think. All right. Before we're done, I have one more thing that I want to show you. So at WP Engine, we've been working to make headless WordPress a really great headless CMS. Part of that is improving the user experience. You probably noticed that while we were creating those custom content types, that it didn't feel very headless first, because there are a lot of fields in there that just didn't make sense. So we've been working through our open-source framework, which is out here. Make sure you start so you can follow along on some code to create a content modeler, which I'm demoing right now. So it's the first time anyone has seen this, but it allows you to create content models in a much more user-friendly way. So we could create that same content model, so developer, developers, that we created earlier in this much better user experience. We have different fields that we can create, so we can put in our name as a text field. We could add another field for the languages, which is a repeater, so that's like an array. We can create these fields and we can create this content type in this very simple way, and then we can also have a different experience for our editors, which will be coming out soon. So you can't get this yet, but make sure you follow along with our project so that you know when it is available. Finally, if you want to keep track of the things that I'm doing, my team is doing around headless WordPress, go to developers.wpengine.com. You can join our Slack channel, where we have lots of people in there that are talking about headless WordPress and doing different projects around it. Also, we create a lot of content on a weekly basis. So we have headless WordPress live, or we do live coding on YouTube every Friday at 1 PM Central. Check that out. We actually built this follow-it-up site during one of our live coding sessions. Then we also have the Decode podcast, so come and check that out. It's out on iTunes, Spotify, all over. But we just talk about everything front-end development and some things around headless WordPress as well. So check it out, let me know what you think, and go build some cool things with headless WordPress. Happy coding. I'm actually really surprised about this poll. I expected everyone to want to do GraphQL, but looks like people are still doing REST. I'm glad I asked this because it's a surprising result. Yeah, but just think about maybe some of them are just stuck in the past more or less and not because they don't want to do GraphQL, but just because the whole infrastructure is really tied to REST in general, maybe that's one thing there. Also, the components relies on REST and it's pretty hard to just move to GraphQL. It can be. Yeah, that's true. For sure. All right, so we received a couple of questions. And I'll start with Yuri's question. He's wondering about authentication in headless WordPress. Is it included out of the box or we should still integrate with third-party services like Auth0, via plugins as it was implemented in WordPress REST API previously? Right. So WordPress has its own authorization mechanism. So if you're comfortable with that, then you can definitely use it. The only thing that you have to do to make authenticated requests is to add the authorization token to the request to WPGraphQL or to the REST API as well. So in our plugin that we've created, the open source framework, there's a authentication flow that we've implemented. It's similar to like OAuth. So you'll be, if you hit a page on your front end site, there where you need authorization, like a preview link, for instance, if somebody is writing a blog and they want to preview it before they publish it. When they hit the link on the front end, it will route them to WordPress to log in, which then will redirect them back to the front end with an access code. That code will be exchanged for a token. And then you can use that token in your request to pull back any data that you need for authorization. But if you wanted third-party logins, like log in with GitHub or something like that, or Auth0, you can do that as well. I haven't tested that out, but that is an interesting scenario that I should take a look at. Yeah, as we were discussing previously, I'm also fighting with this access token to be like, to know exactly that's not coming from a hacker, let's say, and I would like to encode or decode it and see the actual user. This is something that happens on the back end. So it's really something that maybe a third party or WordPress, if it's doing it, it's something really good to rely on. Right, in that case, you could use your back end for your front end for that as well. So if you're using a third party, and then integrate that into WordPress, if you needed to use that token to access data, you could do that for sure. Yeah, exactly. Or maybe a custom of, right? Right. Another question is coming from Rene Goretzka. If you have nested GraphQL queries, does the plugin fetch the data in one SQL request or does it shoot out several requests to the SQL database? I'm not 100% familiar with the inner workings of WPGraphQL, but I can get that question to Jason Ball, who's on our team and who maintains that. I will say that it's very efficient with its queries, a lot more efficient than the REST API. There's some demos that we've done where we hit a server with lots of posts and taxonomies, like tags and categories. And it takes, you know, eight seconds to come back with the REST API. And then when the GraphQL API, it takes, you know, 20 milliseconds. So it's much more efficient than using the REST API for sure. Yeah, I think there's also maybe a data loader involved, right? And there will be like, basically for, even though you're using WordPress or not, it's going to go and take something or is going to join the request maybe. And yeah. Another question. Exactly, yes, yes. So optimizations. Another question is coming from Carlos Barraza. How did you generate the types for the operations? We created the types. So, well, the plugin comes with standard types. So if you have like a regular post or something like that, those will, the plugin has those types available for you. But if you have a custom post type, you'll need to provide those types. So you probably just didn't see it in the presentation, but those types were there. Or you provide them. Right. Another question comes from Navis. Are there any plugins to improve performance? We discussed previously about performance. Maybe there are plugins to improve it. So one of the reasons that you would go with headless WordPress in the first place is for scalability and performance. WordPress, traditionally, when you have the rendering mixed with the API and the data, different plugins are doing different things. You don't have a lot of control over. It's kind of difficult to scale WordPress. But when you go, when you split the architecture up into where you have the API in the front end, it gives you a lot more options on how you would scale that platform. So you can do caching at the node layer. So if you have a post that's being hit a lot and you're doing server-side rendering or something like that, you could cache at the node layer and only reach out to WordPress whenever you absolutely need to. And you can also distribute that front end globally, which you couldn't do with WordPress since it's so tied to the database. So there's a lot of options when you go headless for scalability just by opening up that architecture. Great. Another question comes from Marcus Young. First of all, he or she loves your presentation. So congrats on that. And the question is, do you also create custom dashboards for clients with this headless way or just use the WordPress dashboard? Custom dashboards on the admin side, I assume. I think so. I mean, if you already have plugins that you're using. Yeah, so if you already have plugins that work on the admin side, those will continue to work. So if you have something that's working from a dashboard perspective, I would say stick with it. Don't want to reinvent that. Whenever you go headless, you do lose all the plugins that modify the front end. So I would definitely take advantage of whatever you can on the back end to reduce the development burden for sure. Yeah, it makes sense. Yeah. Wow, a great question arrived. It's from Giannakis87. What about e-commerce plugin? Or do you have already any integrations more specifically to e-commerce? Yeah, so WooCommerce has APIs that you can take advantage of. We haven't built anything specifically on top of WooCommerce yet. I've actually done a few live coding sessions with where I use Shopify mixed in with WordPress. So we mix content commerce. And there's actually a workshop that's part of this conference that we did last week. I think it goes live again next week, where we build a Shopify e-commerce store. But it would be no different than to use WooCommerce instead of that. We just wanted to show using different data sources going into that. But there's definitely an opportunity there to build some stuff out of the box for WooCommerce for sure. Yeah. Another question, a long one, but it's really nice. It's addressed by CW. Since both static front end and WordPress are hosted on WNGen, is the WordPress instance publicly accessible? Or it's a VPC of sort so that you can access the static front end and interact with it via Apollo? Or can someone still accidentally arrive on the WordPress site? Right. So by default, the WordPress instance is available on the internet because a lot of people want to hit that from the browser. So if you were going to do client side stuff, you might want to hit your WordPress instance from the browser. But it is possible to take your back end offline completely and only make it accessible from the node side if you were so inclined to do that. One thing that we do in the plugin is we do take the front end off the internet. So it's not indexed by a search engine or something like that. So if you were to hit the front end for WordPress, that person would be redirected to the front end that's a node to prevent multiple SEO potential being indexed and also to reduce the surface area from a security standpoint. So they could only get to WP Admin, which is going to be a lot harder to break in than some plugin that's messing with your front end. All right. Speaking about the SEO, Zach Winnie asked, is there a way to query for things like head tags for SEO with WordPress Engine Headless? Yes. And we did that in the workshop for this conference. So Yoast has a plugin for WP GraphQL so that you can pull all the Yoast data out of WordPress. And then Will Johnston, who's on my team at WP Engine, he created a React component that you can take that data and just plug it into the React component and it'll put it in the head for you. It'll do that on static or server-side rendering, however you want to do it as well. And I think we have time for one more question. Luis Sardon is asking, any way to create fields via API to WordPress? Is there any way to create new fields through the API? That's a good question. I don't think that out of the box you can do that. But it's something you could easily enable with WP GraphQL. WP GraphQL is very extensible. And I've used it to create fields for sure. And also, so I've used WP GraphQL's extensibility to create a form where you can just only submit to the form but not read the form data, which is a good way to create a contact form. It's pretty cool. And thank you so much, Matt. We had so many questions, but time's out. But maybe people can still reach out to you. Are you going to be available on Discord? I'm going to join the Spatial chat here in a minute. So if you want to jump on there, I'll be there. But you can also reach out to me through my GitHub or Twitter or wherever you want to find me. Matt Undershorelander is on Twitter. Amazing. Thank you so much once again. And enjoy the rest of the day, Matt. OK. Thanks for having me. ♪♪