DEV Community

Ali Nadi
Ali Nadi

Posted on

Headless WordPress Project And How To Deal With? (Real Project)

Hey everyone!

Our team and I (acting as a junior backend) recently finished rebuilding GlobeVM (an enterprise Cloud, IT, and Cybersecurity provider) from a traditional monolithic WordPress site into a Headless architecture.

I wanted to share our entire journey, our tech stack, the massive headaches we faced, and the solutions we engineered. If you are planning a Headless WP build soon, grab a this might save you weeks of debugging!

The Tech Stack

Frontend: Next.js (App Router), React, deployed on Vercel.

Backend: WordPress hosted on Cloudways (Purely as a headless CMS).

Data Structure: Advanced Custom Fields (ACF Pro) + Custom Post Type UI (CPT UI).

SEO: Yoast SEO Premium (via REST API).

Caching: Vercel Edge Cache (ISR) + Redis Object Cache on Cloudways.

During the development and deployment of this website we faced several issues containing the frontend stack itself and traditional features of WordPress. I tried my best to save them all and show them all up here for everyone so that we can discuss on every section of it, maybe we could reach to even something more special :)

Challenge 1: The API Was a Mess ("BFF" Architecture)

When we first started, we were using the default WordPress REST API. Our Next.js frontend was making 8 different fetch() calls just to build the Blog Homepage (fetching posts, authors, categories, tags, ACF fields, etc.). We were also using messy URLs like ?_fields=id,title,acf&_embed.

The Solution:
We built a Backend-For-Frontend (BFF). Instead of Next.js doing the heavy lifting, we wrote a custom PHP plugin in WordPress. We created a single master endpoint (/wp-json/gvm/v1/blog-home). WordPress ran all the complex database queries, bundled the Tags, Hero Article, and Categories into one beautiful JSON array, and cached it in RAM using Transients & Redis. Only one of WordPress default api was used for our categories.

Result: Next.js made one fetch call. The page loads instantly.'

Challenge 2: Handling Vector Icons & ACF

Our design heavily relied on custom SVG icons for our Service Cards. But WordPress blocks SVG uploads by default for security. Furthermore, getting ACF Image fields to play nicely with Next.js was tricky.

The Solution:
It's possible to handle this issue in two ways. First, using plugin and Second, using php codes to force the WP itself to consider this matter.
If you wanna use plugin: Safe SVG to sanitize admin uploads.
If you wanna do the coding: Just get a help from AI :)

Challenge 3: Building a Headless Comment System

We had strict rules: Comments needed Admin approval, and threads could only be 1-layer deep (no replying to a reply).

The Solution:
The GET API: We wrote a custom endpoint that fetched approved comments and built a Parent/Child JSON tree.
The POST API: We created an endpoint to accept new comments. To prevent hackers from bypassing our 1-layer rule via Postman, we wrote an "Absolute Root Finder" (While Loop) in PHP. If someone tried to reply to a reply, the server forcefully pushed their comment up to attach to the Index 0 parent.
The Admin UI: We used a WordPress filter (comment_row_actions) to physically delete the "Reply" button in the WP Dashboard if a comment was already answered, preventing admins from accidentally breaking the 1-layer rule.

Challenge 4: The "View Counter" in a Static World

We wanted a "Popular Articles" section based on view counts. But because Next.js uses ISR (Static HTML), WordPress doesn't know when a user reads an article!

The Solution:
We built a tiny, silent tracker. Whenever a user opens a blog post in Next.js, a client-side useEffect fires a POST request to a custom WP endpoint (/wp-json/abc/v1/track-view/15). WordPress receives it, adds +1 to a custom meta field, and our /popular-posts API queries the database ordered by that meta value. Easy and highly effective!

Challenge 5: The Next.js Draft Preview

How do you let an admin click "Preview" in WordPress when the frontend lives on Vercel?

The Solution:
We hijacked the WordPress preview button using the preview_post_link filter.
When clicked, WP redirects the admin to vercel.app/api/preview?secret=SUPER_SECRET_TOKEN&preview_id=42&route=blog.
Next.js verifies the token, activates Draft Mode, and checks the route parameter to know which React template to load.
Next.js uses an Application Password (HTTP Basic Auth) to securely fetch the unpublished Draft directly from WordPress. We also added autosave detection in PHP (wp_get_post_autosave), so admins see their keystrokes live without even saving the draft!

Challenge 6: The "Double Cache" Trap

When we went to production, Next.js was caching the frontend, and WordPress was caching the backend. When an admin updated a post, the site wouldn't change because WP was feeding Vercel stale JSON.

The Solution:
We killed all traditional WP caching plugins (No WP Rocket, no Breeze, no Varnish). They are dangerous for Headless APIs.
Instead, we used:
Redis Object Cache (Strictly for the database/backend).
On-Demand Revalidation: We installed the WP Webhooks plugin. Now, the exact millisecond an admin clicks "Update Post", WP fires a webhook to Vercel. Vercel instantly purges the cache for only that specific URL.

NOTE: This is about the ISR system as far as we understood, There are two ways to implement the ISR, On-Demand and Time-Revalidation. First one is about to set the NextJS in a way that it stays for the demands (requests) and then refreshes itself. key point is right here, the first visitor see's the cache and the second see's the updated version. with this mechanic ISR gives you the speed of SSG and somehow the live form of SSR caching system. Finally Time-Revalidation is about to set a timer in order to refresh the cache exactly as i mentioned in the previous one. In this strategy you set a time for revalidating the cache and then the webhook is going to be send from wp to next in order to receive and fetch the fresh data.

Challenge 7: Migrating Yoast SEO & Moving to Production

In Headless, you can't just rely on Yoast to inject  tags.
Thankfully, the modern Yoast Premium plugin exposes a beautiful yoast_head_json object in the REST API. We mapped that directly into the Next.js generateMetadata function. We also built a custom endpoint to expose Yoast's 301 Redirects and fed them into next.config.mjs!

Suggestions

Building a Headless WordPress site is not just about using fetch(). It requires treating WordPress strictly as a Database and taking total control of your REST API architecture.
If anyone is working on a Next.js + WP build right now and is stuck on Previews, ACF structures, or Caching conflicts, drop a comment below! I’d love to help out based on what we learned from the GlobeVM build.
It's good to mention this point that, there are many other ways to implement the headless system in either E-commerce and non E-commerce projects. but the key point is about to recognize the figure and the scale of your project. it's not sth that you can easily change the stack or the way (strategy) you code it. It's essential to consider this issue that what exactly you want out of this website, which feature is crucial for your VP's? and what does the brand itself want?
It is also good to mention this point that API plays the most essential rule on headless stack as far as i learn and why? Simple, because there isnt anything called rendering html, css, javascript on the backend side, it is only about API rendering. Somehow everything is relied on the shoulders of frontend. Other parts or just building feilds and custom post types that frontend wants. So choose your frontend stack wisely. Because it is highly demanded in the future of your website the stack that you choose. NextJS was a bit unnecessary for us, cause we could handle it with nuxt or vue as they are more efficient on smaller projects. In my opinion, it would be better to invest more on it so that you can have the finest result.

if your are keen on finding out some massive project examples i would like to suggest you visiting these websites --> https://www.aljazeera.com/ & https://www.bbcamerica.com/

Top comments (0)