DE{CODE}: New Features for Headless WordPress

The updates to WP Engine’s Headless WordPress headless development tools will help you deliver on your clients’ toughest requirements. Using a free Sandbox account, this demo will show you how to add these new features to your headless site.

Check out the video below to start building your most performant, secure website yet!

Video: New Features for Headless WordPress

Session Slides


Full Text Transcript

KELLEN MACE: Hi. I’m Kellen from the developer relations team at WP Engine. In this talk, we’re going to explore some of the new, exciting features in the Headless WordPress ecosystem. We’ll see how in the WP Engine user portal, we can create a new Headless WordPress app and choose this portfolio blueprint. In doing so, we can get a full-blown headless WordPress site live on the internet within a matter of minutes. 

Then we’ll see how we can clone down that project to our local machine and get set up for local development, so that we can make customizations to our new site. Then we’ll turn our attention to Headless WordPress Content Modeler and see how we can use it to create a new custom content model called Photos. 

And this Photos content model will have a few of its own custom fields, including one that’s a repeatable field, which is a new feature that recently came to Headless WordPress Content Modeler. Then finally, we’ll see how we can do some custom development in our front-end JavaScript app and query for that custom Photos data and then render it to the page. 

Once I’ve created a WP Engine account and logged into the Headless WordPress page of the user portal, I can go ahead and click the button to Create a New App. From here, we can either start with a blueprint, which is a prebuilt site, or pull from an existing repo. Let’s start with a blueprint. Now we can select which blueprint we like to use. So we’ll choose the Portfolio blueprint, and then click Continue. 

The next step is to connect this app to GitHub. So we’ll click the button to do so, and then sign in to GitHub. And after that, we’ll see this screen, indicating that our app has been authorized. So next, we need to actually clone this repo. So we’ll click Clone Blueprint, and then give a name to our new repository. And click the button to create a new repo using this blueprint template. 

So here you can see that this new app repo has been created on my GitHub account. Now we need to link this repo to our Headless WordPress app. So back in the user portal, we’ll scroll down to the Selected Repository section. If you allowed access to all your repos, you may see it on the list. If not, you can click on Manage Repositories. 

On this page, you’ll be able to select the repos that Headless WordPress should be able to access. So we’ll select our repo on the list. Click Save, and now when we return to the user panel, we’ll see the repo we had added pop up on the list. So go ahead and select that. For a region for our app, we’ll stick with U.S. Central. And finally, click the button to create this Headless WordPress app. 

Here, we’ll see a notification that our app is now being built. So we’ll give that just a minute. Now that our Headless WordPress app has finished building, we can go ahead and click this Headless WordPress URL link to see our new Headless WordPress app running live on the internet. So on the home page, we’ll see our list of latest posts. We’ll see our testimonials. 

We can head over to the portfolio page and check out a list of our portfolio projects here. I’ll click through to an individual project. Next, we’ll check out the blog. So head over to the blog page and see our grid of posts here. And we can click through to see an individual blog post page as well. And then ready, set, click, to return to our homepage. 

So you may notice that these page transitions are really speedy. We get an immediate cut over from one page to another. And this is one of the benefits of going with a headless WordPress architecture. Next up, let’s see the WordPress site that’s behind the scenes powering this experience. So let’s head back over to the WP Engine user portal, and from here we can click on this link to the linked WordPress environment. 

Here we can click on WP Admin to be sent to the WordPress admin for our site. So here is our back end powering this experience. Let’s head to posts, and we can see here that it’s been pre-populated with a number of dummy blog posts. So this is where all that data is coming from for our new site. Let’s also take a look at plugins. Here you can see several plugins have been installed and activated to enable headless WordPress development. 

Let’s pay particular attention to Headless WordPress Content Modeler. So over in the sidebar, we click on Content Modeler. You can see here that two pieces of custom content have been created for us, projects and testimonials. And we can see those here in the sidebar. So we have projects, a list of those, as well as testimonials, and a list of those. So this is where the projects and testimonials data that we saw in the front end site is coming from. 

