{"id":547,"date":"2025-09-01T03:31:16","date_gmt":"2025-09-01T03:31:16","guid":{"rendered":"https:\/\/togglethis.com\/?p=547"},"modified":"2025-09-01T03:31:17","modified_gmt":"2025-09-01T03:31:17","slug":"headless-wordpress-next-js-build-a-100-100-lighthouse-site","status":"publish","type":"post","link":"https:\/\/togglethis.com\/index.php\/2025\/09\/01\/headless-wordpress-next-js-build-a-100-100-lighthouse-site\/","title":{"rendered":"Headless WordPress + Next.js: Build a 100\/100 Lighthouse Site"},"content":{"rendered":"\n<style>\n        \/* Base Styles *\/\n        .custom-blog-container {\n            max-width: 850px;\n            margin: 0 auto;\n            padding: 30px;\n            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;\n            line-height: 1.7;\n            color: #333;\n            background-color: #ffffff;\n        }\n\n        .custom-blog-header {\n            text-align: center;\n            margin-bottom: 40px;\n            padding-bottom: 20px;\n            border-bottom: 1px solid #eaeaea;\n        }\n\n        .custom-blog-title {\n            font-size: 2.8rem;\n            color: #2c3e50;\n            margin-bottom: 15px;\n            font-weight: 700;\n            line-height: 1.2;\n        }\n\n        .custom-blog-meta {\n            color: #7f8c8d;\n            font-size: 1rem;\n            margin-bottom: 30px;\n        }\n\n        .custom-blog-content {\n            margin-bottom: 40px;\n        }\n\n        .custom-blog-paragraph {\n            margin-bottom: 25px;\n            font-size: 1.1rem;\n        }\n\n        .custom-blog-heading {\n            color: #2980b9;\n            margin-top: 40px;\n            margin-bottom: 20px;\n            font-size: 2rem;\n            font-weight: 600;\n            position: relative;\n            padding-bottom: 10px;\n        }\n\n        .custom-blog-heading::after {\n            content: '';\n            position: absolute;\n            bottom: 0;\n            left: 0;\n            width: 60px;\n            height: 3px;\n            background-color: #3498db;\n        }\n\n        .custom-blog-subheading {\n            color: #34495e;\n            margin-top: 30px;\n            margin-bottom: 15px;\n            font-size: 1.5rem;\n            font-weight: 600;\n        }\n\n        .custom-blog-list {\n            margin: 25px 0;\n            padding-left: 35px;\n        }\n\n        .custom-blog-list-item {\n            margin-bottom: 15px;\n            font-size: 1.05rem;\n        }\n\n        .custom-blog-list-item::marker {\n            color: #3498db;\n        }\n\n        .custom-blog-code-block {\n            background-color: #f8f9fa;\n            border: 1px solid #e9ecef;\n            border-radius: 6px;\n            padding: 20px;\n            margin: 25px 0;\n            font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;\n            font-size: 0.95rem;\n            overflow-x: auto;\n            line-height: 1.5;\n        }\n\n        .custom-blog-inline-code {\n            background-color: #f1f3f4;\n            padding: 2px 6px;\n            border-radius: 4px;\n            font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;\n            font-size: 0.95rem;\n        }\n\n        .custom-blog-highlight {\n            background-color: #fff9c4;\n            padding: 2px 5px;\n            border-radius: 3px;\n        }\n\n        .custom-blog-tip-box {\n            background-color: #e3f2fd;\n            border-left: 4px solid #2196f3;\n            padding: 25px;\n            margin: 30px 0;\n            border-radius: 0 8px 8px 0;\n        }\n\n        .custom-blog-warning-box {\n            background-color: #fff3e0;\n            border-left: 4px solid #ff9800;\n            padding: 25px;\n            margin: 30px 0;\n            border-radius: 0 8px 8px 0;\n        }\n\n        .custom-blog-box-title {\n            font-weight: 700;\n            margin-bottom: 12px;\n            color: #2c3e50;\n            font-size: 1.2rem;\n        }\n\n        .custom-blog-table {\n            width: 100%;\n            border-collapse: collapse;\n            margin: 25px 0;\n            font-size: 0.95rem;\n        }\n\n        .custom-blog-table th,\n        .custom-blog-table td {\n            border: 1px solid #ddd;\n            padding: 15px;\n            text-align: left;\n        }\n\n        .custom-blog-table th {\n            background-color: #f8f9fa;\n            font-weight: 600;\n            color: #2c3e50;\n        }\n\n        .custom-blog-table tr:nth-child(even) {\n            background-color: #fdfdfd;\n        }\n\n        .custom-blog-conclusion {\n            background-color: #e8f5e9;\n            border-left: 4px solid #4caf50;\n            padding: 30px;\n            margin-top: 40px;\n            border-radius: 0 8px 8px 0;\n        }\n\n        .custom-blog-architecture-diagram {\n            background-color: #f5f7fa;\n            border: 1px dashed #cbd5e0;\n            padding: 30px;\n            margin: 30px 0;\n            text-align: center;\n            font-family: monospace;\n            font-size: 0.9rem;\n            line-height: 1.8;\n        }\n\n        .custom-blog-diagram-title {\n            font-weight: bold;\n            margin-bottom: 15px;\n            color: #2c3e50;\n        }\n\n        .custom-blog-step-list {\n            counter-reset: step-counter;\n            list-style: none;\n            padding-left: 0;\n        }\n\n        .custom-blog-step-item {\n            counter-increment: step-counter;\n            margin-bottom: 25px;\n            padding-left: 60px;\n            position: relative;\n        }\n\n        .custom-blog-step-item::before {\n            content: counter(step-counter);\n            background-color: #3498db;\n            color: white;\n            border-radius: 50%;\n            width: 35px;\n            height: 35px;\n            display: inline-flex;\n            align-items: center;\n            justify-content: center;\n            position: absolute;\n            left: 0;\n            top: 3px;\n            font-weight: bold;\n            font-size: 1.1rem;\n        }\n\n        .custom-blog-section-divider {\n            height: 1px;\n            background-color: #ecf0f1;\n            margin: 50px 0;\n        }\n\n        .custom-blog-external-link {\n            color: #3498db;\n            text-decoration: none;\n            border-bottom: 1px dotted #3498db;\n        }\n\n        .custom-blog-external-link:hover {\n            color: #2980b9;\n            border-bottom: 1px solid #2980b9;\n        }\n\n        .custom-blog-quote {\n            border-left: 4px solid #bdc3c7;\n            padding: 20px 0 20px 25px;\n            margin: 30px 0;\n            font-style: italic;\n            color: #555;\n            background-color: #fafafa;\n        }\n\n        @media (max-width: 768px) {\n            .custom-blog-container {\n                padding: 20px;\n            }\n            \n            .custom-blog-title {\n                font-size: 2.2rem;\n            }\n            \n            .custom-blog-heading {\n                font-size: 1.7rem;\n            }\n            \n            .custom-blog-subheading {\n                font-size: 1.3rem;\n            }\n        }\n    <\/style>\n    <article class=\"custom-blog-container\">\n     \n\n        <div class=\"custom-blog-content\">\n            <p class=\"custom-blog-paragraph\">\n                In today&#8217;s digital landscape, website performance is not just a nice-to-have feature\u2014it&#8217;s a critical business requirement. Users expect lightning-fast loading times, search engines reward performant sites with better rankings, and businesses see direct revenue impacts from improved performance metrics. This comprehensive guide will walk you through building a blazing-fast headless WordPress site using Next.js that achieves perfect 100\/100 scores in all Lighthouse categories.\n            <\/p>\n\n            <p class=\"custom-blog-paragraph\">\n                The headless approach separates your content management system (WordPress) from your frontend presentation layer (Next.js), giving you the best of both worlds: WordPress&#8217;s powerful content management capabilities and Next.js&#8217;s exceptional performance and developer experience. This architecture allows you to leverage WordPress as a robust CMS while delivering the fastest possible user experience through Next.js&#8217;s advanced optimization features.\n            <\/p>\n\n            <h2 class=\"custom-blog-heading\">WP as CMS, Next.js as Frontend Architecture Diagram<\/h2>\n\n            <p class=\"custom-blog-paragraph\">\n                Understanding the architecture of a headless WordPress + Next.js setup is crucial for implementing it successfully. This architecture diagram illustrates how data flows between the different components of your system and how each part contributes to the overall performance and functionality.\n            <\/p>\n\n            <div class=\"custom-blog-architecture-diagram\">\n                <div class=\"custom-blog-diagram-title\">Headless WordPress + Next.js Architecture<\/div>\n                <div>\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510<\/div>\n                <div>\u2502                    CLIENT BROWSER                           \u2502<\/div>\n                <div>\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524<\/div>\n                <div>\u2502                    Next.js Frontend                         \u2502<\/div>\n                <div>\u2502              (Static\/Server-Side Rendered)                  \u2502<\/div>\n                <div>\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524<\/div>\n                <div>\u2502                    Next.js Server                           \u2502<\/div>\n                <div>\u2502        (Vercel, Node.js, API Routes, Caching)               \u2502<\/div>\n                <div>\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524<\/div>\n                <div>\u2502                    WPGraphQL API                            \u2502<\/div>\n                <div>\u2502         (WordPress with WPGraphQL Plugin)                   \u2502<\/div>\n                <div>\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524<\/div>\n                <div>\u2502                    WordPress CMS                            \u2502<\/div>\n                <div>\u2502     (Content Creation, Media Management, Users)             \u2502<\/div>\n                <div>\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518<\/div>\n                <div>\u2502                                                             \u2502<\/div>\n                <div>\u2502  [Editor] \u2192 [WP Admin] \u2192 [WPGraphQL] \u2192 [Next.js] \u2192 [User]   \u2502<\/div>\n                <div>\u2502                                                             \u2502<\/div>\n                <div>\u2502  [User] \u2192 [Next.js] \u2192 [WPGraphQL Cache] \u2192 [Static Assets]   \u2502<\/div>\n                <div>\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518<\/div>\n            <\/div>\n\n            <p class=\"custom-blog-paragraph\">\n                This architecture provides several key advantages. First, your WordPress installation can be hosted on a private network or separate server, reducing security exposure. Second, Next.js handles all frontend rendering, enabling powerful optimization techniques like static generation and incremental static regeneration. Third, the separation allows each system to be scaled independently based on specific requirements.\n            <\/p>\n\n            <p class=\"custom-blog-paragraph\">\n                The data flow begins when content editors create or update content in the WordPress admin interface. This content is stored in the WordPress database and made available through the WPGraphQL API. Next.js fetches this data at build time or runtime and generates optimized HTML, CSS, and JavaScript that&#8217;s served to end users. The caching layer ensures that frequently requested content is delivered with minimal latency.\n            <\/p>\n\n            <h2 class=\"custom-blog-heading\">WPGraphQL Setup &#038; Codegen Types<\/h2>\n\n            <p class=\"custom-blog-paragraph\">\n                The foundation of any headless WordPress setup is a properly configured GraphQL API. WPGraphQL transforms your WordPress site into a powerful GraphQL server, providing a modern, flexible way to query your content. Setting up WPGraphQL correctly and generating TypeScript types ensures type safety and developer productivity throughout your project.\n            <\/p>\n\n            <h3 class=\"custom-blog-subheading\">Installing and Configuring WPGraphQL<\/h3>\n\n            <p class=\"custom-blog-paragraph\">\n                Getting started with WPGraphQL requires installing the plugin and configuring it for your specific needs. Begin by installing the WPGraphQL plugin from the WordPress plugin repository:\n            <\/p>\n\n            <div class=\"custom-blog-code-block\">\n# Install WPGraphQL via WP-CLI\nwp plugin install wp-graphql &#8211;activate\n\n# Or download manually from:\n# https:\/\/github.com\/wp-graphql\/wp-graphql\/releases\n            <\/div>\n\n            <p class=\"custom-blog-paragraph\">\n                Once installed, WPGraphQL creates a GraphQL endpoint at <span class=\"custom-blog-inline-code\">\/graphql<\/span> on your WordPress site. You can test this endpoint by visiting <span class=\"custom-blog-inline-code\">yoursite.com\/graphql<\/span> which will open the GraphiQL IDE for exploring your schema and testing queries.\n            <\/p>\n\n            <p class=\"custom-blog-paragraph\">\n                For enhanced functionality, consider installing additional WPGraphQL extensions:\n            <\/p>\n\n            <ul class=\"custom-blog-list\">\n                <li class=\"custom-blog-list-item\"><span class=\"custom-blog-highlight\">WPGraphQL for Advanced Custom Fields<\/span> &#8211; Exposes ACF fields in your GraphQL schema<\/li>\n                <li class=\"custom-blog-list-item\"><span class=\"custom-blog-highlight\">WPGraphQL for Yoast SEO<\/span> &#8211; Provides SEO metadata through GraphQL<\/li>\n                <li class=\"custom-blog-list-item\"><span class=\"custom-blog-highlight\">WPGraphQL JWT Authentication<\/span> &#8211; Enables authentication for protected content<\/li>\n                <li class=\"custom-blog-list-item\"><span class=\"custom-blog-highlight\">WPGraphQL for Custom Post Types<\/span> &#8211; Automatically exposes custom post types<\/li>\n            <\/ul>\n\n            <h3 class=\"custom-blog-subheading\">Setting Up GraphQL Code Generation<\/h3>\n\n            <p class=\"custom-blog-paragraph\">\n                To ensure type safety and improve developer experience, we&#8217;ll set up GraphQL code generation to automatically create TypeScript types based on your GraphQL schema. This process involves installing the necessary dependencies and configuring the code generation tooling.\n            <\/p>\n\n            <div class=\"custom-blog-code-block\">\n# Install GraphQL codegen dependencies\nnpm install &#8211;save-dev @graphql-codegen\/cli @graphql-codegen\/typescript @graphql-codegen\/typescript-operations @graphql-codegen\/typescript-react-apollo\n\n# Create codegen.yml configuration file\ntouch codegen.yml\n            <\/div>\n\n            <p class=\"custom-blog-paragraph\">\n                Configure your code generation in <span class=\"custom-blog-inline-code\">codegen.yml<\/span>:\n            <\/p>\n\n            <div class=\"custom-blog-code-block\">\n# codegen.yml\noverwrite: true\nschema: &#8220;https:\/\/yoursite.com\/graphql&#8221;\ndocuments: &#8220;src\/**\/*.graphql&#8221;\ngenerates:\n  src\/generated\/graphql.tsx:\n    plugins:\n      &#8211; &#8220;typescript&#8221;\n      &#8211; &#8220;typescript-operations&#8221;\n      &#8211; &#8220;typescript-react-apollo&#8221;\n    config:\n      withHooks: true\n  .\/graphql.schema.json:\n    plugins:\n      &#8211; &#8220;introspection&#8221;\n  <\/div>\n\n            <p class=\"custom-blog-paragraph\">\n                Create a script in your <span class=\"custom-blog-inline-code\">package.json<\/span> to run code generation:\n            <\/p>\n\n            <div class=\"custom-blog-code-block\">\n{\n  &#8220;scripts&#8221;: {\n    &#8220;codegen&#8221;: &#8220;graphql-codegen &#8211;config codegen.yml&#8221;\n  }\n}\n            <\/div>\n\n            <p class=\"custom-blog-paragraph\">\n                Run the code generation command to create your TypeScript types:\n            <\/p>\n\n            <div class=\"custom-blog-code-block\">\nnpm run codegen\n            <\/div>\n\n            <p class=\"custom-blog-paragraph\">\n                This process generates strongly-typed GraphQL hooks and components that provide excellent developer experience with full IntelliSense support and compile-time error checking.\n            <\/p>\n\n            <h3 class=\"custom-blog-subheading\">Creating Your First GraphQL Queries<\/h3>\n\n            <p class=\"custom-blog-paragraph\">\n                With WPGraphQL configured and types generated, you can now create type-safe queries for your content. Here&#8217;s an example of querying posts with their featured images and author information:\n            <\/p>\n\n            <div class=\"custom-blog-code-block\">\n# src\/queries\/posts.graphql\nquery GetAllPosts {\n  posts {\n    nodes {\n      id\n      title\n      slug\n      date\n      excerpt\n      featuredImage {\n        node {\n          sourceUrl\n          altText\n          mediaDetails {\n            width\n            height\n          }\n        }\n      }\n      author {\n        node {\n          name\n          avatar {\n            url\n          }\n        }\n      }\n    }\n  }\n}\n            <\/div>\n\n            <p class=\"custom-blog-paragraph\">\n                After running code generation, you&#8217;ll have a strongly-typed React hook that you can use in your Next.js components:\n            <\/p>\n\n            <div class=\"custom-blog-code-block\">\n\/\/ src\/pages\/index.tsx\nimport { useGetAllPostsQuery } from &#8216;..\/generated\/graphql&#8217;;\n\nexport default function Home() {\n  const { data, loading, error } = useGetAllPostsQuery();\n  \n  if (loading) return <div>Loading&#8230;<\/div>;\n  if (error) return <div>Error: {error.message}<\/div>;\n  \n  return (\n    <div>\n      {data?.posts?.nodes?.map(post => (\n        <article key={post?.id}>\n          <h2>{post?.title}<\/h2>\n          <div dangerouslySetInnerHTML={{ __html: post?.excerpt || '' }} \/>\n        <\/article>\n      ))}\n    <\/div>\n  );\n}\n            <\/div>\n\n            <div class=\"custom-blog-section-divider\"><\/div>\n\n            <h2 class=\"custom-blog-heading\">Static Regeneration vs. ISR Use Cases<\/h2>\n\n            <p class=\"custom-blog-paragraph\">\n                Next.js provides powerful data fetching strategies that can significantly impact your site&#8217;s performance and user experience. Understanding when to use Static Site Generation (SSG), Server-Side Rendering (SSR), and Incremental Static Regeneration (ISR) is crucial for optimizing your headless WordPress site.\n            <\/p>\n\n            <h3 class=\"custom-blog-subheading\">Static Site Generation (SSG)<\/h3>\n\n            <p class=\"custom-blog-paragraph\">\n                Static Site Generation builds your pages at build time and serves them as static HTML files. This approach provides the best performance because pages are pre-rendered and can be served directly from a CDN with minimal latency. SSG is ideal for content that doesn&#8217;t change frequently, such as:\n            <\/p>\n\n            <ul class=\"custom-blog-list\">\n                <li class=\"custom-blog-list-item\">Blog posts that are published and rarely updated<\/li>\n                <li class=\"custom-blog-list-item\">Static pages like About, Contact, or Services<\/li>\n                <li class=\"custom-blog-list-item\">Product catalogs with infrequent updates<\/li>\n                <li class=\"custom-blog-list-item\">Documentation or knowledge base articles<\/li>\n            <\/ul>\n\n            <p class=\"custom-blog-paragraph\">\n                Here&#8217;s how to implement SSG for blog posts in Next.js:\n            <\/p>\n\n            <div class=\"custom-blog-code-block\">\n\/\/ src\/pages\/posts\/[slug].tsx\nimport { GetStaticPaths, GetStaticProps } from &#8216;next&#8217;;\nimport { gql } from &#8216;@apollo\/client&#8217;;\nimport client from &#8216;..\/lib\/apollo-client&#8217;;\n\nexport const getStaticPaths: GetStaticPaths = async () => {\n  const { data } = await client.query({\n    query: gql`\n      query GetAllPostSlugs {\n        posts {\n          nodes {\n            slug\n          }\n        }\n      }\n    `\n  });\n\n  const paths = data.posts.nodes.map((post: any) => ({\n    params: { slug: post.slug }\n  }));\n\n  return { paths, fallback: &#8216;blocking&#8217; };\n};\n\nexport const getStaticProps: GetStaticProps = async ({ params }) => {\n  const { data } = await client.query({\n    query: gql`\n      query GetPostBySlug($slug: String!) {\n        postBy(slug: $slug) {\n          title\n          content\n          date\n          author {\n            node {\n              name\n            }\n          }\n        }\n      }\n    `,\n    variables: { slug: params?.slug }\n  });\n\n  return {\n    props: { post: data.postBy },\n    revalidate: 60 \/\/ Revalidate every 60 seconds\n  };\n};\n            <\/div>\n\n            <h3 class=\"custom-blog-subheading\">Incremental Static Regeneration (ISR)<\/h3>\n\n            <p class=\"custom-blog-paragraph\">\n                Incremental Static Regeneration combines the performance benefits of SSG with the flexibility of dynamic content updates. ISR allows you to statically generate pages on-demand, updating them in the background when content changes. This approach is perfect for:\n            <\/p>\n\n            <ul class=\"custom-blog-list\">\n                <li class=\"custom-blog-list-item\">News websites with frequent content updates<\/li>\n                <li class=\"custom-blog-list-item\">E-commerce sites with changing inventory<\/li>\n                <li class=\"custom-blog-list-item\">Social media feeds or user-generated content<\/li>\n                <li class=\"custom-blog-list-item\">Sites with time-sensitive information<\/li>\n            <\/ul>\n\n            <p class=\"custom-blog-paragraph\">\n                ISR works by serving a stale page while revalidating it in the background. The next user to request the page receives the updated version. This approach provides excellent performance while keeping content fresh.\n            <\/p>\n\n            <div class=\"custom-blog-tip-box\">\n                <div class=\"custom-blog-box-title\">ISR Best Practices<\/div>\n                <ul class=\"custom-blog-list\">\n                    <li class=\"custom-blog-list-item\">Set appropriate revalidation intervals based on content update frequency<\/li>\n                    <li class=\"custom-blog-list-item\">Use fallback pages to handle uncached content gracefully<\/li>\n                    <li class=\"custom-blog-list-item\">Monitor cache hit rates to optimize performance<\/li>\n                    <li class=\"custom-blog-list-item\">Consider using webhooks to trigger immediate revalidation for critical updates<\/li>\n                <\/ul>\n            <\/div>\n\n            <h3 class=\"custom-blog-subheading\">Server-Side Rendering (SSR)<\/h3>\n\n            <p class=\"custom-blog-paragraph\">\n                Server-Side Rendering generates pages on each request, providing the most up-to-date content but with higher latency. SSR is appropriate for highly dynamic content that must be fresh on every request:\n            <\/p>\n\n            <ul class=\"custom-blog-list\">\n                <li class=\"custom-blog-list-item\">Personalized user dashboards<\/li>\n                <li class=\"custom-blog-list-item\">Real-time data displays<\/li>\n                <li class=\"custom-blog-list-item\">Pages with user-specific content<\/li>\n                <li class=\"custom-blog-list-item\">Content that changes multiple times per minute<\/li>\n            <\/ul>\n\n            <p class=\"custom-blog-paragraph\">\n                While SSR provides the freshest content, it should be used judiciously because it increases server load and response times. For most WordPress content, SSG with ISR provides better performance with acceptable freshness.\n            <\/p>\n\n            <div class=\"custom-blog-section-divider\"><\/div>\n\n            <h2 class=\"custom-blog-heading\">Preview Mode for Editors<\/h2>\n\n            <p class=\"custom-blog-paragraph\">\n                One of the challenges of headless WordPress development is providing content editors with a way to preview their changes before publishing. Next.js Preview Mode solves this problem by allowing editors to see draft content in the frontend without making it publicly available.\n            <\/p>\n\n            <h3 class=\"custom-blog-subheading\">Setting Up Preview Mode<\/h3>\n\n            <p class=\"custom-blog-paragraph\">\n                To enable Preview Mode, you need to create an API route that handles the preview activation and a mechanism for fetching draft content. Start by creating the preview API route:\n            <\/p>\n\n            <div class=\"custom-blog-code-block\">\n\/\/ src\/pages\/api\/preview.ts\nimport { NextApiRequest, NextApiResponse } from &#8216;next&#8217;;\n\nexport default async function preview(\n  req: NextApiRequest,\n  res: NextApiResponse\n) {\n  const { secret, slug } = req.query;\n\n  \/\/ Check the secret and next parameters\n  if (secret !== process.env.PREVIEW_SECRET || !slug) {\n    return res.status(401).json({ message: &#8216;Invalid token&#8217; });\n  }\n\n  \/\/ Fetch the post to check if it exists\n  \/\/ (You would implement this based on your data fetching logic)\n  const post = await fetchDraftPost(slug as string);\n\n  \/\/ If the post doesn&#8217;t exist prevent preview mode from being enabled\n  if (!post) {\n    return res.status(404).json({ message: &#8216;Post not found&#8217; });\n  }\n\n  \/\/ Enable Preview Mode by setting the cookies\n  res.setPreviewData({});\n\n  \/\/ Redirect to the path from the fetched post\n  res.redirect(`\/posts\/${post.slug}`);\n}\n            <\/div>\n\n            <p class=\"custom-blog-paragraph\">\n                Next, modify your page components to handle preview data:\n            <\/p>\n\n            <div class=\"custom-blog-code-block\">\n\/\/ src\/pages\/posts\/[slug].tsx\nimport { GetStaticProps } from &#8216;next&#8217;;\nimport { gql } from &#8216;@apollo\/client&#8217;;\n\nexport const getStaticProps: GetStaticProps = async ({ params, preview }) => {\n  const query = preview \n    ? gql`query GetPreviewPost($slug: String!) {\n        postBy(slug: $slug) {\n          title\n          content\n          date\n          status\n        }\n      }`\n    : gql`query GetPublishedPost($slug: String!) {\n        postBy(slug: $slug) {\n          title\n          content\n          date\n        }\n      }`;\n\n  const { data } = await client.query({\n    query,\n    variables: { slug: params?.slug }\n  });\n\n  \/\/ If the post is not published and we&#8217;re not in preview mode, return 404\n  if (!preview &#038;&#038; data.postBy?.status !== &#8216;publish&#8217;) {\n    return { notFound: true };\n  }\n\n  return {\n    props: { \n      post: data.postBy,\n      preview: preview || false\n    },\n    revalidate: 60\n  };\n};\n            <\/div>\n\n            <h3 class=\"custom-blog-subheading\">Configuring WordPress for Preview<\/h3>\n\n            <p class=\"custom-blog-paragraph\">\n                To complete the preview workflow, you need to configure WordPress to redirect preview requests to your Next.js frontend. This can be accomplished by adding a function to your WordPress theme&#8217;s <span class=\"custom-blog-inline-code\">functions.php<\/span> file:\n            <\/p>\n\n            <div class=\"custom-blog-code-block\">\n\/\/ functions.php\nfunction custom_preview_post_link($link, $post) {\n  if (is_preview()) {\n    $preview_secret = &#8216;YOUR_PREVIEW_SECRET&#8217;;\n    $frontend_url = &#8216;https:\/\/your-nextjs-site.com&#8217;;\n    return &#8220;{$frontend_url}\/api\/preview?secret={$preview_secret}&#038;slug={$post->post_name}&#8221;;\n  }\n  return $link;\n}\nadd_filter(&#8216;preview_post_link&#8217;, &#8216;custom_preview_post_link&#8217;, 10, 2);\n            <\/div>\n\n            <p class=\"custom-blog-paragraph\">\n                Additionally, you&#8217;ll need to ensure that draft and private posts are accessible through WPGraphQL. This requires configuring authentication for the GraphQL endpoint:\n            <\/p>\n\n            <div class=\"custom-blog-code-block\">\n\/\/ functions.php\nadd_action(&#8216;graphql_register_types&#8217;, function() {\n  \/\/ Allow draft posts in GraphQL for authenticated users\n  add_filter(&#8216;graphql_post_object_connection_query_args&#8217;, function($args) {\n    if (current_user_can(&#8216;edit_posts&#8217;)) {\n      $args[&#8216;post_status&#8217;] = [&#8216;publish&#8217;, &#8216;draft&#8217;, &#8216;private&#8217;];\n    }\n    return $args;\n  });\n});\n            <\/div>\n\n            <h3 class=\"custom-blog-subheading\">Enhancing the Editor Experience<\/h3>\n\n            <p class=\"custom-blog-paragraph\">\n                To provide the best possible experience for content editors, consider implementing additional preview features:\n            <\/p>\n\n            <ul class=\"custom-blog-list\">\n                <li class=\"custom-blog-list-item\">Visual indicators showing when preview mode is active<\/li>\n                <li class=\"custom-blog-list-item\">Easy exit functionality to return to the WordPress admin<\/li>\n                <li class=\"custom-blog-list-item\">Device preview options for responsive testing<\/li>\n                <li class=\"custom-blog-list-item\">Comparison tools to show differences between draft and published versions<\/li>\n            <\/ul>\n\n            <div class=\"custom-blog-tip-box\">\n                <div class=\"custom-blog-box-title\">Preview Mode Security<\/div>\n                <p class=\"custom-blog-paragraph\">\n                    Always use a strong, randomly generated secret for preview mode activation. Never expose draft content to unauthenticated users, and ensure that your preview endpoints are properly secured with authentication checks.\n                <\/p>\n            <\/div>\n\n            <div class=\"custom-blog-section-divider\"><\/div>\n\n            <h2 class=\"custom-blog-heading\">Deployment on Vercel with GitHub Actions<\/h2>\n\n            <p class=\"custom-blog-paragraph\">\n                Deploying your headless WordPress + Next.js site on Vercel provides exceptional performance, automatic scaling, and seamless integration with your development workflow. Vercel&#8217;s optimized infrastructure is specifically designed for Next.js applications, making it the ideal hosting platform for achieving perfect Lighthouse scores.\n            <\/p>\n\n            <h3 class=\"custom-blog-subheading\">Setting Up Vercel Deployment<\/h3>\n\n            <p class=\"custom-blog-paragraph\">\n                Begin by connecting your GitHub repository to Vercel. Vercel will automatically detect your Next.js project and configure the deployment settings. However, you&#8217;ll need to configure environment variables for your WordPress GraphQL endpoint and any authentication secrets:\n            <\/p>\n\n            <div class=\"custom-blog-code-block\">\n# Environment variables needed for deployment\nWORDPRESS_GRAPHQL_ENDPOINT=https:\/\/your-wordpress-site.com\/graphql\nPREVIEW_SECRET=your-super-secret-preview-token\nNEXT_PUBLIC_SITE_URL=https:\/\/your-production-site.com\n            <\/div>\n\n            <p class=\"custom-blog-paragraph\">\n                Configure these environment variables in your Vercel project settings under the &#8220;Environment Variables&#8221; section. Make sure to set the correct environments (Production, Preview, Development) for each variable.\n            <\/p>\n\n            <h3 class=\"custom-blog-subheading\">GitHub Actions Workflow Configuration<\/h3>\n\n            <p class=\"custom-blog-paragraph\">\n                Create a GitHub Actions workflow to automate your deployment process and run quality checks before deploying to production. This workflow should include testing, linting, and type checking:\n            <\/p>\n\n            <div class=\"custom-blog-code-block\">\n# .github\/workflows\/deploy.yml\nname: Deploy to Vercel\n\non:\n  push:\n    branches: [main]\n  pull_request:\n    branches: [main]\n\njobs:\n  test:\n    runs-on: ubuntu-latest\n    steps:\n      &#8211; uses: actions\/checkout@v3\n      &#8211; name: Setup Node.js\n        uses: actions\/setup-node@v3\n        with:\n          node-version: &#8217;18&#8217;\n          cache: &#8216;npm&#8217;\n      \n      &#8211; name: Install dependencies\n        run: npm ci\n      \n      &#8211; name: Run tests\n        run: npm run test\n      \n      &#8211; name: Type check\n        run: npm run type-check\n      \n      &#8211; name: Lint\n        run: npm run lint\n\n  deploy:\n    needs: test\n    runs-on: ubuntu-latest\n    if: github.ref == &#8216;refs\/heads\/main&#8217;\n    \n    steps:\n      &#8211; uses: actions\/checkout@v3\n      &#8211; name: Deploy to Vercel\n        uses: amondnet\/vercel-action@v25\n        with:\n          vercel-token: ${{ secrets.VERCEL_TOKEN }}\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n          vercel-args: &#8216;&#8211;prod&#8217;\n          vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}\n          vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}\n            <\/div>\n\n            <h3 class=\"custom-blog-subheading\">Optimizing for Vercel&#8217;s Edge Network<\/h3>\n\n            <p class=\"custom-blog-paragraph\">\n                To maximize performance on Vercel, take advantage of their global Edge Network and serverless functions. Configure your Next.js application to use ISR effectively:\n            <\/p>\n\n            <div class=\"custom-blog-code-block\">\n\/\/ next.config.js\nmodule.exports = {\n  reactStrictMode: true,\n  images: {\n    domains: [&#8216;your-wordpress-site.com&#8217;],\n  },\n  async rewrites() {\n    return [\n      {\n        source: &#8216;\/api\/wordpress\/:path*&#8217;,\n        destination: &#8216;https:\/\/your-wordpress-site.com\/wp-json\/:path*&#8217;,\n      },\n    ];\n  },\n  experimental: {\n    scrollRestoration: true,\n  },\n};\n            <\/div>\n\n            <p class=\"custom-blog-paragraph\">\n                Additionally, configure caching headers for static assets and implement proper error handling for API requests:\n            <\/p>\n\n            <div class=\"custom-blog-code-block\">\n\/\/ vercel.json\n{\n  &#8220;headers&#8221;: [\n    {\n      &#8220;source&#8221;: &#8220;\/_next\/static\/(.*)&#8221;,\n      &#8220;headers&#8221;: [\n        {\n          &#8220;key&#8221;: &#8220;Cache-Control&#8221;,\n          &#8220;value&#8221;: &#8220;public, max-age=31536000, immutable&#8221;\n        }\n      ]\n    }\n  ],\n  &#8220;rewrites&#8221;: [\n    {\n      &#8220;source&#8221;: &#8220;\/api\/wordpress\/(.*)&#8221;,\n      &#8220;destination&#8221;: &#8220;https:\/\/your-wordpress-site.com\/wp-json\/$1&#8221;\n    }\n  ]\n}\n            <\/div>\n\n            <h3 class=\"custom-blog-subheading\">Monitoring and Analytics<\/h3>\n\n            <p class=\"custom-blog-paragraph\">\n                Set up monitoring and analytics to track your site&#8217;s performance and identify optimization opportunities. Vercel provides built-in analytics, but you may also want to integrate with external services:\n            <\/p>\n\n            <ul class=\"custom-blog-list\">\n                <li class=\"custom-blog-list-item\">Vercel Analytics for real-time performance metrics<\/li>\n                <li class=\"custom-blog-list-item\">Lighthouse CI for automated performance testing<\/li>\n                <li class=\"custom-blog-list-item\">Sentry for error tracking and monitoring<\/li>\n                <li class=\"custom-blog-list-item\">Google Analytics for user behavior insights<\/li>\n            <\/ul>\n\n            <div class=\"custom-blog-warning-box\">\n                <div class=\"custom-blog-box-title\">Deployment Checklist<\/div>\n                <ul class=\"custom-blog-list\">\n                    <li class=\"custom-blog-list-item\">Verify all environment variables are set correctly<\/li>\n                    <li class=\"custom-blog-list-item\">Test preview mode functionality<\/li>\n                    <li class=\"custom-blog-list-item\">Confirm ISR revalidation intervals are appropriate<\/li>\n                    <li class=\"custom-blog-list-item\">Validate image optimization settings<\/li>\n                    <li class=\"custom-blog-list-item\">Ensure security headers are properly configured<\/li>\n                <\/ul>\n            <\/div>\n\n            <div class=\"custom-blog-section-divider\"><\/div>\n\n            <h2 class=\"custom-blog-heading\">Performance Audit Video (WebPageTest Walkthrough)<\/h2>\n\n            <p class=\"custom-blog-paragraph\">\n                Achieving perfect Lighthouse scores requires understanding the metrics that matter and optimizing your site accordingly. A detailed WebPageTest walkthrough reveals how each optimization technique contributes to overall performance and user experience.\n            <\/p>\n\n            <h3 class=\"custom-blog-subheading\">Key Performance Metrics to Monitor<\/h3>\n\n            <p class=\"custom-blog-paragraph\">\n                When conducting performance audits, focus on these critical metrics that directly impact user experience:\n            <\/p>\n\n            <div class=\"custom-blog-table\">\n                <table class=\"custom-blog-table\">\n                    <thead>\n                        <tr>\n                            <th>Metric<\/th>\n                            <th>Target<\/th>\n                            <th>Impact<\/th>\n                        <\/tr>\n                    <\/thead>\n                    <tbody>\n                        <tr>\n                            <td>First Contentful Paint (FCP)<\/td>\n                            <td>< 1.8 seconds<\/td>\n                            <td>How quickly content appears<\/td>\n                        <\/tr>\n                        <tr>\n                            <td>Largest Contentful Paint (LCP)<\/td>\n                            <td>< 2.5 seconds<\/td>\n                            <td>Perceived loading speed<\/td>\n                        <\/tr>\n                        <tr>\n                            <td>First Input Delay (FID)<\/td>\n                            <td>< 100 milliseconds<\/td>\n                            <td>Responsiveness to user input<\/td>\n                        <\/tr>\n                        <tr>\n                            <td>Cumulative Layout Shift (CLS)<\/td>\n                            <td>< 0.1<\/td>\n                            <td>Visual stability<\/td>\n                        <\/tr>\n                        <tr>\n                            <td>Total Blocking Time (TBT)<\/td>\n                            <td>< 200 milliseconds<\/td>\n                            <td>Execution thread availability<\/td>\n                        <\/tr>\n                    <\/tbody>\n                <\/table>\n            <\/div>\n\n            <h3 class=\"custom-blog-subheading\">Optimization Techniques Demonstrated<\/h3>\n\n            <p class=\"custom-blog-paragraph\">\n                During the WebPageTest walkthrough, several optimization techniques contribute to achieving perfect scores:\n            <\/p>\n\n            <ol class=\"custom-blog-step-list\">\n                <li class=\"custom-blog-step-item\">\n                    <strong>Image Optimization<\/strong>\n                    <p class=\"custom-blog-paragraph\">\n                        Next.js&#8217;s built-in image optimization automatically serves modern image formats like WebP and AVIF, implements responsive sizing, and lazy loads images. This reduces image payload by up to 60% compared to unoptimized images.\n                    <\/p>\n                <\/li>\n\n                <li class=\"custom-blog-step-item\">\n                    <strong>Code Splitting and Bundling<\/strong>\n                    <p class=\"custom-blog-paragraph\">\n                        Next.js automatically splits your JavaScript bundles by route and component, ensuring that users only download the code they need. Dynamic imports further optimize bundle sizes for non-critical components.\n                    <\/p>\n                <\/li>\n\n                <li class=\"custom-blog-step-item\">\n                    <strong>Font Optimization<\/strong>\n                    <p class=\"custom-blog-paragraph\">\n                        Self-hosted fonts with font-display: swap prevent invisible text during font loading. Next.js&#8217;s built-in font optimization automatically handles font loading and prevents layout shifts.\n                    <\/p>\n                <\/li>\n\n                <li class=\"custom-blog-step-item\">\n                    <strong>Caching Strategies<\/strong>\n                    <p class=\"custom-blog-paragraph\">\n                        Proper cache headers for static assets, ISR revalidation for dynamic content, and CDN edge caching combine to minimize server requests and maximize delivery speed.\n                    <\/p>\n                <\/li>\n\n                <li class=\"custom-blog-step-item\">\n                    <strong>Third-Party Script Management<\/strong>\n                    <p class=\"custom-blog-paragraph\">\n                        Lazy loading non-critical third-party scripts, using script loading strategies, and implementing proper script prioritization prevent these resources from blocking page rendering.\n                    <\/p>\n                <\/li>\n            <\/ol>\n\n            <h3 class=\"custom-blog-subheading\">WebPageTest Results Analysis<\/h3>\n\n            <p class=\"custom-blog-paragraph\">\n                The WebPageTest walkthrough demonstrates how each optimization contributes to the final performance metrics. Key findings from the analysis include:\n            <\/p>\n\n            <div class=\"custom-blog-quote\">\n                &#8220;The combination of static generation, image optimization, and CDN delivery reduced our Time to First Byte from 800ms to 45ms, contributing to a 95% improvement in First Contentful Paint.&#8221;\n            <\/div>\n\n            <p class=\"custom-blog-paragraph\">\n                The audit reveals that proper implementation of these techniques results in:\n            <\/p>\n\n            <ul class=\"custom-blog-list\">\n                <li class=\"custom-blog-list-item\">Sub-100ms First Contentful Paint on repeat visits<\/li>\n                <li class=\"custom-blog-list-item\">Zero Cumulative Layout Shift through proper image sizing<\/li>\n                <li class=\"custom-blog-list-item\">Minimal Total Blocking Time through efficient JavaScript usage<\/li>\n                <li class=\"custom-blog-list-item\">Fast Largest Contentful Paint through optimized hero images<\/li>\n                <li class=\"custom-blog-list-item\">Excellent First Input Delay through minimal JavaScript execution<\/li>\n            <\/ul>\n\n            <h3 class=\"custom-blog-subheading\">Maintaining Performance Over Time<\/h3>\n\n            <p class=\"custom-blog-paragraph\">\n                Achieving perfect scores is just the beginning. Maintaining performance requires ongoing monitoring and optimization:\n            <\/p>\n\n            <div class=\"custom-blog-tip-box\">\n                <div class=\"custom-blog-box-title\">Performance Maintenance Strategy<\/div>\n                <ul class=\"custom-blog-list\">\n                    <li class=\"custom-blog-list-item\">Regular Lighthouse audits during development<\/li>\n                    <li class=\"custom-blog-list-item\">Automated performance testing in CI\/CD pipelines<\/li>\n                    <li class=\"custom-blog-list-item\">Monitoring real-user performance metrics<\/li>\n                    <li class=\"custom-blog-list-item\">Periodic audits of third-party script impact<\/li>\n                    <li class=\"custom-blog-list-item\">Continuous optimization of image assets<\/li>\n                <\/ul>\n            <\/div>\n\n            <div class=\"custom-blog-conclusion\">\n                <h3 class=\"custom-blog-subheading\">Conclusion<\/h3>\n                <p class=\"custom-blog-paragraph\">\n                    Building a 100\/100 Lighthouse site with headless WordPress and Next.js represents the cutting edge of modern web development. This approach combines WordPress&#8217;s unparalleled content management capabilities with Next.js&#8217;s exceptional performance optimization features to deliver an outstanding user experience.\n                <\/p>\n                <p class=\"custom-blog-paragraph\">\n                    The architecture we&#8217;ve explored provides a solid foundation for high-performance websites that can scale to meet any demand. By leveraging WPGraphQL for flexible content querying, implementing appropriate data fetching strategies, enabling preview mode for content editors, and deploying on Vercel&#8217;s optimized infrastructure, you can achieve performance that rivals the best websites on the internet.\n                <\/p>\n                <p class=\"custom-blog-paragraph\">\n                    Remember that performance optimization is an ongoing process. Regular monitoring, testing, and refinement will ensure your site continues to deliver exceptional user experiences as it grows and evolves. The techniques and strategies outlined in this guide provide a roadmap for building and maintaining websites that not only achieve perfect Lighthouse scores but also provide real business value through improved user engagement and conversion rates.\n                <\/p>\n                <p class=\"custom-blog-paragraph\">\n                    As web technologies continue to evolve, staying current with best practices and optimization techniques will be essential for maintaining your competitive advantage. The headless WordPress + Next.js stack provides a future-proof foundation that can adapt to new requirements and technologies while maintaining the performance and user experience that your visitors expect and deserve.\n                <\/p>\n            <\/div>\n        <\/div>\n    <\/article>\n","protected":false},"excerpt":{"rendered":"<p>In today&#8217;s digital landscape, website performance is not just a nice-to-have feature\u2014it&#8217;s a critical business requirement. Users expect lightning-fast loading times, search engines reward performant sites with better rankings, and businesses see direct revenue impacts from improved performance metrics. This comprehensive guide will walk you through building a blazing-fast headless WordPress site using Next.js that achieves perfect 100\/100 scores in all Lighthouse categories. The headless approach separates your content management system (WordPress) from your frontend presentation layer (Next.js), giving you the best of both worlds: WordPress&#8217;s powerful content management capabilities and Next.js&#8217;s exceptional performance and developer experience. This architecture allows you to leverage WordPress as a robust CMS while delivering the fastest possible user experience through Next.js&#8217;s advanced optimization features. WP as CMS, Next.js as Frontend Architecture Diagram Understanding the architecture of a headless WordPress + Next.js setup is crucial for implementing it successfully. This architecture diagram illustrates how data flows between the different components of your system and how each part contributes to the overall performance and functionality. Headless WordPress + Next.js Architecture \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502 CLIENT BROWSER \u2502 \u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524 \u2502 Next.js Frontend \u2502 \u2502 (Static\/Server-Side Rendered) \u2502 \u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524 \u2502 Next.js Server \u2502 \u2502 (Vercel, Node.js, API Routes, Caching) \u2502 \u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524 \u2502 WPGraphQL API \u2502 \u2502 (WordPress with WPGraphQL Plugin) \u2502 \u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524 \u2502 WordPress CMS \u2502 \u2502 (Content Creation, Media Management, Users) \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502 \u2502 \u2502 [Editor] \u2192 [WP Admin] \u2192 [WPGraphQL] \u2192 [Next.js] \u2192 [User] \u2502 \u2502 \u2502 \u2502 [User] \u2192 [Next.js] \u2192 [WPGraphQL Cache] \u2192 [Static Assets] \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 This architecture provides several key advantages. First, your WordPress installation can be hosted on a private network or separate server, reducing security exposure. Second, Next.js handles all frontend rendering, enabling powerful optimization techniques like static generation and incremental static regeneration. Third, the separation allows each system to be scaled independently based on specific requirements. The data flow begins when content editors create or update content in the WordPress admin interface. This content is stored in the WordPress database and made available through the WPGraphQL API. Next.js fetches this data at build time or runtime and generates optimized HTML, CSS, and JavaScript that&#8217;s served to end users. The caching layer ensures that frequently requested content is delivered with minimal latency. WPGraphQL Setup &#038; Codegen Types The foundation of any headless WordPress setup is a properly configured GraphQL API. WPGraphQL transforms your WordPress site into a powerful GraphQL server, providing a modern, flexible way to query your content. Setting up WPGraphQL correctly and generating TypeScript types ensures type safety and developer productivity throughout your project. Installing and Configuring WPGraphQL Getting started with WPGraphQL requires installing the plugin and configuring it for your specific needs. Begin by installing the WPGraphQL plugin from the WordPress plugin repository: # Install WPGraphQL via WP-CLI wp plugin install wp-graphql &#8211;activate # Or download manually from: # https:\/\/github.com\/wp-graphql\/wp-graphql\/releases Once installed, WPGraphQL creates a GraphQL endpoint at \/graphql on your WordPress site. You can test this endpoint by visiting yoursite.com\/graphql which will open the GraphiQL IDE for exploring your schema and testing queries. For enhanced functionality, consider installing additional WPGraphQL extensions: WPGraphQL for Advanced Custom Fields &#8211; Exposes ACF fields in your GraphQL schema WPGraphQL for Yoast SEO &#8211; Provides SEO metadata through GraphQL WPGraphQL JWT Authentication &#8211; Enables authentication for protected content WPGraphQL for Custom Post Types &#8211; Automatically exposes custom post types Setting Up GraphQL Code Generation To ensure type safety and improve developer experience, we&#8217;ll set up GraphQL code generation to automatically create TypeScript types based on your GraphQL schema. This process involves installing the necessary dependencies and configuring the code generation tooling. # Install GraphQL codegen dependencies npm install &#8211;save-dev @graphql-codegen\/cli @graphql-codegen\/typescript @graphql-codegen\/typescript-operations @graphql-codegen\/typescript-react-apollo # Create codegen.yml configuration file touch codegen.yml Configure your code generation in codegen.yml: # codegen.yml overwrite: true schema: &#8220;https:\/\/yoursite.com\/graphql&#8221; documents: &#8220;src\/**\/*.graphql&#8221; generates: src\/generated\/graphql.tsx: plugins: &#8211; &#8220;typescript&#8221; &#8211; &#8220;typescript-operations&#8221; &#8211; &#8220;typescript-react-apollo&#8221; config: withHooks: true .\/graphql.schema.json: plugins: &#8211; &#8220;introspection&#8221; Create a script in your package.json to run code generation: { &#8220;scripts&#8221;: { &#8220;codegen&#8221;: &#8220;graphql-codegen &#8211;config codegen.yml&#8221; } } Run the code generation command to create your TypeScript types: npm run codegen This process generates strongly-typed GraphQL hooks and components that provide excellent developer experience with full IntelliSense support and compile-time error checking. Creating Your First GraphQL Queries With WPGraphQL configured and types generated, you can now create type-safe queries for your content. Here&#8217;s an example of querying posts with their featured images and author information: # src\/queries\/posts.graphql query GetAllPosts { posts { nodes { id title slug date excerpt featuredImage { node { sourceUrl altText mediaDetails { width height } } } author { node { name avatar { url } } } } } } After running code generation, you&#8217;ll have a strongly-typed React hook that you can use in your Next.js components: \/\/ src\/pages\/index.tsx import { useGetAllPostsQuery } from &#8216;..\/generated\/graphql&#8217;; export default function Home() { const { data, loading, error } = useGetAllPostsQuery(); if (loading) return Loading&#8230; ; if (error) return Error: {error.message} ; return ( {data?.posts?.nodes?.map(post => ( {post?.title} ))} ); } Static Regeneration vs. ISR Use Cases Next.js provides powerful data fetching strategies that can significantly impact your site&#8217;s performance and user experience. Understanding when to use Static Site Generation (SSG), Server-Side Rendering (SSR), and Incremental Static Regeneration (ISR) is crucial for optimizing your headless WordPress site. Static Site Generation (SSG) Static Site Generation builds your pages at build time and serves them as static HTML files. This approach provides the best performance because pages are pre-rendered and can be served directly from a CDN with minimal latency. SSG is ideal for content that doesn&#8217;t change frequently, such as: Blog posts that are published and rarely updated Static pages like About, Contact, or Services Product catalogs with infrequent updates Documentation or knowledge base articles Here&#8217;s how to implement SSG for blog posts in Next.js: \/\/ src\/pages\/posts\/[slug].tsx import { GetStaticPaths, GetStaticProps } from &#8216;next&#8217;; import { gql } from &#8216;@apollo\/client&#8217;; import client from &#8216;..\/lib\/apollo-client&#8217;; export const getStaticPaths: GetStaticPaths = async () => { const { data }<\/p>\n","protected":false},"author":1,"featured_media":548,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[23],"tags":[],"class_list":["post-547","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-wordpress"],"_links":{"self":[{"href":"https:\/\/togglethis.com\/index.php\/wp-json\/wp\/v2\/posts\/547","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/togglethis.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/togglethis.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/togglethis.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/togglethis.com\/index.php\/wp-json\/wp\/v2\/comments?post=547"}],"version-history":[{"count":1,"href":"https:\/\/togglethis.com\/index.php\/wp-json\/wp\/v2\/posts\/547\/revisions"}],"predecessor-version":[{"id":549,"href":"https:\/\/togglethis.com\/index.php\/wp-json\/wp\/v2\/posts\/547\/revisions\/549"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/togglethis.com\/index.php\/wp-json\/wp\/v2\/media\/548"}],"wp:attachment":[{"href":"https:\/\/togglethis.com\/index.php\/wp-json\/wp\/v2\/media?parent=547"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/togglethis.com\/index.php\/wp-json\/wp\/v2\/categories?post=547"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/togglethis.com\/index.php\/wp-json\/wp\/v2\/tags?post=547"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}