This note contains only the "difficult" parts when creating a Next.js website from Wordpress. You should read the official documetation and also things mentioned in this note (it's about Gatsby and WP).
I prefer Next.js other than Gatsby when using with Wordpress because I want to use for free the "incremental building" functionality. As I know, if we want something like that with Gatsby, we have to use Gatsby Cloud (paid tiers).
The following steps are heavily based on this starter, which means that some packages/settings have already been set up by this starter.
Using Local for a local version of Wordpress (WP) site. Read more in this blog. From now, I use math2it.local for a local WP website in this note and math2it.com for its production version.
In WP, install and activate plugin WPGraphQL.
Copy
.env.local.example
to .env.local
and change it content.The site is running at http://localhost:3000.
How pages are created?
pages/abc.tsx
leads tolocahost:3000/abc
pages/xyz/abc.tsx
leads tolocalhost:3000/xyz/abc
pages/[slug].tsx
leads tolocalhost:3000/<some-thing>
. In this file,- We need
getStaticPaths
to generates all the post urls. - We need
getStaticProps
to generate theprops
for the page template. In this props, we get the data of the post which is going to be created! How? It gets theparams.slug
from the URL (which comes from the patternpages/[slug].tsx
). We use this params to get the post data. The[slug].tsx
helps us catch the url's things. Read more about the routing. - Note that, all neccessary pages will be created before deploying (that why we call it static)
Build and run vercel environment locally before pushing to the remote.
Link to the current project
Run build locally,
Define
/styles/main.scss
and import it in _app.tsx
✳️ Define a new class,
Use as:
className="thi-bg"
✳️ Define a new color,
Use as:
className="text-main bg-main"
✳️ Custom and dynamic colors,
Use as:
className="bg-[#1e293b]"
Check this doc and the following instructions.
Install and activate WP plugin wp-graphql-jwt-authentication.
Modify
wp-config.php
Get a refresh token with GraphiQL IDE (at WP Admin > GraphQL > GraphiQL IDE),
Modify
.env.local
Link the preview (
id
is the id of the post, you can find it in the post list).It may not work with math2it.local but math2it.com (the production version).
✳️ VSCode + ESLint + Prettier.
Follow instructions in Build a website with Wordpress and Gatsby (part 1) with additional things
🐝 Error: Failed to load config "next" to extend from?
✳️ Problem
Unknown at rule @apply
when using TailwindCSS.Add the folloing settings in the VSCode settings,
✳️ 'React' must be in scope when using JSX
✳️ ...is missing in props validation
In
.prettierrc
There are some rules taking longer than the others. Use below command to see who they are.
If you wanna turn off some rules (check more options),
Run
TIMING=1 npx eslint lib
again to check!Update: I decide to use self-defined types for what I use in the project.
We use GraphQL Code Generator (or codegen). Read the official doc.
Below are my answers,
👉 Official doc.
Want to use next.js's environment variable (
.env.local
) in the codegen's config file? Add the following codes to codegen.ts
Generate the types,
If you want to run in watch mode aloside with
npm run dev
Then modify
package.json
Now, just use
npm run dev
for both. What you see is something like thisFor example, you want to query categories from
http://math2it.local/graphql
with,After run the generate code, we have type
CategoriesQuery
in graphql/gql/graphql.ts
(==the name of the type is in the formulas <nameOfQuery>Query
==). You can import this type in a .tsx
component as follow,Add
/* GraphQL */
before the query string! Read more in the official doc for other use cases and options!The starter we use from the beginning of this note is using typescript's built-in
fetch()
to get the data from WP GraphQL (check the content of lib/api.ts
). You can use Apollo Client instead.✳️ Query different queries in a single query with alias,
Otherwise, we get an error Fields 'posts' conflict because they have differing arguments. Use different aliases on the fields to fetch both if this was intentional.
👉 Basic Features: Image Optimization | Next.js
👉 next/image | Next.js
👉 (I use this) next/future/image | Next.js
👉 next/image | Next.js
👉 (I use this) next/future/image | Next.js
Local images,
Inside an
<a>
tag?I use below codes,
(To apply "blur" placeholder effect for external images, we use plaiceholder)
Remarks:
- If you use
fill={true}
forImage
, its parent must have position "relative" or "fixed" or "absolute"!
- If you use plaiceholder, the building time takes longer than usual. For my site, after applying , the building time increases from 1m30s to 2m30s on vercel!
🐝 Invalid next.config.js options detected: The value at .images.remotePatterns[0].port must be 1 character or more but it was 0 characters. → Remove
port: ''
!We use only the CSS for the placeholder image. We gain the loading time and also the building time for this idea!
If you wanna add a div (with loading effect CSS only).
Some remarks:
- Using
display=optional
- Add Google font to
pages/_document.js
, nextjs will handle the rest.
Next.js currently supports optimizing Google Fonts and Typekit.s
Catch all routes:
pages/post/[...slug].js
matches /post/a
, but also /post/a/b
, /post/a/b/c
and so on.Optional catch all routes:
pages/post/[[...slug]].js
will match /post
, /post/a
, /post/a/b
, and so on.The order: predefined routes > dynamic routes > catch all routes
Fetch menu data from WP and use it for
navigation
component? Read this for an idea. Note that, this data is fetched on the client-side using Vercel's SWR.I create a constant
MENUS
which defines all the links for the navigation. I don't want to fetch on the client side for this fixed menu.Different classes for currently active menu?
Remark:
router
's pathname
has a weekness when using with dynamic routes, check this for other solutions.URL format from Wordpress:
/category/math/
or /category/math/page/2/
👉 Create /pages/category/[[...slug]].tsx
(Read more about optional catching all routes)To query posts with "offset" and "limit", use this plugin.
Remark: When querying with graphql,
$tagId
gets type String
whereas $categoryId
gets type Int
!If you need: when submitting the form, the site will navigate to the search page at
/search/?s=query-string
, use router.push()
!✳️ Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?
Have this when using
Wrap it with
<a>
tag,🐝 If you use
<a>
, a linting problem The href attribute is required for an anchor to be keyboard accessible....Or add below rule to
.eslintrc
(not that, estlint detects the problem but it's still valid from the accessibility point of view ). Source.👉 Read more in the official tut.
✳️ Warning: A title element received an array with more than 1 element as children.
Read this answer to understand the problem.
✳️ Element implicitly has an 'any' type because expression of type '"Authorization"' can't be used to index type '{ 'Content-Type': string; }'.
✳️ (Codegen's error) [FAILED] Syntax Error: Expected Name, found ")".
✳️ You cannot define a route with the same specificity as a optional catch-all route ("/choice" and "/choice\[\[...slug\]\]").
It's because you have both
/pages/choice/[[slug]].tsx
and /pages/choice.tsx
. Removing one of two fixes the problem.✳️ Could not find declaration file for module 'lodash'
✳️ TypeError: Cannot destructure property 'auth' of 'urlObj' as it is undefined.
Read this: prerender-error | Next.js. For my personal case, set
fallback: false
in getStaticPath()
and I encountered also the problem of trailing slash. On the original WP, I use /about/
instead of /about
. Add trailingSlash: true
to the next.config.js
fixes the problem.✳️ Error: Failed prop type: The prop
href
expects a string
or object
in <Link>
, but got undefined
instead.There are some
Link
s getting href
an undefined
. Find and fix them or use,✳️ Restore to the previous position of the page when clicking the back button (Scroll Restoration)
Remark: You have to restart the dev server.