Using Headless Wordpress with NextJs

Emre Yasin Çolakoğlu
Kunduz, Inc.
Published in
7 min readFeb 8, 2022

During the course of a startup’s life, your expectations from the website will change. While at early stages simply being online would suffice, it is expected that this channel will develop in the future and bring you new users.

And with this change in requirements, we must also take a look at what tools we use and how we might use them. Here at Kunduz, we are using Wordpress as our website solution for more than 3 years now. But lately it just wasn’t enough.

When we first built our website in 2018 our requirements were just to be able to be Googled. We had practically no content, only one landing page which was the homepage and a plans page where we displayed our products.

Kunduz circa 2018

When 2019 came our requirements were very different. We wanted our content editors and various employees to be able to publish static pages without the help of a developer. Our newly started blog was doing quite well. But we didn’t have anything else to offer to our users.

Kunduz (now)

During the pandemic we built various products and features for our users. But some developments were made to increase our reach in Google search results as well. One of them was our question indexing websites. We indexed a portion of our questions to attract more users. Now we had another type of content served from our websites aside from blog posts. Naturally, we wanted to show related content on those pages. 🕸️

Wouldn’t it be nice if you could see some already answered questions about the subject you are reading about? Or a series of videos explaining that particular subject? That’s what we wanted to build.

However, actually doing this was a challenge. None of our developers (including yours truly) knew PHP or wanted to learn PHP. We were fine with creating a template for Wordpress but anything more than that was off the limits. That’s why we failed to implement necessary changes to design a more streamlined experience for our users. ❌

We researched different tools to address these issues. We evaluated platforms like Webflow, Ghost, Strapi etc but none of them could single-handedly solve all our problems. They were either too primitive or too complicated for our use-cases. We also considered the migration process of our existing 1000+ pages of content and the education period of our editors.

When we realized that we couldn’t solve this solution with a third party tool, we decided to build our own solution.

Enter: Wordpress as Headless CMS

To fix all of the problems I mentioned, we decided to use Wordpress as a headless CMS and use NextJs as the presentation layer. This way we could

  • Develop with a language we were already fluent in
  • Have more integration options
  • Not lose (or have to migrate) 3 years worth of content
  • Not lose site editors know-how

While searching through the internet for examples and articles from developers who walked on this path before me, I stumbled upon an example from the NextJs team. The “Wordpress & GraphQL & NextJs” hybrid.

This immediately gave me a lightbulb moment and answered the most deeply buried, dreaded question there ever is. How to deal with nested data? Unlike traditional REST, with GraphQL, you can request relationship data in the same request. With REST, this would have to be N amount of requests depending on the relationship count. And believe me there are lots of relations in a traditional blog post. Author, category, seo meta, tags, main image to name a few. 💡

Installing GraphQL plugins

The first order of business was to install the necessary GraphQL plugins so that development could begin. The wonderful GraphQL team made everything very straightforward and installation was a breeze. 🙏

After installing the common plugin extensions like Yoast Seo, Advanced Custom Fields and Custom Post Types, we were ready to go.

Migrating from WPML to PolyLang

Kunduz.com is a multilanguage website. We used a translation and localization plugin called WPML for three years without any issues. But sadly it was not allowing us to query with language data when requesting blogs posts or pages. For example, we were not able to query for the most recent 20 blog posts published for Turkey. That’s why we migrated our localization solution to another Wordpress plugin called PolyLang. PolyLang both offered a migration tool and GraphQL plugin and it was the natural selection for us. During the migration process we still needed to patch here and there, mainly with pages sharing the same slug for different locales. Overall, the migration was done without any hiccups.

Bootstrapping the NextJs Project

After the Wordpress part was done, we started the development of the NextJs project. Since there were only three major responsibilities of Wordpress we proceeded quickly. At the very basic level, NextJs had to

  • Display a static page
  • Display the list of blog posts
  • Display a single blog post

During the development, we noticed some architectural decisions to make about the data fetching. We could just create a new axios instance and request data from Wordpress endpoint in our getServerSideProps function. But this wasn’t the right way and this would never scale. 📈

So, with the help of the handy next-connect package, we started to collect these functions into middlewares. This way, all common initialization logic like authentication, error handling and custom headers could be shared among functions.

When done, we had 5 middlewares;

  • Elastic Middleware
  • Kunduz Api Middleware
  • Wordpress Middleware
  • Session Middleware
  • Cache Middleware

The names are pretty self explanatory. We use different backends to store different types of content. 🏦

Kunduz

And using next-connect we could fetch a blog post in getServerSideProps function like so;

We opted for the builder pattern, so that each builder shouldn’t deal with client bootstrapping etc..

Perils of Wordpress Migration

Next up was moving Wordpress to a subdomain, so that we could use our primary domain with NextJs. Given my history with Wordpress, I was very skeptical about this step of the process. There were documented cases of infinite redirect loops, SSL issues, login&logout issues. 👻

The actual process was very straight forward. We just updated the “Wordpress Address” section under Settings -> General and voila! Or so we thought.

After we saved the changes, our Wordpress installation froze. We couldn’t navigate the site, users couldn’t access the site because GraphQL endpoint wasn’t responding. And our database was under a very heavy load. Upon a closer inspection we determined the root cause was the Yoast SEO plugin. While searching for a solution, we came across a plugin called Yoast Helper that claims to fix these kinds of issues and I started to read the source code.

The fix was quite simple (finding the fix wasn’t), we just had to delete all records in certain Yoast tables in our database. Once we did that, the issue was resolved instantly. 🤌

Other Improvements

Sitemaps: We wrote a function to get all urls of blog posts and pages from Wordpress and used these urls to create a .txt sitemap.

Error Tracking: We added SentryJS to track all the errors. We are currently sitting at %99.9 crash free.

Sessions: Just as a tease, we started retrieving user data and displaying a cheeky welcome message on our blog if the user is logged-in.

Heyoo

Overall

We are quite happy with how things turned out. We can comfortably serve our users in 2.5 seconds, we can integrate any tool in existence, we improved our analytics and data visibility a lot, our stack is current and up-to-date, we are using technologies that are easy to find new developers. There are still areas to improve but achieving a migration of this size in just 3 weeks and without any major issues or downtime is quite a feat itself. 💪

If you made it to this point, we hope you enjoyed reading. If you are also interested in web development and want to be a part of our team, you can click this link and reach out to us.

--

--