When working with Headless WordPress it can be daunting having to setup an e-commerce site. This workshop will take you through connecting a Shopify app with your WordPress site, linking your WordPress content to your Shopify products, building a React and NextJS frontend to show your products and posts, using Yoast SEO, and deploying your site to WP Engine’s Atlas platform.
Workshop: Mixing Content, Commerce, and SEO with Headless WordPress
AI Generated Video Summary
Headless WordPress allows developers to build the front end using React frameworks like Gatsby or Next, bringing WordPress into the modern development age. The integration of external APIs with Headless WordPress allows for a mix and match approach, using APIs directly or pulling data through WordPress. The project demonstrates the use of Reactaits for state management and the implementation of SEO using Yoast. The workshop also covers the process of retrieving post data, building product cards, and adding products to the cart in a Headless WordPress and Shopify integration. The session concludes with resources for further learning and community engagement.
1. Introduction to Headless WordPress and Setup
Welcome to React Summit! In this session, we'll discuss Headless WordPress and build a site that combines content, commerce, and SEO. Clone the repo, check out the start branch, and delete the Git folder. We have a lot to cover, so let's dive in. I'm Matt Landers, head of developer relations at WP Engine, and Will is a developer advocate. We run the Decode podcast, have a Slack for headless WordPress, and a YouTube channel. This session is more prepared, but we may make mistakes. Now, let's talk about our setup. WordPress is a monolithic system where content producers log in, and we have a WordPress instance set up with Star Wars-related posts.
All right, hello and welcome to React Summit. If this is your first session, welcome, glad to have you. In this session, we're going to talk about Headless WordPress. And specifically, we're going to build a site where we mix content, commerce, and SEO into one site. So, it's going to be fun. You can code along if you want to code along, follow these instructions. Just clone the repo here. This is also in chat and in Discord, so I'd encourage you to be in one of those. There's chat for Zoom and chat for Discord. We're watching both of them. So feel free to ask your questions there. But pull down this repo, just clone it and then go into the folder. Check out the start branch. It might be the default branch for you. I'm not sure how that will turn up. But then go ahead and delete the Git folder to remove it from my Git. So you can put it in your own Git and save it for later. All right. So if you have any questions on that, feel free to ask chat and Will will help you out.
All right. So let's dive into what we're actually going to be doing here. We do have a lot to cover so we're probably gonna go pretty quick here because we're building out not a full fledged site, but it's a lot of functionality. Yeah. I guess we should intro into who we are first. People use these live sessions every Friday. So we're used to just jumping in and starting to code. But I'm Matt Landers. I'm the head of developer relations at WP Engine. And WP Engine is a managed WordPress host. You've never heard of us. And we recently launched a new platform called Atlas which allows you to host your headless WordPress sites. So my team is totally focused on headless WordPress. I'm just making, giving developers good content and educating you on how to build great headless experiences. And then Will is on the team. he's a developer advocate, and I'll let you do a little intro yourself.
Yeah I'm a developer advocate at WP Engine. I help create content and get people started on headless WordPress and on the Atlas platform. And I'm also, Matt and I also run the Decode podcast. So every every Monday a new podcast comes out. When you download the repo you'll get a link to that. You'll also get a link to our Twitter account and we have a Slack for anyone who's interested in headless WordPress. There are people in there asking questions about how to get started, talking about different libraries that are useful when you're using headless WordPress. And then we also have a a YouTube channel where we post some videos, walkthroughs of things, and we also do live coding sessions like this one every Friday. Right. Those are fun. This one we're far more prepared for. If you've been to our live sessions, you would literally go in them unprepared, and it's like a hot mess, but it's fun. This one we have coded previously, so we should know what we're doing. With that said, we will probably make a lot of mistakes because it's a big site. Yeah, we at least have a reference point here. Typically on Friday we come in and we don't know what we're going to build, and so we just build it along the way. We have built this, so we can refer to some code. At the worst case scenario, we can just pull it in. It is already run. Alright, so I want to first talk about our setup. So in Helix WordPress, just a quick overview. If you don't know what that means, WordPress generally is a monolithic system, in that it's the place where your content producers and publishers will log into. WPAdmin, like this, that you can see right now on my screen, where they'll log in and they'll make posts. So we have a WordPress instance already set up. We have all these posts that I've already put in here. I'm a huge Star Wars nerd, so everything is related to Star Wars. Hopefully you can enjoy that. If you don't like Star Wars, you can leave now. No, I'm just kidding. You can stay. It's fine. If you're a Trekkie, you can leave though. We're starting the nerd wars over here. But yeah, so how does WordPress, or WordPress generally, you would, WordPress would also be responsible for rendering the site. So there's themes and ways you can write PHP and HTML and CSS for WordPress to be responsible for rendering out the posts, rendering out all the pages and everything like that as well.
2. Headless WordPress and Setup
Headless WordPress allows developers to build the front end using React frameworks like Gatsby or Next, bringing WordPress into the modern development age. It provides the freedom to use familiar tools while connecting to a WordPress backend. Essential plugins for headless WordPress include WP GraphQL for optimized API queries, custom post type UI for structured content, and Yoast for SEO. We'll build an eCommerce site that combines content and commerce by creating relationships between blog posts and Shopify products using tags and collections. The finished site will have a homepage featuring featured posts and a fast, interactive interface.
But if you go headless, you remove that from WordPress's responsibility and it allows you and gives you as the developer the freedom to build the front end however you want. You could build the front end with Gatsby or Next or any of these awesome React frameworks that are out there. Of course, this is a React conference, so you would only use React, you wouldn't use anything but if you were so inclined to there are other frameworks in the JavaScript ecosystem that you could take advantage of as well.
So that's really cool. So it allows you to bring WordPress into the modern development age. So I think a lot of people when they think of WordPress don't really think of WordPress as something that you would use on a modern site but with headless it's just another API for you to consume from the front end which is really great because your users probably already have experience in the WordPress admin, like what you're looking at right now. Yeah I mean I think I personally love, in the past I haven't enjoyed working on WordPress sites in the monolithic sense but since I've moved to creating more headless WordPress sites, it's a lot more enjoyable. I can use the tools that I'm used to when I've been writing apps and doing other things but I can connect it to a WordPress backend which the people writing blog posts are very thankful when they can use the WordPress editor to write their posts. Yeah in the past we have built systems where we forced our content producers to write Markdown and that's, they don't like that it turns out. They don't like that. Yeah but one thing to note too is like Will and I and either one of us are php developers can we get in and hack around some php? Sure but we don't, we've never done php professionally. So we are front-end Node react developers and we're able to use Headless WordPress and make it a powerful platform for us. So hopefully in this talk you really can start to realize the power of that and what you're capable of doing.
So the first thing that I always do when I start to build a headless site is I have a set of plugins that I like to install. We're not going to use all of these in this talk but I want to go over what they are and how they can be useful to you. The first one that you're going to want is WP GraphQL to me this is like table stakes for Headless because the rest API for content with all the relationships that there are just is leaves a lot to be desired to say the least. Like you don't need all the fields on every page. You also have relationships that you want to pull back and you don't want to have to make multiple calls. With GraphQL we can bundle up what we need for a page and get that all in one request which is really nice. Yeah it helps the front end and it also on the under the hood on the WordPress side it helps GraphQL knows exactly what you need so it can make an optimized query to get what you need. Right and the guy who wrote this Jason Ball he writes, he works at WP Engine. He has a great demo that he shows me of a site that he's worked on where he tries to pull back some posts using the API and it takes like 10 seconds. You pull it back with WP GraphQL and it's 20 milliseconds. So it really does speed up your API significantly. All right so that one you gotta have. And then there are some things that you might want on top of that custom post type UI allows you to create structured content. So if you're used to working in another CMS like GraphCMS, or Content Floor, or something like that. When you log in you're used to creating your content model like your your content types. This will allow you to do that in conjunction with advanced custom fields. We're not going to create any custom content types in this talk, but if you go to our site developers.wpengine.com, we have lots of content on how to use these to create structured content. The other thing that we're going to use is Yoast. So Yoast is typically something you would use in a traditional WordPress setup, but there is an extension for WPGraphQL that allows us to pull that SEO content out of WordPress and get it onto the screen with some help from some stuff that Will has written that we will share here. So you can add, so then your content producers can go into their posts like this. I can show this off. If I go to a post, and I scroll to the bottom Yoast shows up here and I can put in things like keywords and a description, and all that kind of stuff. And then you can pull that out with GraphQL and then we can use that for our SEO on our front end. Alright, what other ones do we need to talk about here? There are extensions for custom post type UI. Actually custom post type UI extension you don't need any more. It's built into it for WPGraphQL. And then you would want the WPGraphQL for ACF if you're doing that structured content, but we're not going to use that in this particular talk. Right, so now let's talk about what we're actually going to build. We're going to build an eCommerce site that mixes content with commerce. And what we mean by that is that we're going to build relationships between our content. So our blog posts here, and products that we have in a Shopify store. And the way that we're going to do that is through tags. So if we go to a post we have these tags on the post, like here. It's a collection dash return of the Jedi, so our different tags are related based on the original trilogy Star Wars. So we have a New Hope, Return of the Jedi, and Empire Strikes Back. And then on the Shopify side, if we go over here. We also have all of our products, so these are stickers. So we're building a store where we have blog posts that are about Star Wars, and then each post can be related to stickers of characters based on that movie that the post is about. All right, and then the way that we're making this relationship is that we have these collections. So we have a Return of the Jedi collection and Empire Strikes Back and a New Hope. So based on the collection that the products are in, it's like here we have Return of the Jedi, we have Chewie, Wicket, which is my favorite Ewok, and C-3PO. So these will be related to any posts that have Return of the Jedi as a tag. So we come back over to our WordPress site and so this particular post is about Ewoks and it is tagged with Return of the Jedi. So we're going to build a front-end site where we pull in this post, then we find all of the products that are related to it and we show them on the screen at the same time. And then if we view a product, we want to also show all the blog posts related to that product. So we kind of intertwine our content and our products that we have. So that's kind of the goal of what we're trying to accomplish here and to make that really, really concrete, I'll go ahead and show you what the finished product looks like. And it's not the most beautiful thing in the world that you've ever seen, but it is fast and it's awesome. But here is the site that we're going to build. What you have right now that you've cloned does not look like this, but we're going to build this up. So we have a homepage where we show our featured post. So I'll show you how that works as well. So if I go over to our WordPress, we are able to add a category here of whether or not they're featured. So if they're featured, they'll show up on the homepage. This particular post isn't featured, so it's not showing up. But if they're featured, they'll show up here. And if we can click on that post, we can see that that static and it's super super fast.
3. Integration and Functionality
You can see our posts and the related products. Add products to the cart, view the cart, remove items, and proceed to checkout on our Shopify site. The site is functional and has potential for a designer to enhance its aesthetics.
You can see our posts and we see all of the products related to that post. And if we view a particular product, we'll see all of the posts related to that product. So that's cool. And then what we can do is we can add these to cart. And then you can see that as we add them to the cart, they are updated up here and we're using state management to do that with another thing that will create a company, which you've definitely never heard of, but happy to show it off here. And then if we click on our cart, you can see all of our products that we've added to the car, the quantity, we can remove them from the card and that'll update and then click checkout and that'll take us out to our Shopify site where we have a secure checkout experience and then there's all of our stuff and we can continue to put our information and buy our products. So while the site isn't the most beautiful thing you've ever seen, it is very functional and you could imagine how a designer could get ahold of this and make it pretty awesome.
4. WordPress and Shopify Integration
In WordPress, we're using tags to associate blog posts with products in Shopify. We'll show these on the front end using React and calling APIs from Shopify and WordPress. The Shopify API has a GraphQL API endpoint, and we've built a small API in the repo that works with it. The services file contains functions to make calls to the Shopify API. We've imported all the queries from the queries file. The actor file handles our state using taits, which is a library for global state management.
So just to quickly recap what we're gonna use, in WordPress we're using tags to associate blog posts with products in Shopify that are in specific collections. So if we go to our collections here and then we're going to show those on the front end using React and calling these APIs from Shopify and from WordPress.
Alright, so let's take a look at the Shopify API. We showed a little bit about the GraphQL API in WordPress which I guess we haven't shown. But you can come in here and we can pull back posts. We'll show this first. So this is cool. If you install WP GraphQL you'll get this IDE for GraphQL and you can come in and just like select some fields that you want to see and run that and see what it'll look like. Which is cool. So we use this to go build our queries and then we put those queries into our code for later and all the queries are in your code right now because I didn't want everyone to have to type those out. I thought that would be a little extreme from a Forward follow. You would run into a lot of issues, so we've already got all the queries you're going to need, but we will go over what the queries do and how they work.
Then on the Shopify side we're going to use the storefront API which is also a GraphQL API endpoint. Yeah, I think it's so Shopify has a JS SDK, but we are TypeScript fans and the JS SDK doesn't have great typings for TypeScript. So we, in the repo that you clone, we built a small API that works with the GraphQL Shopify API and provides you the content you need. So if you were going to expand this to include your own site, you can go in and edit the queries and expand it to what you want. All right, so let's look at that really quickly as well.
So the way that we're making the Shopify calls, which we've already got built out for you in here, so we're not going to build these from scratch, this is already put in a services file. So if you're in the project, let me close node modules here. You're in the project and you come down to source, lib, state, and then Shopify, you'll find a services file. In that file, we have, we make all of the calls to Shopify using the Apollo client here. We have our token here so you can use our store that we're going to use. This is already in here. The one thing that you need to do to set up that I didn't actually make available is you need to create a dot env dot local file and you need to have these things in it. I actually didn't add this. So let's share this in Discord. Yeah, I can, I'll copy it everywhere. Okay, cool. All right, so what this does is it tell we're using a framework that we created at WP Engine. It's an open source framework to handle our Apollo connections to WordPress, and this is just an environment variable that gets set and tells you what WordPress instance to use. You can use the one that we're using as well. So in the pre-writes we had that you needed a WordPress in a Shopify store, but you don't. You can just use ours, and then later on you can go create your own if you want to. You don't need a secret because we're not going to do previews. So you can just leave this as just whatever like this says we're not going to get into this framework too much. But just know that it's handling some of the Apollo stuff for you specific to WordPress. All right, so you'll need that. The the Stripe or the Shopify stuff is built directly into the services file. You would want this to be an environment variable, but we didn't worry about it for the purposes of this just so that we can get moving along. In here, what you're going to see are different just functions that go out and make calls to the Shopify API for us. We've imported at the top here, all of our queries from this queries file that we have here. So all of the Shopify queries are in this file. And we have a Git product which just knows how to talk to Shopify and get a product by the handle. We know how to create a checkout. So that's how we create the cart. They call it a checkout. So we call it a checkout. So our terminology isn't necessarily cart and code all the time but checkout in the code actually, refers to what you would probably think of the shopping cart. And then we have get checkout. So anytime we add items to our cart, we can use Get checkout to go get the updated version of that. We have add line item, which allows us to add an item to our cart, remove line item, which will remove an item from our cart, get products by collection. So this is really important for when we're trying to make these relationships to our content. So we can pass in a collection handle like return of the Jedi, and then that will pull back all the products that are related to that collection. Yeah, and something I'll point out here, if you're unfamiliar with GraphQL and how it works, Shopify also lets you install a graphical editor similar to it's basically the same thing that you get out of WordPress with WP graphical. And you can it's a little playground that you can use to get these queries. And that's what we've used. So you don't have to be an expert at GraphQL to get this to work. Right? Yeah, all of those are available on the Shopify API. When you install it, you'll get a little editor like you saw for WordPress as well. But we didn't want to be we didn't want this talk to be about how to deal with Shopify. So we kind of took that away from you because we spent a lot of time making that work. All right. So the way that this works is these are available in this service as file. So we can call these functions from wherever we need them in our React code. And then we also have this actor file which handles our state and this uses taits, which is a library that we'll create it to handle global state and will since you are the author of this beautiful framework why don't you tell us how it works.
Yeah, so there are actually two libraries. There's taits and then there's reactaits. So since this is a React app we're using React extension for taits. Under the hood, taits uses the proxy API to essentially give you a state object that you can subscribe to and receive updates every time it's a value on state changes. So it lets you subscribe to a specific path.
5. Reactaits and Project Structure
Reactaits helps with state management by providing useful functions that create hooks. It simplifies the process of subscribing to and receiving updates. The use checkout hook is used to receive updates when the checkout value changes. It is a cleaner alternative to using useEffect and subscribe methods. Reactaits is simple to use and provides a consistent API with Shopify. The project structure includes source, lib, and pages folders. The layout component in the components folder provides structure and SEO functionality. The navbar is updated automatically when the cart is modified. The homepage, cart, and post pages are stubbed out. The featured posts query pulls back the title, excerpt, and slug. Emojis can be used in URLs, which adds a unique touch.
And then any time somebody changes that path, it will let you know when that changes. So it's similar to how Angular and other frameworks work, but it just helps you with state management. Now, what reactaits does is it publishes a couple of useful functions that lets you create hooks. So it kind of turns the sort of subscribe and receive updates into a hook. So you can say, yeah, in ours, we have one hook called use checkout. So this is a way where a component can say, hey, I want updates any time the checkout value changes and it makes your react component a lot cleaner. It just uses a simple hook and it doesn't have to do a use effect and then call the right subscribe method and invoke the right function and all of that. All that's handled within reactates. All right. It's really cool. Super simple to use, too. I like it. So we use checkout really is use cart again, but we just went around, we're just using the Shopify terminology to keep it consistent with their API. Not sure why they didn't call it a cart in Shopify. That's their decision, not using TypeScript for their NPM module. Yeah, I do believe they're moving to TypeScript, but it's just not ready yet. Right. Okay. All right. So we also have some components. So whenever I set up a React project, this is usually what it looks like. I use Next primarily. I have a source folder and then I have a lib folder, and obviously you have a pages folder if you do Next. If you've never done Next, Pages is how you do routing. So it does file-based routing. So in here, index will be our homepage, these with these brackets will be dynamic pages. So the slug page will be our post page, where we see an individual post. And then the product slash handle will be our product page where we can see an individual product. And then under lib, we have components and state and our SEO component as well, which we'll get into later. In components right now, the only thing that we have in here is our layout. So this is providing that SEO stuff for us and also just providing us a container to put our children in. So, whatever our page our pages will be wrapped in this layout component to give us some of the structure for us. And it also already has the nav bar associated to it. The navbar is using that is using that hook that we just saw in this, the actor file. So whenever something is added to the cart, this use checkout will update and the navbar will automatically update. So no matter where we are in the app, if we update the cart, the navbar will be notified of that and update accordingly. Alright, So that's that's pretty much all that we have set up right now. So if you run this as is, there's nothing in here, the pages are stubbed out for you. So let's go ahead and look at what we have. So if we're running this, we just have the home page here. If we go to cart, it just says cart, we can go to I don't know, this will probably set 404, but I don't know, take us to a single post, because we don't have... it's doing the fallback method, I guess. Yeah, we will get 404's later. So we're gonna build this out. So the first thing that we're gonna do, we're going to start kind of like let's get the bare bones thing up. And that would be let's get the homepage showing. And then let's allow you to add something to your cart from the homepage. And then go view your cart and go to checkout. So we'll get the whole thing working. And then we'll add in some of those ancillary components like a product page and a post page. All right, I'm gonna shrink this down. All right. So the first thing that we want to do to get started here and feel free to ask questions, if something's not completely clear. All right. So the first thing that we're going to do to get started here is we're going to pull back our featured post on our homepage. So we're on this index.tsx file, we already have already all of our imports in here, so you don't have to worry about that. But you can tell the stuff we haven't used yet here. The stuff that's gray, grayed out what we're going to use. We have our query. So let's go ahead and pull this query into our IDE in WordPress. Already have this open over here. Make this bigger. All right. So I just pasted this in and we'll run it and we'll see what we're going to get back. So this is the query that we're using for our featured posts. So it pulls back the title, the excerpt which you can see is actually just raw HTML. So we need to make sure that we handle that. Our slug, which by the way, this is awesome. I had not realized this until we wrote this, but you can have emojis in your URLs, which is amazing. So if you come over here and you click on this, there's an emoji in this URL, which I thought was, I've never seen anybody do that, but I hope that this talk encourages everyone to use emojis for every URL.
6. Retrieving Post Data and Using UseQuery
We pull back the post and its related tags. The call is made using the get static props function. The headless framework handles the Apollo client setup and caching. We use the client to make the query and await the data. The data is returned to the client in the expected structure. On the front end, we use UseQuery to make the same call and retrieve the data.
All right. So that part is pretty cool. So we come over here, we get our title or sir, we get our slug. So we're going to use that for where our posts should show up for whenever we're using the full post. And then we also see all the tags related to it. So we need these tags to know what products to pull back for that post. Yeah. And we also, if you see there, it has a search and it says it's essentially saying only return the tags that have collection dash in front of them. So you might have other tags on your posts that aren't related to Shopify. But for this, for the purpose of this talk, we're trying to relate the post to Shopify items. And we do that through a pending collection dash to the collection name of the Shopify collection.
All right. So this is the call that we're going to make. So the first thing we want to do is just pull back the post. We won't worry about products for now. So let's just get something on the screen. Let's do some coding. All right. So we're going to build all these pages as static. So they're super fast. So we, first thing that we need since we're using next is a get static props. And we get a context from that, which we'll use our get static props context. And we'll, we'll keep me on track here, hopefully. All right. We're using a headless framework that we built at WP Engine. And that gives us our Apollo client already set up. And it does that by wrapping our entire app in this headless provider, this headless provider knows to look at those environment variables that you have to get the connection string to the GraphQL for WordPress. So all of that is already handled for us. So the Apollo client is created, it handles caching that on the server versus the client so On the server versus the client so that you won't double your calls up. So if you make if you do an SSR, let's say you might make the call on the server. And then you also might have a hook that makes the same call in case you're doing client-side routing on the front end. It prevents you from making that call twice. So it'll take the Apollo cash and push it down to the client, which is really handy. In this case, we're going to do a static site so it's not doesn't matter. But it's already set up. So we need to get our client. So we're gonna say const client equals get Apollo client. Well, not Gert early, and we pass in the contest there. And we can use our client to make that query. So we'll say client query. And we'll make the query with our featured post query here. Yeah, and we don't have any variables that we need to pass in. So that should be good. And then we need to pull out the data from this, and we want to await it. So ran an async method, we can await this and use a sink away. I said this data is going to come back in the structure that we have in the query. So it's going to be post nodes, and then all the data that we need. So we want to return that to the client. So we want to return. This is how the client is expecting it to, this is expecting... You want to return the get next static props, right. So we're going to use query on the front end. And we're going to have, so just up front, we'll want to use the wp engine headless static props function, right. We'll pass it in with the props. All right, well, so that's post products, right? So where post products relates the post to the product in Shopify. We're not going that far yet. You're not doing that yet. True, true, true. So I start, you want to do the get next static props, right? So part of our framework is that we have git net static props, which this first we just make sure we take that cache that's on the client and we push it down to the browser. That's all that this is doing for us in this case and then we're going to return, you want to return the result of that. Yeah. Return the result of this. Yeah, exactly. All right, cool. Yeah, so that's just going to bundle up the Apollo cache, assign it to props and then it will be returned from the front end. And then on the front end, it will be restored, put on context, and so you'll have the right Apollo client with its cached, featured posts on the front end. Right, so now on the front end, we can use UseQuery. So we'll say const, what is it? Same thing, right? We get data out. Yeah, and we just say UseQuery. Yeah, it's important to make the same call, you make the same call on the front end as you do in GetNextStaticProps and what that means is you use the same GraphQL.
7. GraphQL Call and Adding Style
We define the query at the top and use the exact same query on the front end and back end. Apollo grabs it from the cache. We get our posts from the data and map them out using React. We made a GraphQL call and used the WP Engine headless framework provider to restore the Apollo cache. We can now add style using bootstrap and dangerously set inner HTML for HTML excerpts.
And that's why we've pulled out the query up here at the top. So we define the query at the top, and then we use the exact same query on the front end and the back end. And this way Apollo is able to grab it out of the cache. Right, and now we have, we can get our posts out of this as well. So we can say data dot, what is it? Yeah, so I'll go ahead and, yeah. posts dot nodes. Yeah. And we're not going to have this home here, so we're going to go ahead and, okay. We're using a VS Code live share, so we'll add. I'm going to put in the typings because I'm a stickler. Yeah, and that means that now we have the typings here. If I were to type this here, we can actually see. What's part of these objects. Cool, so that gives me the post. And now what we want to do is we want to have a component that will show all these posts. So first let's just go ahead and map these out. So we'll say post dot map. Here, just so that TypeScript doesn't complain to me, even though we know this is never going to be empty. I'm going to say that it's an empty array. If it is empty. Then we'll do post and then we'll just for now, output an h1 which I'm. And then post dot title. Is that right? Yes. Yeah. All right, so. But you have to do it. You have to like put it in brackets. Right? This is React. Yeah, this is React. So I'm gonna do React. I have coding time man. All right now we come back over here. We run it and look at that. We have stuff on the screen working all right so we made our GraphQL call that seemed pretty simple Meta GraphQL call, she didn't get static props in our query here. This is actually not gonna make a query when we call use query it's just gonna pull the cache that we already made in our static props. That's confusing I think Will has a blog post on that. Yeah and the simple gist of it is the WP Engine headless framework comes with a provider and we use that provider in the underscore app.tsx. We call the provider and wrap our all of our page components in it and it goes ahead and recognizes that there's an Apollo cache in props and it restores the Apollo cache uses the Apollo provider and then it's like your any normal application where you've set the Apollo provider. And then you can use use query in any component underneath that so it's I think it uses context on the on its side. All right. That's when we wrap it in that headless provider. All right. Let's go ahead and add some style into this. So we're using bootstrap. I didn't talk about that part, but we're pulling in a global CSS reason bootstrap. I realized bootstrap isn't cool anymore but I know bootstrap really well. And so we're gonna use it because it's easy for me to do live. I was gonna use chakra and I started it last night and it's like, I can't. My first time using chakra isn't gonna be when I'm live coding. We can save that. You can use chakra in one of our live coding sessions so we can struggle through it. Yeah, exactly. We need to dangerously set inner HTML here because the excerpt that we're going to show is going to be HTML and not just raw text. Technically we need to do that for the title too? I don't know. I don't think so. No. All right. So now if we save that, we go back and now we've got our text on the screen. So this is awesome. We're making some progress. We've got our blog showing with the excerpts. Now let's add a link in here. So we would want, actually, let's go ahead and export this to its own component because we don't want to clutter up our homepage. So I'm going to refactor this. Can you do this this way? I extract it here first. All right. Cool. I'm going to copy this out. We're going to create a new component called post header. We're just going to make this a simple pure component.
8. Post Header and Linking to Blog Post
Post header component is a simple pure component that requires the 'post' prop to be passed in. The 'post' prop should have types defined. We use the 'post header' component in the home page and pass in the 'post' prop. We add a link around the H1 to link to the blog post. We import the 'Link' component from 'next/link' and use it to wrap the anchor tag. We now have links that go to a single post page. We also plan to show related products below the featured posts by extracting the row component and adding it to the main file.
Post header, keep me honest. Maybe you want to add the typings in there? Yeah, I'll do that. All right. So we just copied this over. Now, this is a very simple component. We'll just copy over these typings that we have. They're not 100% required, but this is how we like to code. We like typings. We like TypeScript. We like typings on our props. That's right. A post could be undefined. It really couldn't be. We need to set these to be. You have to send them in. All right. Cool. All right. So that's our post header. Then we're going to do export that. I'm not sure if I need to export it in default, but I'm going to do it. I don't remember how I imported it.
All right. So this is just a simple pure component. Now let's go back over to our home page and use that component. Instead of this new function that showed up here for some reason, I'll let you use post header. And it has...must have pulled something wrong. You have to pass in the post. You have to pass in the post. Yeah, it's not showing the types though. Why am I not getting types? Let's see, we have post there. Oh, that, that'll do it. Or not. I don't know where the... Oh, post is right there. But I don't know why it's not blue for me. All right. So we're going to pass in the post and should be good. No, we're not. So you need to, I need a bracket to close it out. Yeah. Goes here, right. Whoops. There you go. And that's my will is here. All right. Now we come back over here. We're good to go. All right. So now let's make it a little bit nicer in here. We're going to, we're going to have a link around this H1. So let's do that is we want to link to our, to the blog post. It will go to post that slug. I think I got to add this like, yeah, you want slash in there, just like won't have a slash by itself, starting to add that in. I wouldn't want to import this touchscreen may or may not tell you about it, but it's not for me. So I'm going to import that from net slash link. And then we need an anchor tag here as well with the exact same thing as this. And we'll wrap that here. All right, cool. We saved that. Go back over here now we have links. It goes to a single post page, which we haven't built out yet, but we're getting closer now.
All right, so now that we have our featured posts, we want to also show the products that are related to the featured posts below, below these. So let's do that. All right, I'm actually going to extract the row out of here. Maybe, maybe we'll see. Actually, I am going to do that. Yeah, I want the row to be I would take the row and the column out, right, and then just have this be a div that you put in and put the row and the column in the main file. For now, I don't know. It's outside the grid.
9. Fetching Shopify Products for Posts
We need to go to Shopify and pull back the products related to the post. We have a function in our server that allows us to get products by collection. We create a post variable and grab the posts from data.post.nodes. Then, we iterate through the nodes and call get products by collection, attaching the products to post products. The key for the post products is the post slug. We check if we have posts and safely map through them to get all the products for each post. This is an async call.
Yeah. All right, bootstrap things, bootstrap things. All right. That's just a simple little thing change there because I'm going to put the we're going to have product cards in here that we're going to use. All right. Okay. So now we need to go to Shopify and pull back the products related to the post, which is going to be fun. All right. We have a function in our server. That allows us to get products by collection. So we're going to make this call and we're going to pass in the handle, which if we look at our data dot post dot nodes dot. We're going to grab the first one and grab tags. You got the first tag. That right tag nodes. Well, so there are a couple things we have to do here, right? Think about think about how we have this we have multiple posts. And for each post, we need to go and grab the tag off the post. Right. And then make a call to get products by collection. Right. Right, so let's go ahead and create a post variable here. And we're going to grab the posts from data dot post nodes. Yeah, you're also the pose. You're also going to want to create the post product. So something like this, we'll have two coders, something like this, so that this way you can have the, the post products object, yeah, the key value. And you can now iterate through all of your nodes and call get products by collection, and then attach the products to post products. Right. And our key is going to be the slug right. The key is the post tag name, right? Or yeah, the key the key of that. Yes, I think we want to use the post slug. That way on the front end we can say post products as the slug and we'll have the list of Shopify products that are attached to our post products. So I think the way that the way that I would do it in here is I would first check if we have posts because, you know, we might not. And then after we know that we have posts and it's post nodes, we can safely map through them all. Right. Yeah. OK. So you're good there. OK. So now we want to go get all the products for the collection for each post. Yeah. And this is going to be an async call. Right. Right. So, I need to. Yeah. Waited enough. All right. And let's. OK. So it's saying that the tag name could be undefined, which we know based on our data, it's not, but it technically could be. So we're going to check and make sure that is this. So we'll just say if post or we'll grab the tag out, I guess, first, let's just grab this. Yeah. And then if it doesn't exist, do nothing. Right. All right. Cool. Why is this complaining? Object is, oh. Post can't be undefined, but nodes could be. Where is it complaining on here? Oh, there it is. Yeah. All right. Okay. Whew. That's hard. There you go. Yeah. TypeScript. TypeScript. All right. Cool.
10. Building Post Products and Product Card Component
We grab all the products and add them to our post products. We build a cross-reference table of slugs or posts and show the related products on the front end. We create a product card component to display the image and title of each product.
So this will just make sure that our tag is defined. If it is defined, we're going to go and grab all the products. So we'll say cons products here. And now we should get this typed. So this will be of type products. And then we want to add that to our, um, to our post products, right? So in here, once we get our products and we're awaiting that, we will, uh, say post products dot, um, or we're going to do like this and say, uh, post dot slug, whoa, equals, um, products, products. Here we go. Another TypeScript thing I had to cast it to a string just to satisfy those types. Um, and then we're good to go. So now what we're doing is we're building this basically a cross reference table, hash map of, um, our slugs or our posts that come back and we're keying that by our slug, since that's unique. And now on the front end, we can loop through this and show the products, um, related to each post. So let's do that. We need to send this back though. So we need to say, uh, result that props that, uh, post products. Yeah. Like that. So that'll make it to our front end and be passed in here as our props. Hopefully that made sense. I think we got it. I think we got it. Alright. Now what we want is we want to have a post card as a component that we're going to use on multiple pages, but we're going to need that now. So let's go ahead and just create that. We're going to create a post card. And we will do similar things that we've done already. So be a pure component. That will bring in the types again. Yeah, that's sure. And this component is just going to be a card, bootstrap card, that shows the image. So I div dot card, dash image top. And then we'll show the image that comes through, so it's going to pass in a product. Right. Now this should be- This is your postcard, right? That's a product card. Post in here. Oh, you're doing the product card. I did it. Yeah, alright. Name that's wrong. You called it postcard. We're doing a product card, not a postcard, because now we're going to show these products underneath the post. My bad. My bad. Exactly. Alright. Now you get the types in here. Alright, cool, cool. There we go. So we're bringing in a product. We're also able to pass in some styling here if we need to. So I'm going to do that here. What I'm going to do is have a template string, where this is always a card, but it also might be, it might pass in a class to style this a little bit. Alright, we want to add this as well. So now we can pass in our source. So it's going to be product.images.source. And this will be product.title for our Alt text. And then we also want to show the title as part of the card. And what are we using for this card-body? Card-body? Yeah, first you're going to do card-body and then, Card-body, and then an H5 or something for the title. It's just product-title? Yeah. Alright. Cool. And then we're going to pass here product.title. Alright, so we've made it this far, let's go ahead and get this showing up on the screen. So this is just the pure component. And what we're doing is we're just passing in a product and potentially a class name, if we want to add some styles to this. Like some margin and padding is usually what we might add here. What happened? What'd you fix? Sorry about that. You only need the image there. You don't need the div with the image top. Okay. Cool.
11. Building Post Products and Product Card Component
We're going to pass in a product and potentially some styles in the form of a class name. We're going to show the image associated with that product and the title. Later on, we'll add the AgiCart button and view details. Let's loop through all of the post products for this particular post. We'll have a div that is a column and show the postcard product card. We need to use keys when looping in React. We're passing in the product as the prop. There might be a refresh issue if the post products are not making it through. We need to export our get static props for Next.js to recognize it as a static page. We're getting the featured posts from WordPress and using the slug to populate our post products, which is a cross-reference hash map. We query Shopify using the tag and remove the collection name from the call. Shopify returns the products for that collection and we associate them in our hash map.
All right. And so it's pure component. We're going to pass in a product and potentially some styles in the form of a class name. And then we're going to show the image associated, that product and the title. And then later on, we'll add the AgiCart button and view details, but let's go ahead and get this on the screen. I like to take it in smaller chunks.
All right. So now down here, what we want to do is we want to loop through all of the post products for this particular post. So we'll do postproducts.map. I need to pull in the right one, so I need to do post.slug.map and then we're going to get the products out of that. And from that we're going to have a div, which is going to be a column. Col-md-4, that's what we'll go with. We get some responsive juice out of that. Yeah, and this is and get out of speed product, and then we want to just show that postcard. product card. Man. You're missing a couple of critical things here when you're working in React, and that is these keys. Oh yeah, that's right yeah we need a key for whenever we're looping. Coming through to save the day. Guest user is really just on it. What are we passing here, because for some reason we're not getting typings which is really bizarre actually. You're just passing in the product. Yeah, so we're going to pass in a product which is the product. And it's hating me. Oh can I? That's why I'm not getting typing. There we go. And I think we're gonna want something around this let's see if this is working. So I saved it, we go back over and we see that we have errors. You might read the property of undefined. So post products is not making it through. It might be actually a refresh issue because this is a static page. Let's make sure that was not it. Why is this running? Did I spell something wrong? Result.props.PostProduct, let's make sure that PostProducts is getting populated here. Yeah and you may refresh your server just because you've added some files and stuff. That might be it too, yeah. Yeah because nothing's crashing, so let's restart the server. Did you await postMap? Oh it does return very comic, very astute there. Let's do a promise.all then we're going to do promise.all here. And that's going to give us back, that's going to do what we need, yep we're good. Now we're good, right? Yep, do any more. Nope, should be fine. Interesting. Yeah. We're returning a promise, something isn't working. Now let's console.log the Post-Products. This isn't running for some reason. Oh I didn't export this. This has never run yet. Yeah. So, uh, yeah, that was a problem. There we go. Oh, it's early. Uh, I don't usually start coding until later in the morning. Alright, cool. So now we have everything up here we just forgot to export our get static props which so next had no idea that we wanted this page to be static. Um, alright, cool. So now we're pulling that back. Let's just walk through this a little bit, cause it is a little bit complicated, uh, and Jamie was all over it, which we appreciate. So basically what we're doing is we're getting our client for WordPress here. Uh, we're making our call to get our featured posts. We show those on the screen via this, um, the post that come back. We pull our posts out here so that we can map over them, uh, loop through them essentially, uh, and then use the slug to go out and populate our post products, which is our, um, cross reference hash map so that we can take a slug from a post, which is unique, and then query Shopify via our get products by collection. Uh, we query Shopify by that tag. The collection name, uh, Shopify is handle also has those dashes in it. So we don't have to do anything magical there. It just works. Uh, we passed that in, uh, we remove the collection piece here because in Shopify, we didn't name it collection return to the Jedi or whatnot. So we just remove that starting piece whenever we make that call. Uh, Shopify returns back the products for that collection. And then we assess, associate those products or hash map.
12. Setting Up SEO for Homepage
We injected the props into our home component and looped over the products associated with each post to show a product card. For SEO, we passed the site schema from Yoast to the layout component. The site schema contains properties like the site title and description. The SEO component, pulled from react-headless-yoast, populates the appropriate SEO tags in the head. This allows us to customize the SEO for our homepage. The SEO component works with Yoast and the WP GraphQL plugin. It expects a similar object to a WP GraphQL query. It can be used with different frameworks like Next.js or Gatsby. We can see the SEO tags in the head when we inspect the page. The SEO component also handles social media metadata, although Twitter didn't display the image correctly in this case. Overall, the SEO is now set up for the homepage.
We return those, uh, as part of our props and our, I guess that it props. So then they get injected into our home. Component. That component, then for each post, it lives in our cross reference hash map for that slug loops over all the products that are associated to that post and shows a product card. Was that right. Is that what's happened here? That what I just coded?
There's one last piece here, and we haven't done anything with the SEO. You haven't done anything with the SEO that is accurate. Why don't you do that? Yeah. So for SEO, yeah, for SEO, we just want to pass in the, uh, the layout component takes in an SEO prop and we want to pass in, since this is just the index page, uh, we will get a site schema from Yoast and we can pass in the site schema to the layout component. So if we go into our get static props, what we're looking to do and get static props is just make sure we make the call to get the site schemas. So, uh, We'll get, we'll pass in the client and get our site schema. We already coded a file for you that publishes a way to get site schema. And, um, and it also publishes a hook on the front end, but this is all you need to do on the backend and then on your, on the front end, you want to use site schema, so we'll say site schema. What? Yeah. I have to sit for. I gotta follow you around. Oh yeah. Okay. So you cite schema and then we'll pass it in to our SEO. Site schema actually has a property called site schema on it, but for this, we don't need to do that. So simple as that to hook up our SEO for our homepage. A site schema has, you know, it's going to have the right. Um, properties on it. So it'll have like the site title and description and whatever you put into yoast. Yeah. Let's go take a look at that real quick. Uh, so this, um, mates, this get site schema query. Um, which just makes a call to GraphQL to pull that data out, um, which is all right here. So we get the logo. We get the site name, company name, site URLs, all this stuff that we need for SEO comes up. And then I gets populated in the head. The, uh, component that will has published. Right. Yep. Which is in the layout over here. Uh, this SEO component. So we pull this from react headless Yost. So this is just on NPM. You can pull that down. Uh, and we add that to our layout. So when we pass that into our layout, that SEO, uh, it gets populated on, um, yes, populated in the head and the appropriate places. So if we go back to our page now, ensure we refresh this and then we look into the SEO component is written to work specifically on it. So it's basically with Yoast and the W GraphQL WP GraphQL plugin for Yoast. So it expects a similar object to what you would, um, what your query would look like in WP GraphQL. So it makes it easy for you to pass in, uh, you know, your posts or your page, also your site schema, and it also lets you, um, we're using next. And that's how you put a meta tags and link tags and scripts into the head. Uh, but if you were using react dash head, or if you were using Gatsby or something, um, SEO doesn't really care what you're using. It just expects you to pass in the, the head component and it will render into that. Yeah, that's pretty neat. Uh, so you can see in here that we have all of our SEO stuff now that we're pulling back from Yoast. So we have our web site. Site name and title. W we, this, I think we hard-coded in there. Um, Jeff. So now if we take the link, so if I take this link that I have live out here, just to show you some of the social stuff that happens too. And I go to Twitter. And I paste this in, I should get something that comes back. So we get the site title here. We don't have an image on this particular page, but we'll show you what we'll do on other pages. I like. Yeah. It's not as exciting on our index page, but once you get to a product page or a post page, it's a little more exciting. Yeah, let's say so that Twitter re Twitter, not like me. All right, well, Twitter isn't doing it, but when I posted it in the discord, the image also shows the images there, I don't know why Twitter trying to show this and some other image, so we can work on that later. All right. Um, let's see. So our SEO comes through, you saw the title, the description or what not. And everything came through on that and then everything should appear. So you could blow this out as much as you want. That component accepts everything that you would need here.
13. Adding Products to the Cart
We add a button to the product card component that allows users to add products to the cart. Clicking the button triggers the 'add product' action, which adds the product to the cart. The 'get checkout' function is called to update the cart quantity in the navigation. The functionality is working correctly.
All right. Where were we? I was in code. All right, cool. So that's our SEO, anything else on that? Nope. We'll do that on each page.
Alright, cool. So now let's take a look at our site. So we can decide what we want to do next. All right. So right now we just have these, uh, these product cards, but we don't have any way to actually let people buy them, so let's add them to our cart. So let's go back to our product card. Do we go to product card this time and not postcard? Yeah. Not postcard. We're going to do product card. Only if we're going to get to postcard, if we have enough time. Um, yeah, here we go. All right. So we're in product card and we want to add a, uh, button that will, um, allow us to add to cart. So we can do this, and div.card-footer, I think. Then we'll just add a button and the form of a link or link. No, we want a button. Right. Yeah. Just do a button. We're not trying to go anywhere. Yeah. We'll create a button and it'll just be a add to cart. And we want to, whenever we click it, we need to do something. We need to actually add it to the cart. Yeah. So this is where our actor is going to come in. Right. So the way that Tate's work is you have this actor, which you would have seen over in our state. And that exports actions that you can take on the state. What the two actions that we have here are add product and remove product. So we import them into our product cart as actions, and then we're going to call the add product action whenever someone clicks this button. So we'll just say actions.addProduct. I'm just going to pass in the variant ID, which we can grab from the product, uh, variants.id hit. And that's it. So now through the magic of Tate's. Whenever we click this button, it will add the product and then that will fire off the hook for used checkouts. Let's take a look at that. Oh, we're in here. We fire this off. We call get checkout once we've updated the product. So once we know that Shopify has it, it's in the cart, we call get checkout, which really is get cart. But again, Shopify naming is hard. Uh, but, and when it does that get checkout actually, um, will. Uh, set the state right here when this happens. Uh, Tate's is watching this property through a proxy, which is a JavaScript API, and then it fires off subscription events, which will then make this used checkout, uh, hook fire off in the nav over here. Uh, which updates the quantity of the number of items that we have in our cart. I think I got all of that. Now will it work? That was the big question. Alright, we have add to cart. Oh, I guess we didn't use the footer. What is when the world is that? Yeah. We just didn't use footer in our test because it didn't look right. All right, I won't use the footer cause that does not look nice. Yeah. How to work. I just, now, when you click add to cart, click it and then you'll see that our cart was incremented by one up here. I keep clicking. Nope, nope, nope. This is awesome. They're going into the cart. Um, yeah, so it's working. You might want to, uh, zoom in, in your browser here cause it's kind of small. There. Yeah. That's better now when I click.
14. Building the Checkout Page
We need to show the products in our cart on the checkout page. We'll create a new card to display the quantity of each product. The checkout in Shopify has line items that correspond to the selected variants. This page is dynamic and client-side rendered. We'll map through the cart line items and create a div with the MDS-4 class. We'll display the product image and title, and add a paragraph to show the quantity. The code for this will be separate from the product card component.
Oh, I wouldn't zoom in that far. I'm just doing it. Okay. Yeah. That's good. Uh, yeah. We'll stay at this size. All right. Cool. So our cart gets filled up now, and now we could click on this and we get taken to our checkout page or cart, but now we need to actually show something in this page. So we get to go off and build another page. Then we will be so much closer to buying our beautiful stickers.
All right. Cool. So we have all this now let's go over to our checkout page. I'll close some of these other ones we don't need right now. All right. We have our checkout page and we want to just show the, uh, products that we have in our cart and we'll use the same product card that we created. Or will we? No, we won't. We're going to create a new card because we want to show the quantity on it that we've added to our art cart. Yeah. We'll have to create some sort of line item. So a checkout in Shopify. It looks like you would expect like an order, but it has, it has some information, it has a line items. And each line item is equivalent to the variant that, uh, you have selected. Right.
So for this page, we're not worried about SEO. We're not worried about static rendering because this is a totally dynamic page based on what the user is doing locally to them. So we're going to do everything client side for this page, which is one of the things that I really like about next. So if you're not an X fan, I don't know why you're not. It was awesome because now I can just do regular react stuff without any of the magic that they do. You just check out. Let me call this cart just because that terminology is just awful. It's difficult for you. It's very difficult for me.
All right now I'm just going to map through the cart line items and wow, what's happening and we're going to grab an item and then we want to show something here we're going to have a we're going to break this out into a line item card later, but we'll just do it from scratch here first. So we'll do a div with class name is called MDS-4, so it's not similar to our product card actually. But we want to have a quantity on here. Which we could have just added to our product card. That'd be a pain. I'm going to do that, because we didn't code it that way. But we could do that. But we didn't have to create a whole other one. All right, so we have our card, we have our image top, so do image.card-image-top. The alt here doesn't matter so much, but we'll just leave it. Yeah, so for this one it's, you're looking at the variant and the image. Do we have the typings in here? Can you? No, the typings aren't here. Yeah, I think you're. Oh no, it's just, I don't have a, whoops, what just happened? I don't know, I don't think that there's a, is this, what is this, image is product image. Yeah, it's just image.source. There we go. But you have to. There's only one that we're pulling back. That we're pulling back. We're mapping that from how it comes back from Shopify, and I did that last minute, last night. So I keep forgetting that when we need the nodes and edges from Relay or not. Very confusing. Alright, and we'll just add the title here for the alt text. Or what is the alt text? You can probably just do item.title. Item.title. There we go. Alright, cool. And then we want to show the quantity for this particular. Yeah, in our card body here. Yeah. Card body for this particular product. And we'll just do that in a paragraph tag, I guess. Yeah. And I think I had the way I did this was like pulled these quantities out. Right. Let's pull that code over.
15. Displaying Quantities and Adding Checkout Button
We added a row to display the quantities in a row. We also added a Checkout button that redirects to the Shopify cart. We added a button to remove line items from the cart. The Global State ensures that the changes are reflected in the header as well.
You just had. I normalized the quantity stuff because it's kind of a pain to go through, but you just did that. Oh, is that what I did here? Yeah, what am I thinking? Of? Oh, I'm thinking of the nav bar. Never mind. So let's go look here. All right, cool. We have these quantities. These are going straight down, which we don't want. We want these in a row. So let's wrap this whole thing in a row. So, looking good. Now, we also, I'm going to add some padding here or some margin from the top. Pull that down a bit. All right, cool. We also want to show a Checkout button now. So we want to be able to go and check out if there are items. So, we'll say div dot, we'll do that down here. We'll add another row and we'll add a div.call and then a button for... or this will be a link, actually. We'll do a link, but it'll look, we'll make it look like a button. And it's going to go to the checkout URL that Shopify gives us. So if we pull up the cart, it's webURL, webURL, yeah, that's the actual URL that takes us to our cart on the Shopify side where then the user can checkout. And we don't want to leave, we'll go ahead and do that in a different tab and then we'll add our stuff in here so that Shopify can't hack us because that would be bad. All right, cool, so let's see if that works. And you need a name for it right? We might want something in here. There, all right, there it is. Let's make this bigger too. And add some padding here so, our margin. There we go, so now we click this checkout, takes us over to Shopify with the right, well, no that is with the right, where'd it go? I don't know what I just did there. But it has our cart in here. Pulls it up and shows us all the items that we have in here. And will point it out, C3PO is free. So I mean, you should load up on those. All right, cool. So let's go back to Shopify and we'll go back here. So let's show you what's happening here. Right, cool. So let's go back here. Our checkout is working. But now we may come in here and say, I don't actually want one of these stickers. So we need to be able to remove a line item as well. So let's get our code. So for each of these cards where we have the quantity, we also want to show underneath it. We'll show a button that would be like, that will remove it from our cart. I'm going to use secondary here, so it's not prominent. We're not making it obvious to the user that they can remove it, necessarily. The other thing I'm going to do in here is I'm just going to add the title. Because I noticed on your cart you don't have the title. All right, cool. All right, remove item. So we just need to click Event here, just like on our other page. And we're going to do this. It's going to look just like that Add click event that we did, where we're going to call Actions.RemoveProduct. And we're going to pass in the variant. You already, yeah, this is a variant, so you just need item.id here. OK, so we're already in, we're looping through the variants here, or line items. Yep, it already knows what it is. So we say to remove that product. When we do that, again, let's just go over that one more time. When we go to our Actor here, we click Remove Product, it makes the Shopify call to actually remove it from our cart. And then we go refresh our checkout, which again is our cart, from Shopify. When that happens, our checkout is updated here, which fires the Use Checkout hook, which we're listening to here. This will come back, render this screen, and that item won't be there anymore. And it will also... So that works on the cart page, and it will also be reflected in the header. So the header will... That's why that Global State is cool. When I click Remove Item here, it removes it from the page, but it also changed the quantity up here as well. So let's watch that again. That's six.
QnA: Building the Post Page and Multiple Data Sources
Now it's four. And if we click Checkout, we go to the page. On the Shopify side, we have a complete working site. Let's take a little pause here. We've been going for an hour and a half. If anybody has questions or wants to know what else you could do with this site, let us know. We haven't shown building out the page for a single post and the page for a single product, but we can do that if there's time. Regarding the cart listener and updating the site after checkout, once you check out, the checkout object would go away and your cart would empty. We haven't gone that far in this app, but you would essentially create a new cart. If you want to automate the process, you could use subscriptions. We haven't used WooCommerce as Headless WordPress, but it should work similarly to Shopify. You can have multiple data sources in a Headless app, and everything becomes an API.
Now it's four. And if we click Checkout, we go to the page. On the Shopify side, we have a free... four free C-3PO's. Four stickers. Awesome. Now we have a complete working site, actually. So that's cool. Yep. So it's 1030. Let's take a little pause here. 1030, my time. I don't know what time it is where you are. Probably not 1030. It is 830 where I am. Yeah. We've been going for an hour and a half. And I'm interested if anybody has questions, and about what else you could do with this site. Because this is really what we planned on getting through. The other stuff is just... Icing on the cake, I guess. Wouldn't you say? Yeah, I'd say. So what we haven't shown is building out the page for a single post and the page for a single product. Right. Which we can probably build out, you know, if we have half an hour left, we can get to one of those. But if there are any specific questions that somebody has, we can answer those. Right. If not, we will go ahead and build those out. And there's a lot of people watching. And we got a half hour. Let's do it. Okay, let's build out the post page. Which page should we do? Okay. Sure. How do we do post? Oh, somebody says regarding the cart listener. Can you talk about the post page? Okay, let's do that. Updating the site after checkout? Yeah. So we haven't gone as far as to know what happens after you check out. But once you check out your the checkout object would go away. And so your cart would empty. Right. So once you checked out Shopify wouldn't know what this cart ID is, or they got a checkout. So it doesn't exist anymore. So when we call it over here when we call get checkout from Shopify, Shopify wouldn't return anything because that checkout object is gone now. So it would just empty the cart out. And then we could, we would create a new cart. Yeah, we haven't gone so far in this app as to like pull the checkout or anything like that and and remove it, but that's essentially what you would do. Right. Yeah, we're not going to automate, I don't know if GraphQL supports or Shopify support subscriptions, but that would be one option if they do. So you could have a subscription to your checkout and then update it automatically there. Well, you want to, can we do a poll? Does that work? Yeah. So Let's see, do you want image or a post page? Okay, so have we used WooCommerce as Headless WordPress and what's our experience? I haven't built out a site, a full site using WooCommerce and Headless WordPress, but WooCommerce does work with WPGraphQL, so it would function similarly, although you would get the, you know, on the WordPress side of things. You get the WooCommerce versus you have to go to Shopify to manage all your products here. So it would work very similarly. Right, yeah, you would just be calling a different API. So you could do that with WooCommerce, BigCommerce. That's, what's really cool about Headless. Like you choose the services you want to use for each of the things that you're building. So you like right now, we're using WordPress for our content. So any publishing that we're doing, but then we're using Shopify to manage our econ stuff, but you can interchange those for whatever you're using when you go Headless. So good stuff. All right. I don't know how to do a poll so let's just do a post page start there. Yeah, I think the post page is nice. Cause that really shows off the SEO component. We get the posts in there and where you can do the product too, but right. All right. So can you have multiple data sources like WordPress and something else? Yes, absolutely. So we actually have multiple data sources in this app, but once you go headless, everything is an API. In our Decode podcast we have an episode on APIs that goes into this a bit further.
QnA: Headless WordPress and External APIs
When using headless WordPress, you can integrate external APIs directly into your site. Multiple data sources can be used, such as custom post types in WordPress and external APIs. Headless WordPress allows for a mix and match approach, using APIs directly or pulling data through WordPress. Multiple WordPress instances can be used to display information from different sites. A headless framework is being developed, with teams working on making WordPress a great headless CMS. Security concerns are reduced in headless WordPress, as the WordPress site can be locked down to only wp-admin and static site generation can be used. A plugin allows for redirecting and previewing posts on the front end, removing the attack surface of WordPress. The plugin also allows for separating the WordPress API from the internet, further enhancing security.
But WordPress just becomes your CMS. It's no longer the entire site. So when you move into that world, you're no longer thinking, hey, there's a plugin for WordPress that I need to install to add some feature to my site. If there is some external API or service that you want to use, you can just integrate that API directly into your site and have it work.
So one example of that is if you go to developers.wpengine.com, which is a headless site built with Next, it's actually running on the Atlas platform. Our docs for the Atlas platform are all written in Markdown and are out on GitHub. And so we pull all this down using the GitHub API and it doesn't have any connection to our WordPress back end. But this entire page and everything is rendered from GitHub directly. Right, so we have multiple data sources here. We pull back our videos, we were pulling these directly back from YouTube, but now we're using custom post types and WordPress. And these are different posts that we have. So yeah, so we have a couple of different data going on here. So headless is really nice, you can like mix and match. Sometimes it makes sense to have to use an API directly, sometimes APIs will have, you know, limitations on how many times you can call them or things like that. So it makes sense to pull them through in WordPress and keep things updated that way. So on the developer site, we are, we're definitely using a good mix of like things in WordPress and other external APIs that don't need to talk to WordPress. And you can also have multiple WordPress instances. So, you know, some people have used WordPress multi site might be have one site that shows information from multiple different WordPress sites. And when you're using headless WordPress, you can do that really easily by just grabbing the data, setting up, you know, an Apollo client, or if you're using React Query, setting up React Query to hit the WordPress site you want, and then you can grab data from more than one WordPress site at a time. Right.
There's one thing that we've been using that I I've talked about a little bit but I haven't shown, but if you go to GitHub on the WPO engine, GitHub, we're using this headless framework here. This is an open source framework that we're working on. We have teams working on the CMS side, so making WordPress a really great headless CMS, they're working on some really cool stuff that I'm gonna preview in my talk next week at React Summit. I am lucky enough to go right after the Kent C. Dodds, but in that talk I show off some stuff that we're doing in this framework that's going to be coming out in the next few months, so definitely check that out. It's super cool.
So Steve asked if you need all the WordPress security plugins if it's headless, and the answer is not exactly, because you're hosting your WordPress site when you go headless, you're hosting your WordPress site on one domain, and then you'll host your frontend on a separate domain. So that allows you to take advantage of a number of things. You can lock down your WordPress site to only wp-admin, so people can't even get to the front end of your monolith WordPress site. Then you can also, like we did, use static site generation and take advantage of CDNs to cache your pages and serve them up very quickly to whoever is visiting them. So the WordPress, the inherent WordPress security and security concerns that people have, they kind of go away once you move to headless WordPress. Right, and let me show you something. So part of the framework that I'm showing here is that there's a plugin. So when you install that plugin, you get this settings page here. You tell it where your front end is. In this case, I'm telling it a local host 3000. And what that allows you to do is like if we go over here to a post and we're going to preview it, probably impossible to see but if I try to preview this, it's going to preview it on the front end and it also does something else. It changes the... it'll do redirects for you. So now let's say that I tried to visit this site and this is security related. I swear I'm getting back to the point of this. But I'm going to visit this WordPress site, right? So instead of going to wpadman, I just go straight to it. It's actually not going to... it's going to direct me to the front end locally. So I'm going to local host now. It doesn't let me get to the front end. So you remove that entire attack surface from WordPress altogether. So it's really hard for somebody to attack WordPress directly now because they don't really have access to anything to attack unless they can get in a wp admin. But you could even lock that down and only allow WordPress to be... the API to be communicated with like for your back end for your front end and just take WordPress basically completely off the internet at that point, which is a way to lock it down all the way, essentially. Yep. So yeah, so in this particular site, since we have this plugin installed, you can't even get to the front end. It always redirects you to your node front end. So one thing that Matt did by showing you this page is he exposed the secret key there. So I'm going to tell him that he needs to regenerate that secret key later. I will do that. Here's my key. All right. Oh, cool. Let's see. I don't need to show anything here. What are we doing? All right. We're going to build out a page now. All right. So we're going to build out the post page. Whenever we click on the link here. And right now it's taking us to the single post page. This is where we are. So let's make it work. All right.
QnA: Building the Post Page and SEO
We create a custom query called 'Get post' to retrieve a massive amount of data, including SEO information from Yoast. The SEO component simplifies working with Yoast properties on the front end by using feature detection and fallbacks. We use 'getStaticProps' to make the same query on the back end and front end to retrieve post data and apply SEO. On the front end, we use 'useQuery' and the Next.js router to get the slug and call the query. We also implement 'getStaticPaths' to pre-render dynamic routes and handle 404 pages for non-existent slugs. We retrieve the site schema for SEO and pass it to the SEO component. Finally, we display the post title using the retrieved data and semantic HTML.
So for this page we have a custom query that we're creating. Get post. It takes in a slug and it returns this massive amount of data. The reason we're doing this is so we can grab all this yummy SEO stuff that Yoast gives us out of WordPress. And then we can have that show up from a social standpoint, from a searchability and all that. Yeah. And this is where the SEO component really comes in handy because there is all of that, SEO. You know, the SEO properties that you get out of Yoast can be difficult to work with on the front end and the SEO component, you can go and look at the source. It's not like it's super complicated, but it does feature detection. So, you know, if a property exists, it will use it. And then it also does fallbacks. So, for example, you know, if you only have a title, it'll make sure that the open graph and the Twitter title are the same and same with the description and all of those. So it, it takes the configurability of Yoast and applies it to your front end site as best as possible. Yeah, so right here, Matt's doing something similar to what we did in the index, right? So we have the get static props. We're exporting that function, you know, the right way. But we have get static props and we're making the same query on the back end and the front end. So we're trying to get our post data. And I will, I'll put in the type here so that we get our typings We get the post data. We can go ahead and do the SEO at the same time here. I'll do the site schema. Yeah, I actually don't need to. I do need this yes. Eventually, we're going to get that collection. But we let's not worry about that for now, right? We'll just use get next static props for now and return the result of that. Result of that. Right, similar to how we did on the front end, or in the index page. Yeah, we got to, we got to get the products as well. But for now, we don't have to. Yeah. Alright, then on the front end, we're going to do use query. So do comms, data. And we're going to call that same query, and we got to pass in the same parameter as well. So well, not what I want. Yes, you'll have to use router, use the next router to get the slug and everything, too. And if you're unfamiliar with, with how neXt works, there is a, you'll see that this page or this file is, has angle brackets slug. neXt takes that to mean this is a dynamic page and it will automatically pass the slugging on the params for in the router and on the back end. It does it on the the params as well. The other thing I just put in there is the get static paths, so in neXt, when you have a dynamic route, you can and you want to do get static props, you can tell it what paths you want to pre render by default and it will create a bunch of static pages for that. Or you can use this fallback blocking mechanism and what that will do is anytime somebody goes to the page it will do server-side rendering for that page and then from then on it caches the result and serves up a static page. And so we wanted to make sure this post actually is this. Yeah and then we can set what is it, not you can just return, yeah just return not found true in there. Oh yeah and you could probably do that before you even get next static props or anything you just return not found true. So this will give us a 404 page if somebody types in a random slug that doesn't exist we'll get a 404 on the front end which we want because that's good for SEO too. We don't want every slug that anyone tries out to be indexed by Google. All right and now we should see you're also going to want to get the site schema here. Okay yeah. Uh site schema do I need to pass anything up nope it just works on the front end Cool magic magic and then I add that here right yep and so the SEO prop expects a page um which you just pass the post directly into the page you'll probably have to cast it I don't have to cast it but I'll take care of the typing here hey I can do this okay yeah because it's So we have our post what is that data dot post and then and then we'll also pass in the site schema which is our site schema yes yeah oh I'll call it I'll rename this system yeah all right yeah there you go cool so now we have our SEO in here and now we would just want to show the post so let's do it instead of saying single post here now we can say post or is it data dot post yeah you might just pull the post out just just pull a post out like up above so we don't have to do this all right so we're just pulling the posts out of our query here and now I can just say post up title. I'm not getting my typings because you want to add this is it a query? Oh, that's why I was wondering I keep forgetting I'm you're like backseat you know armchair you're my automatic typing person. So I don't have to remember where they are. Yeah, exactly. Now it's now it's giving you the right stuff. No. Why is it doing this to me? It should make it require whatever. Let's do it here. Yeah. I'm going. Yeah, I don't. Yeah, just do that. Worry about it. All right. Cool. So now if we come over here, now we're seeing the title of the post. So let's go ahead and make build this out a little bit. So we need a row. And we want to add the products to the right hand side of the actual post. So we're going to do a call dash MD dash nine for the actual post. And we'll make that an article. Yeah. Use our semantic HTML, which is also good for SEO. And then we need a div for our dangerously set inner HTML.
QnA: Showing Products for Post
When using Headless WordPress, you have to use dangerously set inner HTML because WordPress sends back HTML. React calls it dangerously set inner HTML because it can potentially load scripts. However, in our case, it's not a big deal since the content comes directly from our WP admin. We had a 404 error because the links in the database were not updated. We fixed it by checking for tags in the query. In development mode, Next.js uses server-side rendering, which can be slow due to requests to WordPress and Shopify. But once deployed, with static site generation, the pages will be statically generated and load faster. We now need to get all the products for the post by making a call to Shopify and passing the tag as a parameter. We replace the collection prefix in the tag and pass the products as props to the page. We're almost done!
Microsoft property, ever. When you get started with Headless WordPress, you'll realize pretty quick you have to use this dangerously set inner HTML because WordPress sends back HTML. And so you don't have somehow you have to have to put it in the Dom as HTML, not as text content. And by default, if you just put it in a component, React is going to render it as text content because it wants to safely. If you're depending upon how old the developer you are, you may be familiar with a day when you used to or some people used to say element dot inner HTML equals and then text content. And that is a little bit unsafe because it can you can do things like put script tags in there and it can it'll load a script. And you don't and you don't really want to do that. But in our case, and that's why React calls it dangerously set in our HTML. In our case, that's not that big a deal because this WordPress content is coming directly from our WP admin. So we would hope that none of your admins are trying to hack into people's computers. Seems unlikely. All right, cool. Now we have our single post. If we go back to the homepage and we click around. Yeah. Yeah, we got a 404 for that one. Why? I don't know. Don't know. Why did we get a 404? Where did it send you? Oh, wait. Our link no. You know, why? I changed these links in the database, but they're not updated. Right now, none of them are working. What's going on? What did we do? That's a good question. If not, data.post.id. Are we getting ID back? No, that's what I need to check for the slide. Yeah. So I think the way we did it in here, I'll put it in here. Um, I think we just checked for tags because we only want to show posts that have tags, so we just did it there. There we go. Alright. We didn't pull the ID back in our query, so the ID was never there. All right. Cool. But now if we click around back to where, what I was saying, go to these different posts and everything is working. It's slow and development mode because it's all statically generated. But when you get out to, when you deploy it and you can see that this is like super fast. Yeah. So in development mode, next is going to render this and use SSR. server side rendering for every page, which is going to be a little bit slow because you're making the request to WordPress and some in. Specifically in our home page, we're making a bunch of requests. We make a WordPress request to get the list of posts. Then we make for each post a request to Shopify to get the collections. But if you're using static site generation, once you go to production, all of your pages will be statically generated and they won't make those calls and everything will be very fast. Right. So now what we want to do is we have the post where we want to show all the products on the side here. So we need to go get all the products. So we're going to loop through our, or we're just going to grab one tag. Right. And then we're going to go grab all the products from Shopify. Yeah. The collection. So I'm gonna go ahead and grab that tag out, which is data post up. Hangs zero. And then we're going to make a call to Shopify to get the products. So say products equals get products by collection and we'll pass in that tag. Need to await this. It's it, it is there like technically might not be one, but we know there. No, or you can get there. All right. And you want to replace the collection in here, right? Cause the products don't have the collection dash in them. So it'll be like tag dot replace collection, but we're going to pass these in a static as props to the, uh, the page as well. So we need to make sure that we do that here. So we say a result that this has the right content. Result that props dot products equals products. So that'll pass those down. And then we'll already added their replaces already is talking about, our collections don't have that collection in front of it, prefixed in Shopify. So we just want to pull that out of our tag cause that's how we had tagged these posts. All right. So we save that we should be getting products in our component now. And now we just want to show those, um, and you're already having a component for it.
QnA: Adding Products to the Cart
We added a button to the product card component that allows users to add products to the cart. Clicking the button triggers the 'add product' action, which adds the product to the cart. The 'get checkout' function is called to update the cart quantity in the navigation. The functionality is working correctly.
Oh yeah. I have a power. So now we can pull it, we can just loop through these. So we'll do our map over them, or whatever. How's that map. We get a product out and we just use the, uh, product card. And we pass them product, which I still want. Cool. Well, what does that Oh, key. Saving me. I like having a backseat. Yeah, that's nice. Everything gets fixed automatically and there are products. Now you can see why I added that class name there. We get to use it now, but these are no spacing here. So, wow, first of all, I want a little bit more than here. And then I also want to pass in a class name on the product card. What's your give me a little margin on the bottom. Make it a three and that'll spread those out a little and now we're good to go. So now from this page, the add to cart should just work. So you can see our cart going up. Well, well, well, well. Super simple. We go over here. There it is. Awesome. That was easy. Next. Nice, but we have five minutes left, so maybe now we, um, can just answer a few questions if anybody has any and you can, yeah. So I'd say. Patrick looks like. Yeah. Now on your own, you could go and create a product page, right? The individual product page. Um, and the other thing we haven't added. Is to the product card, a button that lets you go view it since we haven't created the product page yet, but. Yeah, we could add a button real quick. I'm not sure, just be a link actually. Yeah. But if anybody has questions, now is the time and then we'll wrap up here in a minute. Well, this is gonna go to slash products slash. Use the handle thing. Product that handle, I think we called it. Yeah. Yeah. And you can use the next link to since it's internal. Right? Um, yeah, that well, net routing. Well, that's routing. Uh, I don't want to see primary. Now all of our product cards that, which we want to a little bit of, uh, uh, spacing. Boom. And we go to the product page. So now we just build this out. Yeah. But we will leave that up to you. We will, you can do it. You have the tools. All right. So there's no questions. Then hopefully you learn something in this talk. We appreciate you spending the time and go out there. And somebody, please take this and style it and make it better. I'd love to see this, like actually look cool, uh, but we just use some pretty basic files here. I would suggest if you keep working on this, that you, uh, Hook it up to your own Shopify site and your own WordPress site, because there's no telling when Matt is going to shut down the Shopify site, it's not real. Uh, so it might just disappear on you. Yeah. And you can go to Shopify and create a developer account and get a free store to play around with. Uh, and you would just replace that API key in the code with your own, and then also whatever WordPress site. You had a local WordPress site you could use using like a local WordPress, or if you had one deployed somewhere, you can add that in there in the environment variables. So. Cool.
QnA: Conclusion and Next Steps
That was fun. If you want to learn more about Headless WordPress, go to developers.wpmg.com. We run a podcast and do live coding sessions on Fridays. Join our Slack community at developers.wpmg.com. Thanks for joining us and happy coding!
That was fun. Um, uh, hopefully everybody, uh, learns this and thanks for joining us. Uh, I don't see any questions, so I guess, uh, we're going to call it here. If you want to learn more about Headless WordPress, definitely go to developers.wpmg.com. Uh, follow all of the accounts that we have here in the readme. Let's see, so those to end with. Yeah. And the other thing I'll point out is, uh, we run a podcast, but we also do live coding sessions on Friday. Similar to this, uh, our live coding sessions are the coding is a little bit more rough, but we like to answer questions anyone has about Headless WordPress or, uh, WordPress in general, or even any front end questions you have. We've had a lot of, uh, people come in and talk about different frameworks and different libraries they're using. And it's always a fun learning experience for us as well. Uh, we are not experts at WordPress by any means. Uh, also not experts at WP GraphQL. So last week I think we learned about, uh, taxonomy queries and we're able to implement those in a project. And, um, yeah, so if you visit the Decode YouTube, which is linked in the Readme for this, uh, this repo. That's where we do our live coding sessions on Fridays. Yeah. Also, if you do have this WordPress, we have a Slack that you can join. So I have a link in the, uh, repo, but you really want to go to the DevRel site. If you're watching this recorded, this link and the repo may have expired. So go to the DevRel site, which is developers.wpmg.com. And, uh, there's a link in the header for the, uh, Slack there. Uh, we have a lot of people joining in there, just doing all kinds of cool Headless WordPress stuff. So come check it out, ask us questions and tell us what you want us to live code for you as well. I guess that's it is I don't see any questions coming through. So a lot of people connected, but, uh, thanks for spending your two hours today, whatever time it is with us. Uh, we really enjoyed it. And we look forward to our talk next week, um, Where we talk more about Headless WordPress and react. So join us. Go out there and build a cool commerce experience with Headless WordPress, Shopify, whatever e-commerce platform you want and happy coding.
Comments