Instructor: Now that we created three themes, a marketing theme, a Shopify theme, and the product blog, we'll take a dive into scheme and customization. We can turn our attention to how to abstract this theme into a data structure that can support our product blog inaudible from WordPress and our deaf blog inaudible from MDX files.
We're going to start a new theme to abstract the WordPress blog we already created. This theme will be Gatsby theme blog data, and we'll start off with the MD index file. Run your Yarn in it to get your package json, and then we can take a look at the data that we're using in each.
If we look at the WordPress blogpost template and we scroll down to the query we can see that we're creating for the title and the content. If we go to www and we look at the blogpost query or the blogpost template, we can see that we use title and body.
Note that we should also take a look at the devblog.js file and the blog.js file in our product blog. Together, this gives us a set of fields that we should use if we intend the data structure that we build to be able to support the whole structure, that is, the ID, the title, the slug, the excerpt, and the content.
Create a gatsby-node.js file. We'll take the types we just looked at, and create a blog post interface. We use the interface keyword, and we use @node interface. The ID is required, as are most other fields. The excerpt isn't, however. This is going to be most of what we have in our data theme.
Now we're going to take the familiar step of using our theme, except that, instead of using our theme in www, we're going to be using our theme in gatsby-theme-product-blog. This is going to create a parent-child relationship between gatsby-theme-blog-data and gatsby-theme-product-blog, where blog-data is the parent, and product-blog is the child that uses the parent and extends it.
Gatsby-config or gatsby-theme-product-blog add gatsby-theme-blog-data, in the package.json, add gatsby-theme-blog-data at a version of 1.00Now we can go back to the root of our project, and run yarn to link our packages together. We can run the site now.
Instead of viewing the site this time, we're going to view the GraphQL graphical explorer. We can see a set of types that are included in our Gatsby site on the left. We can see types like allMDX, allShopify, allWordPressPage, or allWordPressPost, as well as a number of other types. These are being added either by our themes, our plugins, or come with Gatsby itself.
What we just did is added this allBlogPost type. Note that we don't have any data inaudible to BlogPost, or satisfies this interface, so we don't get any results, but we also don't get any errors if we query it. This is one of the powerful features of theme customization and defining our types up front.
By declaring all blogposts as an interface, our templates can now rely on the fact that all blogposts exist with a set of predefined fields, which is title, blog, excerpt, and content. This means we can source our data from anywhere, and as long as it fits the blogpost interface, our templates can handle it. Leading to more robust sites, but are resilient against content existing or not existing.
To be able to query WordPress posts, we need to create a set of concrete nodes that implement a blogpost interface. In our case, we'll take a look at the WordPress post type. The WordPress post type includes all the fields we need, including title, blog, excerpt, and content. We can see that we've returned a fully formed node under WordPress post.
In the Gatsby theme product blog Gatsby Node, we're going to introduce another create schema customization lifecycle. In this case, we've created a new type of blogpost WordPress. We've declared that it implements Node, which means that it has an ID, and it also implements blopost, blogpost being the interface we defined earlier.
We also declared to be a child of a specific type. In this case, we've declared it to be a child of WordPress post. Though if we ever need to, we can actually access a blogpost WordPress as a child of any WordPress post, allowing us to make more intricate queries if we ever need to break outside the blogpost interface.
Even if we need to make these more intricate queries, we can always return the blogpost data because the WordPress post satisfies the interface. Note that all the fields that are required match exactly the ones in our blogpost interface earlier.
Since we've used schema customization to define the blogpost WordPress type, the type exists just like the interface exists. Note that we don't have any data in it yet. To create concrete nodes, we'll require crypto at the top of the file. Then we'll introduce an onCreate node lifecycle call.
The onCreate node lifecycle call takes a node, gives us some actions, and allows us to use the create node ID. createNode is the main API we'll use to create the concrete nodes to fill in the blogpost WordPress type.
If the type we're operating on in onCreate node isn't a WordPress post, we don't want to do anything, so we just return. If it is a WordPress post, we can take each of the fields off of the WordPress post and assign them to each of the fields that we want that satisfy the blogpost interface.
In this case, all the fields exist on the node and none of them need to be resolved. When we go over MDX, we'll cover what it looks like to resolve fields that aren't on the node already. Then we call createNode.
CreateNode inserts a concrete node of type blogpost WordPress into the Gatsby Node system. It takes the field data, redeclare the parent ID, and a couple of internal types. This is why we imported crypto before to create a content digest.
Note that even though we've already created the nodes that implement blogpost interface, we still don't get any in either of the all blogpost query, or the all blogpost WordPress query. That's because from here on out, "rm -rf .cache" or "gatsby clean" are your friend, especially when we're working with the onCreate node lifecycle call.
If you make changes to the logic that creates nodes, you will have to remove the cache because the nodes get cached and don't get recreated or some type. Now we can see that all blogpost WordPress and all blogpost both return objects.
We can see that the IDs of these nodes are the same, indicating that they're the same backing node. This is because all blogpost is an interface and returns nodes of different types, such as blogpost WordPress, which is the concrete implementation.
Now that we know we can query for all blogpost, we'll change the query that constructs our pages. We're not querying all blogpost instead of all WordPress post. We'll change our logic to iterate over all blogpost, and we'll still pass in this node slug and the node ID.
Next, we also have to change the query that we're making in our page template. Instead of querying for WordPress post, we're going to query for blogpost. We can leave the rest of the query the same. Note, however, that we do have reference to WordPress post in our page logic. We'll have to change that to blogpost. This will happen for the title and also for the content.
One last place we need to make this change is in the pagesBlog.js file. You'll no longer want to query for all WordPress post, so we'll query for all blogpost. The fields that get returned are the same, but we can leave that. We do need to change the logic or any place that references it inside of our component.
After rerunning the site, we can check out our product blog and see that our blogposts are still there. The interface that we've just created in apparent theme and implemented in a trial theme access query any node, including MDX, WordPress, intentful JSON, or YAML files. In fact, any concrete node you can think of that you can get to implement this interface can be returned here.