So we’ve made some great progress. We’ve seen how from the user portal we can create a new Headless WordPress app. And when we do that, it creates not only a front-end JavaScript application to serve the pages of your site, but also it creates the WordPress back end that powers that experience and saves you the trouble of linking the two up. It connects those two so that the front-end app is able to source its data from the WordPress back end. 

From there we were able to take a look at the front-end app and see it running live online, as well as poke around in the WordPress admin and see some of the custom data types or data models and also some of the dummy data that’s been created for us. So in very little time, you can see that we have a full blown working headless WordPress application running now. 

What if at this point we want to make changes, though? What if you’re building an actual portfolio site, and you think to yourself, this is really cool. This is a great head start. But now I want to make some changes. I’d like to make some code changes to maybe swap out some colors or add additional pages to my site. How do I do that? How do I get started with local development? Let’s find out next. 

To start, we’ll copy the link to our GitHub repo and then go ahead and run git clone on the command line to clone down our project. From here, we can CD into that project directory, and then run NPM install to install our project’s dependencies. Once that’s done, we’ll go ahead and open the project in a code editor. 

Next, we need to set up some environment variables. So you’ll see that a sample file has been created for us here. And now we just need to make sure this has the right values. So back in the user portal, we’ll click on Manage Variables and then take a look at the environment variables the production app uses. Go ahead and copy and paste both of those into our app so that our local app will use the same environment variables that production does. 

And the last step here is to rename this file, removing .sample from the end of it so that it goes into effect. Now, the front-end app that we’re working with here is built on top of Faust.js. And Faust, in order to do the data fetching magic that it does, needs to be able to run what’s called a GraphQL introspection query. 

So this is basically Faust asking the WordPress back end, hey, what data do you have available in the GraphQL schema for me to query? So we’ll need to enable introspection for this to work. We’ll head back over to the WordPress admin here and go to GraphQL and then settings in the sidebar. 

On the Settings page, we’ll scroll down to where we see Enable Public Introspection, and go ahead and click that box. While we’re here, I recommend also enabling Graphical Debug Mode. That will give you more descriptive debug messages showing up. Once we’ve done that, we can go ahead and click the button to save our changes. And now finally we can pop open the terminal and run NPM run generate. And then once that’s done, finally, NPM run dev to get our app up and running locally. 

Now, I’ll click this localhost 3,000 link, and we can see that our site is indeed running locally here. So we said that we want to add some content to this to customize our site. And now that we’re set up for local development, we can do exactly that. So let’s say for this project, we want to have not only blog posts and then our few pieces of custom content that we have, such as the portfolio projects we saw and also these testimonials. 

Beyond that custom content, let’s say we want to add even more. Beyond somebody who creates blog posts and creates portfolio projects, let’s say the client the site is for is also a photographer, and they want to feature the photos that they’ve taken. How could we add a custom content type or custom content model to our site to support this photo’s data, query for that, and then display the photos in our front end application? Let’s do that next. 

So I’ll head back to the WordPress admin here, and we’ll go to Content Modeler. So we’ve been to the screen once before. We glanced at the projects and testimonials. We can see that these are custom content models that have been created for us as part of this blueprint. And I can click through to each one of these and see that each of these models has their own set of individual fields. 

So projects, for instance, would have these individual fields. And projects and testimonials are both reflected here in the sidebar. And then the fields for each of those. If I click on a project, and then click on an existing one or go to Add New, either way, we’ll see all of those fields reflected here. So our content creators will see all the fields that they need to input this data. All right. 

For our custom piece of content, though, we need a new model. So I’ll go ahead and create a new model by clicking this button here. So I’ll call this photo. And for a plural name, we’ll just put an S on the end and call it photos. This auto-generated API identifier– here, this ID– I’m OK with. Photo looks good to me. For API visibility, this one we want to make sure to click public, since we want to be able to query for this data via GraphQL. For our model icon, maybe something like a camera would be appropriate for photos. And now I’ll click Create. 

