Building Modern Websites with Headless WordPress, Next.js & Elementor

Did you know that 71% of developers prefer using headless CMS’ for their flexibility and performance? This comprehensive guide will show you how to leverage headless WordPress with Next.js alongside Elementor to build fast, modern websites with powerful user interfaces.

What is Headless WordPress?

Headless WordPress is a modern approach where the front end is decoupled from the back end. WordPress serves as a content management system (CMS) while frameworks like Next.js render the front end. This setup allows developers to create dynamic websites with enhanced performance, scalability & flexibility.

Key Components:

  • WordPress: Acts as the backend CMS, allowing content creators to manage posts, pages & media effortlessly.
  • Next.js: React-based framework that provides server-side rendering (SSR), static site generation (SSG) & seamless routing for faster performance.
  • Elementor: A powerful page builder for WordPress that enables users to design complex layouts and manage content through a visual interface.

Implement Headless WordPress with Next.js & Elementor Step-by-Step

1. WordPress Setup

Install Elementor. Make sure the Elementor plugin is installed and active in your WordPress instance. Enable headless functionality: You can enable REST API or GraphQL support using WPGraphQL.

Example to enable REST API:

PHP
// functions.php - Enable REST API for custom post types
add_action('init', 'register_custom_post_types');
function register_custom_post_types() {
    register_post_type('custom', array(
        'show_in_rest' => true,
        'supports' => ['elementor'],
    ));
}

Install plugins:

  • WPGraphQL – maps Elementor data to GraphQL.

2. Elementor Configuration

  • Build Pages: Design your pages normally using Elementor.
  • Dynamic Content: Utilize Elementor’s dynamic tags for CMS-driven content like post titles and featured images.

3. Next.js Setup

Create a Next.js App:

bash
npx create-next-app@latest

Install Dependencies:

bash
npm install graphql @apollo/client @headlessui/react

4. Data Fetching

Option A: GraphQL (Recommended)

Configure Apollo Client (lib/apollo-client.js):

JavaScript
import { ApolloClient, InMemoryCache } from '@apollo/client';

const client = new ApolloClient({
  uri: 'https://your-site.com/graphql',
  cache: new InMemoryCache(),
});

Fetch Elementor Page (pages/[slug].js):

JavaScript
import { gql, useQuery } from '@apollo/client';

const GET_PAGE = gql`
  query GetPage($id: ID!) {
    page(id: $id, idType: URI) {
      elementorData
      title
    }
  }
`;

export default function Page({ slug }) {
  const { data } = useQuery(GET_PAGE, { variables: { id: slug } });
  const page = data?.page;
  
  if (!page) return <div>Loading...</div>;

  return (
    <div>
      <h1>{page.title}</h1>
      <ElementorRenderer data={page.elementorData} />
    </div>
  );
}

Option B: REST API

Fetch Rendered HTML (pages/[slug].js):

JavaScript
export async function getStaticProps({ params }) {
  const res = await fetch(
    `https://your-site.com/wp-json/wp/v2/pages?slug=${params.slug}&_fields=id,title,elementor_content`
  );
  const [page] = await res.json();
  return { props: { page } };
}

5. Render Elementor Content

Elementor Renderer Component (components/ElementorRenderer.js):

JavaScript
const ElementorRenderer = ({ data }) => {
  const parsedData = JSON.parse(data);
  
  const renderElements = (elements) => 
    elements.map((el) => {
      switch (el.elType) {
        case 'section':
          return <section key={el.id}>{renderElements(el.elements)}</section>;
        case 'column':
          return <div key={el.id}>{renderElements(el.elements)}</div>;
        case 'widget':
          return renderWidget(el);
        default:
          return null;
      }
    });
  
  const renderWidget = (widget) => {
    switch (widget.widgetType) {
      case 'heading':
        return <h2>{widget.settings.title}</h2>;
      case 'image':
        return <img src={widget.settings.url} alt={widget.settings.alt} />;
      // Add more widget cases
      default:
        return <div>Unsupported widget</div>;
    }
  };
  
  return <>{renderElements(parsedData)}</>;
};

6. Styling

Global CSS: Include Elementor’s CSS in pages/_app.js:

JavaScript
import 'elementor-frontend/css/frontend.min.css';

Per-Page CSS: Inject page-specific CSS using metadata retrieved from the REST API.

7. Deployment & Optimisation

Static Site Generation (SSG):

JavaScript
export async function getStaticPaths() {
  const res = await fetch('https://your-site.com/wp-json/wp/v2/pages?_fields=slug');
  const pages = await res.json();
  const paths = pages.map((page) => ({ params: { slug: page.slug } }));
  return { paths, fallback: true };
}

Preview Mode: Implement Next.js preview mode for displaying draft content.

Key Considerations:

  • Elementor Data Structure: Element stores its data as JSON; ensure proper mapping of widget types to corresponding React components.
  • Dynamic Content: Utilize @apollo/client for real-time updates.
  • Performance: Optimize rendering by pre-fetching data with getStaticProps or getServerSideProps.

Frequently Asked Questions

Q: What are the benefits of using headless WordPress?

A: The primary benefits include improved performance, greater flexibility in frontend development using modern frameworks like Next.js, and enhanced security by decoupling the frontend from the backend.

Q: Can I still use Elementor with a headless setup?

A: Yes, while Elementor is primarily designed for traditional WordPress setups, you can still utilize Elementor for designing your pages, and extract the content through the REST API or WPGraphQL.

Q: What if I need to use custom components?

A: You can create custom React components in Next.js that correspond to Elementor widgets, allowing you to leverage the design capabilities of Elementor while adapting them for a React-based frontend.

Key Takeaways & Next Steps

Set up WordPress with Elementor and the required plugins. Create your Next.js project and configure data fetching through GraphQL or REST. Implement custom rendering components to display Elementor content in Next.js.

Recommended Actions:

Get started with your WordPress setup today.

Experiment with creating and rendering custom components.

Explore Next.js performance enhancements for your site.

This structured approach combines the power of WordPress, Next.js, and Elementor, giving you a robust solution for modern web development.

Leave a Reply

Your email address will not be published. Required fields are marked *

© 2025 Jay Doolan