Next.js Tutorial - How to Fetch Posts from WordPress GraphQL API [part 7]
Aug 15, 2023
Next.js Tutorial - How to Fetch Posts from WordPress GraphQL API [part 7]
This video is a part of the series where we’re building a headless WordPress blog with Next.js. In this video, you’ll learn how to query the WordPress GraphQL API to fetch the posts, then display on the frontend using Next.js. Repo: https://github.com/iabhinavr/nextjs-blog Website: https://codingreflections.com --------------------------------------- Server providers: Linode: https://codingreflections.com/go/linode/ DigitalOcean: https://codingreflections.com/go/digi … ------------------------------------------------------------- Disclaimer: This video is based on my personal experiences and knowledge. There is no guarantee that the information shared is 100% accurate. Disclosure: This video and its description may contain affiliate links, which can earn us commission if someone purchases products using those links.
Content
0.18 -> in the previous video we had created the home
page of our site which looks like this we had
6.3 -> also installed WordPress and set up the graphql
API so that we can start fetching the data if
12.18 -> it's the first time you are watching this series
then I have given the link to the playlist above
17.64 -> so that you can watch the previous videos and in
this video we will be creating the blog index page
26.04 -> currently the blog index page is displaying
a simple text this is our blog index page
34.32 -> we want to replace that with the list of
posts fetched from the WordPress backend API
42.48 -> so let's go to the code editor this
file the index.js file in the Pages
48.66 -> directory is the route corresponding to
the site home page while the route for
53.76 -> the blog index page is located within the
subdirectory called block let's open that
60.12 -> currently it outputs an H1 heading tag
which we saw just before in the browser
67.86 -> before continuing let me place the editor and the
70.68 -> browser windows side by side so that you
can view the changes as I edit the code
80.4 -> okay
83.46 -> and in the terminal I have already started the
development server by running the command NVM
89.28 -> run Dev first let me delete this line and add
the react fragment instead which wraps the code
98.82 -> this blog index component requires a few other
components so let's import them at the top
105.36 -> the first one is the built-in head component
which allows adding and modifying page title
110.58 -> meta description Etc followed by that we
also want the link and image components
118.62 -> in addition to that we want the custom built site
header component we built in the previous video
129.06 -> here the default function block form needs to
131.58 -> render the list of posts right
so it needs access to that data
138.6 -> the recommended way to do that in next
JS is to provide such data as function
143.34 -> arguments or props in react a prop is an
argument passed to the function components
148.98 -> which contains the data so let's add
a prop called old posts here we have
154.92 -> used JavaScript object restructuring to extract
the property or posts from the argument object
167.04 -> but where is the block home function
called and how to pass the data
172.32 -> luckily you need not worry about that because
it's the job of the next framework called
177.78 -> the default function block home during
build time and to pass the props data
183.18 -> to the function next gives another function
called get static props so you can define a
189.06 -> function named get static props in the same
file which Returns the data as an object
196.56 -> so export a sync function get static props
206.64 -> and the data returned by the get static props
function will be available to the default
211.14 -> function which is the function block form as an
argument that's how the internals of next JS work
219.36 -> also note the difference that the
function block home is the default
223.56 -> export while get static props is a normal export
241.98 -> within this function we can also
perform tasks like fetching data
245.76 -> from the remote API before returning it
251.28 -> so we want to build the query and send a request
to our WordPress API to fetch the first list I
257.94 -> think it would be a good idea to move that
to a separate function so that get static
262.56 -> props remains clean also it allows reusing the
function in other page components if required
269.4 -> so let's go to the file explorer
and within the project root
274.2 -> create a new folder called lib and inside
lib we can create a new file called posts.js
282.9 -> this file is where we will put all the custom
functions related to fetching data for our blog
288.36 -> including the function to fetch the list of posts
so let's export a function called get all posts
302.94 -> then we need to build the graphql query to
fetch the post list so constant query equals
310.14 -> okay let's use the graph iql IDE or our
WordPress dashboard to compose the query
315.84 -> instead of typing it manually so
log into the WordPress dashboard
323.04 -> then open the graph iql IDE
327.54 -> and open the query composer
333.24 -> for each post we want to fetch
all the important details
337.92 -> such as the title slug published date featured
image as well as the categories assigned to it
344.4 -> so on the left side expand the post section then
expand nodes and select the fields one by one
356.04 -> okay posts notes
360.3 -> then we want the published date slug title
370.62 -> post excerpt and the featured image as well
but you might know that featured image itself
378.9 -> is a content type in WordPress that's why
it has its own subtree of fields expanded
384.9 -> then go to the media details section where
we can find the file and the sizes details
392.04 -> that is the image thumbnail sizes generated by
WordPress select the source URL width and height
400.02 -> as I am doing this you can see the
equivalent query on the right side
405 -> then we need the category details as well
remember WordPress allows grouping a single
409.5 -> post into multiple categories category also
has its own subtree like the featured image
419.22 -> expand nodes
423 -> we want the category name and slug in addition
to all this we also want the page info remember
430.56 -> we are fetching the list of posts and blocks can
have hundreds or even thousands of posts and the
438.18 -> page info information helps fetching posts Page by
page so that it will not overload the server it's
445.92 -> an alternative to the traditional limit and offset
based SQL queries and does not slow down even if
452.16 -> you have tens or thousands of rows to fetch okay
you might think that the query is a little long
459.06 -> but the advantage is that it allows getting
all the required data in a single request
466.5 -> on the other hand if we were relying on the rest
API an endpoint returns a fixed set of data fields
475.14 -> and it often contains a lot of unnecessary
information then it's the job of the front-end
481.2 -> developer to Wade through it and extract
the relevant data whereas this one makes
487.08 -> the job easier for the developer okay let
me copy the whole query to the clipboard
498.66 -> come back to the editor and paste it within
our constant inside a property called query
508.86 -> wrap it inside back text so that we can
preserve multiple lines without causing errors
515.64 -> then we need to perform the fetch request
using the JavaScript fetch function
522.42 -> maybe we can put that into a separate file
so that we can reuse it for other queries
527.28 -> so create a new file called graphql
request dot JS within the lib folder
537.24 -> then Define a function export default function
Let It Be async function graphql request
545.64 -> the function accepts one
argument which is our query
553.14 -> constant URL equals the endpoint URL
that is https wp.apinawar.com graphql
565.56 -> Define one more constant called headers
which contains the content type header
574.14 -> set its value to application slash Json now comes
the response constant which equals a weight fetch
584.88 -> the first argument is the URL
590.16 -> the second argument is an object that contains
our headers then set the request method to post
599.34 -> because we are sending it as a post
request then within the request body
604.2 -> pass the query after stringifying
it Json Dot stringify query okay
614.22 -> now we can call the function Json upon
616.8 -> the constant rest to extract
the response in Json format
625.26 -> oh there is a typo here async okay
the function graphql request is
633 -> ready to be used and we want to
import it to the post dot JS file
642.06 -> okay now we can call the function
646.2 -> constant rest Json equals a weight
graphql request and pass the query object
654.66 -> in order to use the avoid keyword
this function should also be async
660 -> now if the request is performed
successfully constant rest Json
664.56 -> contains the complete data including our
post list it can be accessed as data.posts
672.36 -> because if you look at the
format of the return data here
677.88 -> it goes like this data posts nodes
685.26 -> okay finally return all posts
690.24 -> now we can go back to our route
file and call this function get
694.92 -> all posts from within the
get static props function
700.56 -> first of all import the new
function import get all posts
710.52 -> uh there is one change I want to make
there was no need to set it as export
715.2 -> default normal export is enough because this
file is not a route file it's just a collection
721.56 -> of functions so all functions within this file
have the same status so no need for a default
727.56 -> export and the import statement becomes
import get or posts within curly brackets
736.38 -> that's how you import individual
functions from map file
740.88 -> call the get all posts function and assign
its value to a constant named all posts
747.66 -> now return an object which contains
all posts within the props property
754.68 -> this is how you return data from
get static props which will then
759.48 -> be available to the function component
let's get back to the block home function
766.56 -> and in the browser open the blog index page
772.02 -> let's set the page title using the head component
780.06 -> set the title text as blog and it has changed
787.2 -> first we want to create a hero section
which shows the title And the tagline
791.58 -> on top of a background image the side
header should also appear on top of that
801.12 -> let's add a container div element set the
class name attribute height 50 percent of
808.38 -> the viewport height minimum height let it be 20
Ram later you can adjust it to make it responsive
816.24 -> on all devices for the background image we can
use the same image used on the side home page
824.88 -> BG URL home.jpg
830.82 -> okay the image is showing
set the position to relative
839.04 -> then add an absolute position div
inside that to create the overlay effect
846.9 -> background slate 900 inside 0 Z
index 0 and opacity 40 percent
864.24 -> okay that looks good now call
the side header component
873.54 -> it's showing up let's fix it
by adding a few class names
881.94 -> first one is header blog also set the insert index
to 10 and position relative okay that looks good
894.96 -> maybe we can put it inside a
container div and Center it
901.98 -> class name equals container
906.12 -> set the maximum width on large screen devices
912.66 -> and MX Auto class to center it now put
the site header component inside that
920.16 -> okay now it appears centered below
that we want to display the title
925.44 -> that is blog followed by a tagline
that says read our latest articles
933.06 -> so are the text block inside
an H1 heading tag and the text
937.98 -> read our latest articles within a paragraph tag
947.82 -> it's there but invisible because the
color is still black let's fix that
958.5 -> text size 6 XL and text Center
963.48 -> color slide 100 relative positioning
is an index 10 vertical padding 8
973.62 -> okay for the tagline position relative is at
index 10 text sender color slide 200 text size 2XL
984.06 -> okay let's move on to the main section where we
will iterate the list of posts and display them
991.92 -> so create an HTML main tag
and inside that a section tag
999.12 -> set the class name as post
list and give some top margin
1009.86 -> within that add an unordered list tag
1013.64 -> open curly brackets to iterate the JavaScript
array we are gonna use the map function to do that
1024.38 -> let the variable post be the individual post item
the map function Returns the list item tag there
1032.66 -> is some error cannot read properties of undefined
let's try refreshing the page and now it's working
1041.84 -> set the key attribute to post dot slug
1045.74 -> because whenever we are iterating an
array we want to set the key attribute
1054.68 -> we want to show each item in a two column format
on the left side we want to display the featured
1060.5 -> image and on the right side we want to Output the
post title except date and the category we can use
1068.06 -> the CSS grids to achieve that so set the display
to grid and the number of grid columns to 5.
1079.82 -> because here we want to display
ethernet 2 is to 3 width ratio
1084.62 -> let the column Gap be 4 and margin bottom 4.
1091.04 -> then inside that create two new divs add
class called span 2 for the first div
1099.02 -> it's gonna contain the featured image
so add a custom class featured image
1107.84 -> for the second div called span 3.
1116.84 -> okay I think there is no need for
this class now so let me remove it
1123.5 -> let's start with the second div
before dealing with the featured image
1131.24 -> the first element we want to
Output is the post title inside
1137.54 -> and its two heading tag
1140.84 -> and we want the title linking to the individual
post page let's use the link component for that
1149.24 -> link href equals blog slash post dot
Slug and the link text is post dot title
1158.06 -> okay the post titles are already showing up and
they are linked to the corresponding post pages
1169.04 -> that means it's working
1172.4 -> below the title we want to show the post
except let's use a div element for that
1181.4 -> we can use the dangerously set inner
HTML attribute to set the divs inner
1186.62 -> HTML one thing I want to mention here is that the
excerpt is already an HTML string not plain text
1196.46 -> let's check the graph iql IDE to verify
that when you check the accept property
1204.14 -> you can see a field called format which
offers two options row and rendered
1210.68 -> rendered is the default option and it
outputs the content as an HTML string
1220.16 -> instead if we set the format to row the result
will be null because it requires authentication
1226.1 -> that's how the plugin WP graphql works fetching
any field in row format requires authentication
1235.04 -> maybe I will show you that in a later video
for now let's set the format to rendered
1245.54 -> okay let's set the dangerously set inner
HTML attribute value to post dot accept
1253.52 -> the excerpt is showing up on the right side
let's display the post categories below that
1260.24 -> insert a new div posted under iterate post dot
categories dot nodes array using the map function
1269.78 -> category is the individual category we can
link category name text to the category
1276.68 -> archive page using the link component
href equals category slash category dot
1283.22 -> slug then set the key attribute also to
the corresponding category dot slug value
1290.9 -> link text is category dot name now
the categories are showing up posted
1296.84 -> under inspiration posted under photography Etc
let's beautify that by adding some CSS classes
1305.72 -> starting with the post title it's two element
1310.7 -> vertical padding p y four now the link inside that
1318.8 -> let the link color be light blue
1323.06 -> increase the text size also change the
hover color to slightly darker blue color
1331.94 -> okay now comes the post excerpt
1336.56 -> make the text slightly bigger text
LG then we have the categories py4
1345.44 -> then the category link
1352.34 -> okay now it looks nice we want to deal with the
featured image it requires a little more work
1364.64 -> because as you can see in our graphql request
we want to go through all these details
1372.26 -> media details sizes and things like that
also some hosts may not have a featured
1378.8 -> image set from WordPress so we have to take into
account that as well and set if default image
1388.82 -> okay let's create a new file called featured
image.js inside the components directory
1395.18 -> import the image and Link
components at the top of the file
1403.16 -> then export the default function
featured image the purpose of this
1407.48 -> function is to return the featured
image for a given Post in HTML format
1418.76 -> it receives the current post as an argument
1421.94 -> create a variable IMG which is going to contain
the image data for now set its value to an empty
1428.3 -> string now let's set the default image in
case no featured image is set from WordPress
1435.56 -> constant default featured image let's use
an image hosted on the vectors site itself
1449.18 -> okay let me use this image
1453.26 -> set its URL as our constant value we want
to set the default width and height as well
1460.88 -> keep it like that next let's check if
the post has already a featured image set
1466.82 -> so if it's set then this field
featured image will not be null
1476.9 -> so we can use that inside our if condition
1484.1 -> let size equals it's
available within media details
1489.86 -> size equals post dot featured image dot
not DOT media details dot sizes of zero
1502.28 -> that means we are using the first item in the
sizes array which is the full size image others
1509.66 -> are thumbnail sizes generated by WordPress
maybe we can use them later to make the images
1516.26 -> responsive for now it's enough let's use that
image to set our IMG variable make it an object
1529.88 -> SRC property equals sizes dot
Source URL with size dot width
1547.7 -> and height equals size dot height okay
1552.26 -> else if featured image is null
we will use the default values
1563.12 -> the function should return the featured
image linked to the parent post
1572.96 -> so let's use the link and image components
1596.66 -> okay let's go back to the post index page
and import the featured image component
1610.76 -> now we can call it from here featured
image pass the current post as a prop
1620.24 -> but we got an error invalid SRC prop hostname
wp.apnivore.com is not configured under images
1628.16 -> in your next dot config.js why it happened
because we are loading an image from an
1635.06 -> external domain and next.js requires you
to add the domain names to the config file
1640.88 -> before you can load images from them so we
need to go to the next configuration file
1648.98 -> then add a new property called images remote
patterns you can check the documentation to see
1656.72 -> more details about this now just understand that
we need to add it to make it work protocol https
1667.34 -> hostname the URL here in
this case our WordPress URL
1674.84 -> followed by Port Let It Be an MD string for now
1681.32 -> you might get a small warning here for
keeping it empty but for now it doesn't matter
1690.38 -> path name any path so add a wild card okay now
1695.42 -> that we have modified the config
file we want to restart the server
1704.36 -> so stop the current running server
and execute nbm run Dev again
1713.12 -> okay now we can view the featured images besides
1716.3 -> each post but the size is a little
off so we can style it and fix it
1724.94 -> let's see how it looks in full screen
1728.06 -> okay so we want to do two things first
we want to style this wizard image and
1734.6 -> second we want to put everything inside a
container element so that it appears centered
1746.18 -> let's add the container class to the section tag
1750.62 -> container MX Auto and Max
width on large devices Max w5xl
1763.1 -> okay that's fixed next we want to style the
featured image let's give it a rounded corner
1770.18 -> and also fix its size on smaller screen sizes
now it's towards the top we want to stretch it
1777.56 -> to the full height so go to the featured image
file and add class names to the image component
1789.92 -> first let's set the height
to 100 percent it's full
1796.16 -> but now its aspect ratio is screwed
1800.12 -> we can fix that by setting the object
fit property to cover object cover
1807.74 -> okay also make the corners rounded by adding the
class around it Excel and it's also responsive
1818.72 -> I think it's enough for now I am not
going into more minute details as it
1823.46 -> can make the video longer but before ending
this video let's add the site footer as well
1832.34 -> let's go to the components directory and
create a new file called site footer.js
1841.22 -> spot default function site footer
1847.16 -> return we just want to display a copyright
notice that's all just a simple site photo
1855.2 -> so add an HTML photo tag and set
the ID attribute to site footer
1865.16 -> okay copyright year 2022 Dash 2023 followed by
the site name now let's go to the blog index page
1880.34 -> and just like we did with the site header
component import side footer as well
1887.96 -> then call it after the closing main tag
1903.02 -> it's working
1907.28 -> let's style that with a little bit
of padding and a background color
1915.86 -> div class name equals py3 vertical padding 3
1927.86 -> then set the display to flex
justify center background slide 200
1939.74 -> okay all right I hope that's enough
1947.18 -> and in the upcoming videos we
will create the remaining pages
Source: https://www.youtube.com/watch?v=Fl_k4iKliys