So just like that, our photos content model has been created. So at this point, it says choose your first field for the content model. And as of this recording, these are the field types supported by Headless WordPress Content Modeler. For the photos that we want to feature on this site, let’s use a couple of these. 

Let’s say we’re going to give each of our photos a title. So I’ll say Title, and then call it Photo Title as the API identifier. And that’s how it’s going to be available in the GraphQL schema. That’s what that’s for. And we’ll say we want to use this as the entry title. And single line text is fine. So go ahead and click Create. 

For our next field, let’s say we want to capture that image itself for the photo. So I’ll hit the plus. And here, we’ll create a new field. We’ll call this one image. And for the type, actually, we’ll need to select Media, since it’ll be a photo. So I’ll name it image. And then down here, I will go ahead and set this as the featured image for each post. So I’ll click that, and we’ll make it required, as well. So we always know it’ll be there. And then click Create. 

There you go. There’s our second field. For the third one, let’s have a description. So I’ll hit the plus. And for this one, this will be a rich text field. So we’ll say description and that’ll do it for that field. And then our last one we want is for the subjects. So we’ll use this field to capture what’s shown in the photo. So if it’s a photo of a mountain range at sunset, for instance, like one of our photos will be, some of the subjects in the photo might be mountain, stars, sky, things like that. Just a list of things that are present in the photo. 

There would be different ways of storing this data. You could create a custom taxonomy, for instance, and then assign terms to each of those things. So each one of these photos could have one or more terms. That would be one way to do it. Let’s say for our purposes, though, we’re not interested in being able to group together photos based on something like a tag like that or a taxonomy. 

Instead, this list is really just for display purposes on the site. The trouble is if we hit the plus here, we make it a text field, well, then we only get one of them, right? And what if there are more? We don’t know ahead of time how many of these subjects a given photo might have, right? And that’s where the repeatable fields feature of ACM comes in really handy. So let’s see what that looks like. 

I’ll make this a text field here, and we’ll name it subjects. And then make this field repeatable. So this is key. We’ll go ahead and click that. And we’ll keep it as a single line text field, and hit Create. So just like that, our photo content model here has now been created. And we can see it in the sidebar. 

So if I click here on Photos, we’ll see that I have one dummy one I created ahead of time here. But if we create Add New, you’ll see that this reflects– the fields here reflect what we had added in the content model. So we get a title. We get the opportunity to attach an image. We have a rich text field for the description of the photo, and a repeatable field here to add one or more subjects. 

So let’s see what we can do here. I’ll click Add Featured Image. And I will choose one from my machine. Let’s see. And once that’s done uploading, we’ll give it some alt text. We’ll say, a white flower, like that, and done. So there’s our image. Let’s go back and give it a title, now, though. We’ll say white flower with bokeh. Just like that. For a description, we’ll say here’s a great shot of some pretty white flowers. Just like that. 

And now for our subjects, we can ask ourselves, what’s present in the photo here? And maybe we can– flower could be one. Click Add Item. And that bokeh effect, with the blurred background, is there as well. And the stem or the branch of the tree, I guess, would be in the shot, for another example. So we’ll add a few of those here. And if we think we’ve captured everything, you can go ahead and hit Publish. So there we go. 

And then back in photos, I had previously created this one. Mountains are cool. It should be set like that. So you get a mountain range photo. And then here’s a great shot of a mountain range with mountain, stars, shadows. A few subjects that it has. So that would give us at least a few posts to work with in our front-end application. 

So at this point, we have created our content model in the WordPress back end to store the data we need for these photos, and we’ve created two new photo posts for us to use to try to consume on our front-end app. And next, you might be wondering, well, how are we going to pull this data out of WordPress so that we can go use it in our front-end application? 

