NextJS and the WordPress REST API - Kevin Uriel Fonseca
I learned this so I could manage posts talking about improvements in my projects from one single place which is this website. I’m trying to make it everything more centralized also.
Starting Off
I’m not going to be talking about NextJS. By now, if you got here, that means you’re a programmer or looking to become one. Learn to be a self learner and read the documentation and/or watch YouTube which I believe is the best school online!. What I’m going to do is to help you to create tools or utilities to make it more easy for you to write clean code.
The first one, my favorite that I use in every single project; the api.js file, this one will be the root of your front-end API routes. Take a look at it:
import axios from 'axios'// HANLDE API REQUESTSconst api = axios.create({ baseURL: `https://YOUR_WORDPRESS_DOMAIN/wp-json/wp/v2`, headers: { 'Content-Type': `application/json`, // YOU CAN ALSO ADD MORE HEADERS IF REQUIRED; A GOOD USE-CASE IS AUTHENTICATION PURPOSES },})api.interceptors.response.use( (res) => { return res }, (err) => { let res = err?.response if (res?.status === 401 && res?.config && !res?.config?._isRetryRequest) { // YOU CAN CREATE/CALL A FUNCTION HERE TO TRIGGER WHENEVER THEREA FALSY RESPONSE } })export default api
As you might have noticed, you need to install axios! to make the HTTP request calls.
The Complexitivity is Increasing – Index.js File
Now, its time to continue with our pages and API route calls.
Usually the first page I think about when making stuff with WordPress is the index page or the page that fetches the posts. NextJS will force you to create said file within the pages folder, name it as index.js and then make whatever design you want and you can later proceed to modify it.
That being done, we need to call our getServerSideProps method given by NextJS. This will make sure to fetch everything in the backend so it can be used for social media and SEO in general. Take a look in what this page might look like:
import { withRouter } from 'next/router'
// ACTIONS
// HELPERS
import Row from 'react-bootstrap/Row'
import { getWordPressPosts } from '@/actions/wordpress'
import SingleWordPressPost from '@/components/singleWordPressPost'
export const getServerSideProps = async (context) => {
const params = `?page=1&per_page=10`
const wordPressPostListing = (await getWordPressPosts(params)()) || []
return {
props: {
params: params,
serverWordPressListingPosts: wordPressPostListing,
},
}
}
const Blog = ({ params, serverWordPressListingPosts, router }) => {
return (
<>
<h1>Blog Page</h1>
<div className="container mt-3">
<Row>
{serverWordPressListingPosts?.length > 0 ? (
<div className="col-blog" id="fetch-more">
{serverWordPressListingPosts.map((wp, index) => (
<SingleWordPressPost key={wp.id} wp={wp} />
))}
</div>
) : (
<h2>Nothing found</h2>
)}
</Row>
</div>
</>
)
}
export default withRouter(Blog)
Obviously this is just the design, the magic actually happens in line 10; all of this happens while the server is loading. This is the function:
export const getWordPressPosts = (params) => async (dispatch) => {
try {
const res = await api.get(`/posts${params}`)
return res.data
} catch (err) {
// const error = err.response.data.message;
const error = err?.response?.data?.error?.errors
const errors = err?.response?.data?.errors
if (error) {
// dispatch(setAlert(error, 'danger'));
error &&
Object.entries(error).map(([, value]) => toast.error(value.message))
}
if (errors) {
errors.forEach((error) => toast.error(error.msg))
}
toast.error(err?.response?.statusText)
return { msg: err?.response?.statusText, status: err?.response?.status }
}
}
This function is straigforward, “call the api file that was created early and then add some query” to look in the exact route we need for the fetching of posts.
That’s pretty much what we need for the index.js page. I’m not adding pagination or anything fancy.
The Single Page – Individual Post
This is cool, you actually need to take your time to match the URL of your already-existing WordPress blog. Let’s say, my URLs usually look like this: https://kevinurielfonseca.me/309/life/fuck-you-all-i-have-chosen-peace-over-people/. The way is built is as follow, “domain/:id/:category/:slug” which suggest that in order to build this in Next, you will need to create 2 folders [id]/[category]/[slug].js
. Don’t panic!, using the brackets just means the it will be “changeable” which also means “dynamic”. This is what said page might look like:
import { withRouter } from 'next/router'
// ACTIONS
// HELPERS
import Row from 'react-bootstrap/Row'
import { getWordPressPost } from '@/actions/wordpress'
import Content from '@/layout/Container'
import Sidebar from '@/layout/Sidebar'
export const getServerSideProps = async (context) => {
const params = `${context.query.id}`
const postId = `?post=${context.query.id}`
const wordPressPost = (await getWordPressPost(params)()) || null
return {
props: {
params: params,
serverWordPressPost: wordPressPost,
},
}
}
const FetchHtml = ({ text = `` }) => {
return (
text && (
<div
className="fetchHtml"
dangerouslySetInnerHTML={{
__html: text.replace(/\n\r?/g, ''),
}}
></div>
)
)
}
const SingleBlog = ({ params, serverWordPressPost, router }) => {
return (
<div className="container mt-3">
<Row>
<Content>
<FetchHtml text={serverWordPressPost.content.rendered} />
</Content>
<Sidebar>SIDEBAR</Sidebar>
</Row>
</div>
)
}
export default withRouter(SingleBlog);
The function to call the route is very similar, the only line that is different is this one:
const res = await api.get(`/posts/${id}`)
return res.data
Again, nothing fancy, just the post data. That’s about it!.
Bye Bye! 🙂
COMMENTS
Oh, thank you for letting me know about that. It is actually useless in the code that I posted on the article, you can delete it if you want. The thing is that I forgot to take it off when writting the article; I was using it to fetch the comments corresponding the the postID. You can leave it there and retrieve the comments by going to this website: https://developer.wordpress.org/rest-api/reference/comments/ . The way to call the WordPress comments API would be something like “comments?post=POSTID”.
Thanks for reading!.
Would you tell me why is it that you need the postId variable?