Next.js Tutorial - How to Fetch Posts from WordPress GraphQL API [part 7]

Next.js Tutorial - How to Fetch Posts from WordPress GraphQL API [part 7]


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