There’s a very cool feature that Headless WordPress Content Modeler shows off to make that very easy. So I’ll go back to Content Modeler here and find our photos model, and click the little ellipsis dot icon here. And I will go to Open in Graphical. So as soon as I click this, it will compose a query for me that includes this content model we created, photos. 

And it grabs the first 10 of those, and then it includes this GraphQL fragment below that has all of the fields we had created, including the custom ones. So if you’ll notice, we added the photo title, we had our image, we had the description, and then the subjects. So this is super handy for seeing what this data looks like in the GraphQL schema. So go ahead and hit this button to execute this query. 

And you can see what our front-end JavaScript app would get back if it were to execute this same exact GraphQL query. It would get back photos. And then inside of that would be an object called an array, called nodes. And inside of that array would be objects that look like this. Each one of these photos would have a title, an image, and then further down, the description and subjects as well. 

So this is exactly what we need. So we’re going to make use of several of these fields now. So we’re good to go, in terms of our WordPress back end and the ability to store and also expose this photos data. So now let’s see how we can use this in our front-end JavaScript app. 

So we’ll head back over there. And I think a good starting point for this would be to look at the Portfolio page, which is a list of projects, right? Since that’s a list of custom content model posts, and photos will be as well, those two pages have a lot in common. So we can use that as kind of a starting point. 

So I’ll click on Portfolio here, and just to remind ourselves what that looks like. And that’s like this, where we get this list of portfolio projects. So let’s crack open the code now and get our hands dirty a bit. We’ll track down this page, which is that slash project, and see how this is built. 

So inside of Source, I’ll go to Pages. And then I’ll find Project. There it is. And open up the index.js file inside of that. So scroll down a bit, and we’ll see that this use node pagination hook is being used. And this is a React hook that comes from this location here, inside of the Hooks folder. And inside of that, we’re calling query.projects. 

And query.projects is going to allow us to access data about our projects custom post type, aka our project’s content model that we had created. So we’re going to call query.projects and then pass in some fields that we want to process ahead of time, so that they’re as soon as the page loads. So that’s what this array is up here. So those fields are there on the very first load of the page. 

And then once we actually are ready to render the content of this page, we’re doing this. We have an SEO component, a header, and then a footer at the bottom. And then the main section of the page here is inside of this main tag, where we have the header, which is the blue section being pulled in. And then a wrapper div with our projects list inside of that. And then also this Load More component, which results in this Load More button at the bottom, which I can click. And then that fetches more projects and pops them into the UI. 

So that’s how that page is built. And like I said, I like to use this as a starting point for us. So let’s go ahead and copy this entire file, and we’re going to mimic this file structure here. So inside of Pages, we’ll create Photo. And then inside of that folder, we’ll create an index.js file. All right. And in this new file, I will paste in the contents. But we’ll switch some things up, since we’re not interested in projects data for this, we want our photos data. So let’s see how we can do that. 

So the name of this constant is referencing projects. So let’s go ahead and rename that as a first step. We can say photo nodes pre-pass fields. So that’ll be good. We’ll have to provide our own list of fields. Maybe we’ll just leave database ID for now, and then we’ll add some in a moment. 

Further down, let’s see. Photo pre-pass. Oh, the name got messed up. There we go. So now they match again. All right. Instead of query.projects then, remember, we want query.photos for our custom content type. So go ahead and update that to be photos, right there. Scroll down a bit. 

So this projects component, this will no longer apply, since we’re not using that. So I will remove that at this point and how about this? We’ll just have– we’ll just H1. It says Hello, just to get something rendering on the page here. And maybe we’ll comment out load more as well. 

So I’m going to run a search for project to see if there’s anything I forgot. Yeah, just a few code comments and then this component here that’s being pulled in that we’re not using anymore. So I’ll delete that component. And I think we should be good. So we’re not using a few of these things at this point, but that’s OK. We will momentarily. 

So I’ll give this a Save, and we’ll see if we can get that rendering. So now on our front-end app, I should be able to navigate to Photo, like this. And there we go. So here’s our new page. It says hello, and much of it looks the same as our portfolio projects page, like the header at the top and the footer. 

