Query any page by it’s path using WPGraphQL
By Jason Bahl
December 23rd, 2021
One of the most common ways WordPress is used, is by users visiting a URL of a WordPress site and reading the content on the page.
WordPress has internal mechanisms that take the url from the request, determine what type of entity the user is requesting (a page, a blog post, a taxonomy term archive, an author’s page, etc) and then returns a specific template for that type of content.
This is a convention that users experience daily on the web, and something developers use to deliver unique experiences for their website users.
When you go “headless” with WordPress, and use something other than WordPress’s native theme layer to display the content, it can be tricky to determine how to take a url provided by a user and convert that into content to show your users.
In this post, we’ll take a look at a powerful feature of WPGraphQL, the
nodeByUri query, which accepts a
uri input (the path to the resource) and will return the node (the WordPress entity) in response.
You can use this to re-create the same experience WordPress theme layer provides, by returning unique templates based on the type of content being requested.
One of the benefits of GraphQL is that it can provide entry points into the “graph” that (using Interfaces or Unions) can return different Types of data from one field.
WPGraphQL provides a field at the root of the graph named
nodeByUri. This field accepts one argument as input, a
$uri. And it returns a node, of any Type that has a uri. This means any public entity in WordPress, such as published authors, archive pages, posts of a public post type, terms of a public taxonomy, etc.
If you’ve not already used the “nodeByUri” query, it might be difficult to understand just reading about it, so let’s take a look at this in action.
Here’s a video where I walk through it, and below are some highlights of what I show in the video.
Let’s start by querying the homepage.
First, we’ll write our query:
In this query, we’re doing a few things.
First, we give our query a name “GetNodeByUri”. This name can be anything we want, but it can be helpful with tooling, so it’s best practice to give your queries good names.
Next, we define our variable input to accept:
$uri: String!. This tells GraphQL that there will be one input that we don’t know about up front, but we agree that we will submit the input as a string.
Next, we declare what field we want to access in the graph:
nodeByUri( uri: $uri ). We’re telling WPGraphQL that we want to give it a URI, and in response, we want a node back.
nodeByUri field is defined in the Schema to return the GraphQL Type
UniformResourceIdentifiable, which is a GraphQL Interface implemented by any Type in the Graph that can be accessed via a public uri.
If we inspect the documentation in GraphiQL for this type, we can see all of the available Types that can be returned.
The Types that can be returned consist of public Post Types, Public Taxonomies, ContentType (archives), MediaItem, and User (published authors are public).
So, we know that any uri (path) that we query, we know what we can ask for and what to expect in response.
Now that we have the query written, we can use GraphiQL to execute the query.
GraphiQL has a “variables” pane that we will use to input our variables. In this case, the “uri” (or path) to the resource is our variable.
First, we will enter “/” as our uri value so we can test querying the home page.
Now, we can execute our query by pressing the “Play” button in GraphiQL.
And in response we should see the following response:
We can see that when we query for the home page, we’re getting a “ContentType” node in response.
We can expand the query to ask for more fields of the “ContentType”.
If we look at the home page of https://demo.wpgraphql.com, we will see that it serves as the “blogroll” or the blog index. It’s a list of blog posts.
This is why WPGraphQL returns a “ContentType” node from the Graph.
We can write a fragment on this Type to ask for fields we want when the query returns a “ContentType” node.
If we look at the documentation in GraphiQL for the
ContentType type, we can see all the fields that we can ask for.
If our goal is to re-create the homepage we’re seeing in WordPress, then we certainly don’t need all the fields! We can specify exactly what we need.
In this case, we want to ask for the following fields:
- name: the name of the content type
- isFrontPage: whether the contentType should be considered the front page
- contentNodes (and sub-fields): a connection to the contentNodes on the page
This should give us enough information to re-create what we’re seeing on the homepage.
Let’s update our query to the following:
And then execute the query again.We now see the following results:
If we compare these results from our GraphQL Query, we can see that we’re starting to get data that matches the homepage that WordPress is rendering.
There’s more information on each post, such as:
- post author
- avatar url
- post date
- post content
- uri (to link to the post with)
We can update our query once more with this additional information.
The query is now getting us all the information we need, but it’s starting to get a bit long.
We can use a feature of GraphQL called Fragments to break this into smaller pieces.
I’ve broken the query into several Fragments:
Fragments allow us to break the query into smaller pieces, and the fragments can ultimately be coupled with their components that need the data being asked for in the fragment.
Here, I’ve created 3 named fragments:
And then we’ve reduced the
nodeByUri field to only ask for 2 fields:
The primary responsibility of the
nodeByUri field is to get the node and return it to us with the
__typename of the node.
ContentType fragment is now responsible for declaring what is important if the node is of the
The responsibility of this Fragment is to get some details about the type, then get the content nodes (posts) associated with it. It’s not concerned with the details of the post, though, so that becomes another fragment.
The Post fragment defines the fields needed to render each post, then uses one last Author fragment to get the details of the post author.
We can execute this query, and get all the data we need to re-create the homepage!! (sidebar widgets not included)
Now, we can expand our query to account for different types.
If we enter the
/about path into our “uri” variable, and execute the same query, we will get this payload:
We’re only getting the
__typename field in response, because we’ve told GraphQL to only return data
...on ContentType and since the node was not of the
ContentType type, we’re not getting any data.
So now, we can write a fragment to ask for the specific information we need if the type is a Page.
And we can work that into the `nodeByUri` query like so:
So our full query document becomes (and we could break the comments of the page into fragments as well, too):
And when we execute the query for the “/about” page now, we are getting enough information again, to reproduce the page that WordPress renders:
We’ve looked at querying the home page and a regular page, so now let’s look at querying a category archive page.If we navigate to https://demo.wpgraphql.com/category/alignment/, we’ll see that it’s the archive page for the “Alignment” category. It displays posts of the category.
If we add “/category/alignment” as our variable input to the query, we’ll now get the following response:
So now we can write our fragment for what data we want returned when the response type is “Category”:
Looking at the template we want to re-create, we know we need to ask for:
- Category Name
- Category Description
- Posts of that category
- avatar url
So we can write a fragment like so:
And now our full query document looks like so:
And when I execute the query for the category, I get all the data I need to create the category archive page.
Any Type that can be returned by the
nodeByUri field can be turned into a fragment, which can then be coupled with the Component that will render the data.