I notice it still says portfolio, and we probably want to swap that out. So we can do that real briefly. So here’s portfolio. We’ll say photos. And then also in this spot, we’ll change that to photos. Save it. There we go. So that updated the header. 

Now let’s dive into how we can actually use that data, fetch our photos data and display a list here. So where do we even start with that? As we saw in the GraphQL– or in the WordPress admin here, this is what our query is roughly going to look like. It’s going to have these fields. So let’s do that. So photo title is the custom field. But actually, since we set this field as the title of the post, we could just use title, since that’s going to be– the title of the post is going to be the same as the custom field with this name. So we could just use that. 

So in this array, we will do not only database ID, but we’ll get the title for our photos, image, description, and subjects. So let’s add those as well. Image, description, and then subject. All right. You’ll need commas at the end. There we go. So I think that’s all of our fields that we want to have available right when the page ends. So that looks good to me. 

And let’s test out if we can actually get some data rendering here. So under our Hello H1 that we have, let’s do this. We’ll do JSON.stringify, and then we’ll pass into that something. So we’ll do data here, and see if we can get data rendering to our page. 

So I’ll save that, and we’ll return to our front end. And there it is, sure enough. So this is kind of what the data looks like. You can see we’re successfully fetching it from our WordPress back end. We have this nodes array, and then inside of that objects representing each of our individual photos and exactly the data that we had asked for back, including each of the individual values for our repeatable subjects field here. 

So this is great. This is exactly what we need. Let’s make things a bit cleaner– well, a lot cleaner, I guess, than just spitting data out on the page like this. Instead of just this pre tag here, let’s map over each of our pieces of data and render a card on the page for this. 

So one thing I like to do is before we assume that we have posts to render, we have to account for the case that maybe there are none, right? So one thing I like to do is at the top of my components, I do const have photos, something like that. And then I do data.nodes.length like that. And we’ll do a question mark for optional chaining, because we don’t know if data will exist yet. 

And then we’ll cast this to a Boolean like that. So that means if we fail at this point and data is undefined, this will get casted to false. We’ll say, we have no photos to render. Otherwise, if we’re able to drill all the way down to the length of this array, it’ll be either zero, if there are no posts, or one or more. So if we cast that integer to a Boolean, it will tell us whether or not we have photos. So if it’s zero, this will be false. If it’s one or more, havePhotos would be true. 

So with that knowledge, then we can do some decision making inside of our component here. So let’s figure out how we can do that. So I’ll say, if we have photos, then we want to render one thing. We’ll say– let’s see. We want to do data.photos and then we’ll map over those. So for each photo, we will render something. 

So let’s just return something easy at first. We’ll return the– let’s see. We’ll make an H2, how about, since this is going to be like one of our cards. And then we’ll say photo.title like that. All right. So we’ll map over each of our photos. And for each of those, we’ll return an H2 with the title of that photo. All right. 

So all of this is what we want if we actually have photos to render. But what about the alternative, if we don’t? So we’ll have our else clause here, and let’s render something else. How about paragraph. And we’ll say, no photos to display. So now if we save it, there we go. So now we’re getting our post titles rendering out here. 

So let’s make this a bit more feature complete here. We’ll say we want to return something else. All right. And for each of these, I’ll copy in just some styles, some inline styles that I wrote ahead of time here, just to save us the time of typing those out. So I’ll have that wrapper div. And then inside of that, we can restore our H2 that we had. So I will paste in an H2 with the title. 

After the title, how about let’s show the description. We can do that one next. So that’ll be photo.description, like that. But we can’t just render it by itself, like inside of a container, for instance, just like this. If we try to do this, this won’t quite work for us, because the HTML won’t be escaped. So if I save that, you can see now we have the escaped HTML being shown on the page, which is not what we want. 

So React has a utility for working with HTML that is safe and doesn’t need to be escaped like this. And that is to use div and then dangerouslySetInnerHTML like that. And you can pass to it an object where one property is double underscore HTML. 

And then the value you pass to that is the thing that you want to render without escaping. So for us, that would be photo.description, just like that. And then this div can be self-clothing. All right. So now I’ll give that a save. We’ll see what we get. Cool. So now our HTML is not being escaped any longer. So it looks good to me. 

So this is great. How about that featured image? What we could do is write this from scratch. We could grab the featured image URL and have an image tag and pass that in as the URL. And then the browser would render an image and point it to that source. 

However, this project, if you dig into this blueprint code base, actually has a prebuilt component exactly for this purpose called featured image. So for us that would be perfect for us to use. So I’ll scroll up a bit to where we’re importing a bunch of different components from our components directory. And I’ll tag one onto the end here called featured image, just like that. So now we can render our featured image wherever we want it. 

Right under where this div is with our photo description, we’ll render our featured image. And this requires an image prop. And what we need to pass in here is the whole node for this image. So for us, that would be photo.feauredimage.node, just like that. And I think that should do the trick for our image. So I’ll save it, and sure enough, here we go. So once our page reloads here, now we have our title, our description, and then the photo itself being displayed. And likewise, for our next photo as well, that image is being shown on the list. 

So this is cool. We’re making great progress. The last thing was taking care of our repeatable field for the subjects present in the photo. So what I’ll do is I’ll create a paragraph here and close it out. And then inside of this paragraph tag, we can pop open some curlies and do our same photo.subjects. But now we’ll tack onto the end of it join. And we’ll tell [INAUDIBLE] we want to join it by a comma, space, just like that. And I will give that a save. 

When our hot reload happens, I should be able to scroll down. And sure enough, there we go. So they’re being shown on the list. The user might not be sure what those are. So maybe in our app, we can pop back over and add a label of some kind, a little preceding thing there that says Subjects maybe, like that. Subjects flower, bokeh, branch. And then our other photo here has subjects mountain, stars, shadows, just for an example. 

So we’ll pause here, but you can see how quick I was able to put this page together. I guess we should get rid of our hello, world on top there. We don’t quite need that. Or hello word. So I’ll remove that. There we are. So you can see, as I was saying, how quickly we were able to put this together. 

Just kind of basing our code off of the portfolio list page, we were able to create our photos list page here and then map over each of the individual photos and access the Headless WordPress Content Modeler custom fields for it– the title, description, image, and then our repeatable fields for the subject here. So I would love for you to feel empowered by this on your own projects. 

If you want to take one of our blueprints as this huge head start that can get much of your project done for you, a lot of the legwork done. And then from there, you can do something similar to what we did in this talk. You could customize it further and add your own customizations and other content models and so on. 

Thanks so much for watching. I hope this talk was really useful and gave you a good sense of all of the great features that have been coming out and will continue to come out in the Headless WordPress ecosystem. 

PRESENTER: And that is a wrap for DE{CODE} 2022. I hope you found it inspirational and are leaving with more WordPress expertise and new community connections. Look out for the recorded content on the site from Friday to catch up with anything you may have missed or watch a video again. 

I want to say a final thank you to our sponsor partners: Amsive Digital, Box UK, Candyspace, Drewl, Elementary Digital, Illustrate Digital, Kanopi Studios, Springbox, Studio Malt, StrategiQ, WebDevStudios, and 10Up. A massive thank you for donating to our DE{CODE} fundraiser. We really appreciate your generosity. 

Now, for everybody that has been interacting with us in our attendee hub and our sessions, we will pick the top three winners and let you know how you can claim your prize at the end of DE{CODE}. We look forward to seeing you again at our future events, either in person or virtually. We can’t wait to bring you more on the latest WordPress development trends and how you can implement them to build WordPress sites faster. 

That’s all from me. Thank you very much for joining us, and take care. 

Get started

Build faster, protect your brand, and grow your business with a WordPress platform built to power remarkable online experiences.