Blog

  • Hello world!

    Welcome to WordPress. This is your first post. Edit or delete it, then start writing!

  • Why We Built FlatWP: The Headless WordPress Stack We Actually Wanted

    After building dozens of headless WordPress sites for clients, we kept running into the same problems. Every project started from scratch. Every developer had to figure out ISR strategies, image optimization, and WordPress GraphQL quirks all over again.

    We decided to build FlatWP to solve this once and for all.

    The Problem with Current Solutions

    Most WordPress headless starters are either too basic (just fetch and display) or too opinionated (locked into specific frameworks or hosting). Agencies need something that’s production-ready but flexible enough to customize for different clients.

    We wanted a starter that understood real WordPress workflows – ACF, custom fields, WooCommerce, forms – not just blog posts.

    What Makes FlatWP Different

    FlatWP is built with performance as the foundation. Every architectural decision prioritizes speed:

    • Smart ISR: Content updates instantly via webhooks, not on a timer
    • Static by default: Pages that rarely change are fully static
    • Optimized images: Automatic WebP/AVIF conversion and responsive sizing
    • TypeScript throughout: Full type safety from WordPress to React

    But the real differentiator is the WordPress plugin. Instead of just showing you how to query WordPress, we built tooling that makes the entire workflow seamless.

    Built for Real Projects

    This isn’t a demo or proof-of-concept. FlatWP is designed for production use from day one. We include preview mode for editors, form handling, SEO metadata, and all the unglamorous features that matter when shipping to clients.

    Our goal is simple: let developers focus on building great experiences, not wrestling with infrastructure.

    We’re launching the open-source version this month, with Pro features coming in early 2025. Stay tuned.

  • Understanding ISR: The Secret to Fast Headless WordPress Sites

    Incremental Static Regeneration (ISR) is the killer feature that makes Next.js perfect for headless WordPress. But understanding when and how to use it can be tricky.

    What is ISR?

    ISR lets you update static pages after build time without rebuilding your entire site. You get the speed of static generation with the freshness of server-side rendering.

    Here’s how it works: Next.js generates static HTML at build time. After deployment, when someone requests a page, they get the cached version. In the background, Next.js regenerates the page and updates the cache.

    Time-Based vs On-Demand Revalidation

    Next.js offers two ISR strategies:

    Time-based revalidation regenerates pages after a specified interval:

    export const revalidate = 3600; // 1 hour

    This is great for content that updates predictably, like archive pages or dashboards.

    On-demand revalidation regenerates pages when triggered by an API call. This is what FlatWP uses. When you save a post in WordPress, our plugin immediately triggers revalidation:

    await fetch('/api/revalidate', {
      method: 'POST',
      body: JSON.stringify({ paths: ['/blog/my-post'] })
    });

    The FlatWP Approach

    We use different strategies for different content types:

    • Blog posts: On-demand ISR (update immediately when edited)
    • Static pages: No revalidation (fully static)
    • Archives: Short time-based ISR (5 minutes)
    • Homepage: Very short ISR or server component

    This gives you instant updates where they matter, without sacrificing performance.

    Performance Impact

    With ISR, first-time visitors get sub-100ms page loads. The page is pre-rendered, served from the edge, and cached globally. Subsequent visitors get even faster loads from CDN cache.

    Compare this to server-side rendering, which queries WordPress on every request. ISR gives you the best of both worlds.

  • ACF + TypeScript: Building Type-Safe Flexible Content

    Advanced Custom Fields (ACF) is the go-to solution for flexible WordPress content. But in a TypeScript headless setup, losing type safety on your custom fields is a major pain point.

    FlatWP solves this with automatic TypeScript generation from your ACF field groups.

    The Problem

    When you query ACF fields through GraphQL, you get untyped data:

    const hero = page.acf.hero; // any type - no autocomplete, no safety

    This means runtime errors, no IDE support, and constant trips to the WordPress admin to check field names.

    The FlatWP Solution

    Our WordPress plugin exposes ACF schemas as structured JSON. Our codegen tool transforms these into TypeScript interfaces:

    interface HeroBlock {
      heading: string;
      subheading: string;
      image: {
        url: string;
        alt: string;
      };
      ctaText: string;
      ctaUrl: string;
    }

    Now your components are fully typed:

    export function HeroBlock({ fields }: { fields: HeroBlock }) {
      return (
        <section>
          <h1>{fields.heading}</h1>
          <p>{fields.subheading}</p>
          {/* TypeScript knows exactly what fields exist */}
        </section>
      );
    }

    Flexible Content Blocks

    ACF’s Flexible Content field type is perfect for page builders. FlatWP provides a block renderer pattern:

    const blockComponents = {
      hero: HeroBlock,
      features: FeaturesBlock,
      testimonial: TestimonialBlock,
    };
    
    export function BlockRenderer({ blocks }: { blocks: ACFBlock[] }) {
      return blocks.map((block) => {
        const Component = blockComponents[block.layout];
        return <Component key={block.id} fields={block.fields} />;
      });
    }

    Coming in FlatWP Pro

    The Pro version will include a library of 20+ pre-built ACF blocks with matching Shadcn components. Hero sections, feature grids, testimonials, pricing tables – all typed, styled, and ready to use.

    You’ll be able to build complex page layouts in WordPress while maintaining full TypeScript safety in your React components.

  • WordPress Plugin Compatibility: What Works with FlatWP

    One question we get constantly: “Will my favorite WordPress plugins work with FlatWP?”

    The short answer is: most of them, yes. But it depends on what the plugin does.

    Plugins That Work Great

    Content & SEO Plugins:

    • Advanced Custom Fields (ACF) – Full support via WPGraphQL
    • Yoast SEO – Meta data accessible through GraphQL
    • Rank Math – Similar to Yoast, works perfectly
    • Custom Post Type UI – Create custom post types, query via GraphQL

    Media & Assets:

    • Any media library plugin – Images flow through next/image optimization
    • ShortPixel – Optimize before Next.js processes them
    • Cloudinary – Can integrate as image source

    Forms:

    • Contact Form 7 – Works with our form adapter
    • WPForms – REST API integration available
    • Gravity Forms – GraphQL extension available

    Plugins That Need Adapters

    Some plugins require custom integration but are totally doable:

    WooCommerce: FlatWP Pro will include a headless storefront. You can also use WPGraphQL for WooCommerce for custom implementations.

    Multilingual (WPML/Polylang): Works with proper GraphQL queries. FlatWP Pro includes multi-language routing.

    Membership plugins: Require custom authentication flow but compatible.

    Plugins That Won’t Work

    Anything that depends on WordPress themes or relies on server-side rendering:

    • Page builders (Elementor, Divi) – Use ACF Flexible Content instead
    • Caching plugins (WP Rocket, etc.) – Next.js handles caching
    • Theme-specific plugins – Your frontend is React, not PHP

    Our Compatibility Roadmap

    We’re actively testing and documenting plugin compatibility. Current priorities:

    1. WooCommerce integration (in progress)
    2. Popular form plugins
    3. Multilingual support
    4. Events plugins (The Events Calendar)

    If there’s a plugin you need, let us know. We’re building adapters based on community demand.

  • Image Optimization in Headless WordPress: Beyond next/image

    WordPress is notorious for bloated images. Editors upload 5MB photos from their phone, and suddenly your site loads like it’s 2010.

    In headless WordPress, you have a unique opportunity to fix this at the framework level.

    The WordPress Media Problem

    Traditional WordPress generates multiple image sizes on upload. But these sizes are often wrong for modern responsive design. You end up with dozens of unused files cluttering your media library.

    Plus, WordPress doesn’t handle modern formats (WebP, AVIF) or responsive srcsets particularly well.

    The Next.js Solution

    Next.js Image component handles optimization automatically:

    • Serves modern formats (WebP/AVIF) to supporting browsers
    • Generates responsive srcsets on-demand
    • Lazy loads by default
    • Prevents layout shift with automatic sizing

    But you need to configure it correctly for WordPress.

    FlatWP’s Approach

    We create a custom image loader that:

    1. Pulls the original image from WordPress
    2. Proxies it through Next.js optimization
    3. Caches the optimized versions globally
    4. Serves from Vercel’s edge network

    The result? A 5MB WordPress upload becomes a 50KB WebP delivered in milliseconds.

    Configuration

    In your next.config.js:

    images: {
      domains: ['cms.flatwp.com/'],
      formats: ['image/avif', 'image/webp'],
      deviceSizes: [640, 750, 828, 1080, 1200, 1920],
    }

    Then use it in components:

    <Image
      src={post.featuredImage.url}
      alt={post.featuredImage.alt}
      width={1200}
      height={630}
      priority={isAboveFold}
    />

    WordPress-Side Optimization

    Even better: prevent bloated uploads in the first place. Our WordPress plugin includes:

    • Upload size limits
    • Automatic compression before upload
    • Warnings when images exceed recommended dimensions
    • Bulk optimization tools for existing media

    Performance Impact

    We measured a typical blog post with 5 images:

    • Traditional WordPress: 2.3MB transferred, 4.2s load
    • FlatWP optimized: 180KB transferred, 0.8s load

    That’s a 92% reduction in bandwidth and 5x faster load times. For free.

  • Preview Mode: Let Editors See Drafts Before Publishing

    One of the biggest challenges with headless WordPress is preview functionality. Editors want to see their drafts before publishing, but your static site only shows published content.

    FlatWP’s preview mode solves this elegantly.

    How It Works

    When an editor clicks “Preview” in WordPress, our plugin generates a special URL:

    https://flatwp.com/api/preview?secret=xyz&id=123&type=post

    This hits your Next.js preview API route, which:

    1. Verifies the secret token
    2. Enables Next.js draft mode via cookies
    3. Redirects to the post URL

    Now when Next.js renders the page, it queries WordPress for draft content instead of published content.

    The Implementation

    Your preview API route:

    export async function GET(request: Request) {
      const { searchParams } = new URL(request.url);
      const secret = searchParams.get('secret');
      const id = searchParams.get('id');
    
      // Verify secret
      if (secret !== process.env.PREVIEW_SECRET) {
        return new Response('Invalid token', { status: 401 });
      }
    
      // Enable draft mode
      draftMode().enable();
    
      // Redirect to the post
      redirect(`/blog/${slug}`);
    }

    Then in your page component:

    export default async function Post({ params }) {
      const { isEnabled } = draftMode();
      
      // Fetch draft if preview mode is enabled
      const post = await fetchPost(params.slug, {
        preview: isEnabled
      });
      
      return <PostTemplate post={post} />;
    }

    The WordPress Side

    Our plugin adds a “Preview on Frontend” button to the WordPress editor that generates the preview URL automatically.

    It also handles authentication – only logged-in WordPress users can generate preview links, keeping your drafts secure.

    Exit Preview

    We add a banner to preview pages:

    {draftMode().isEnabled && (
      <div className="bg-yellow-100 p-4">
        <p>You are viewing a preview.</p>
        <a href="/api/exit-preview">Exit Preview</a>
      </div>
    )}

    The exit route simply clears the draft mode cookie.

    Why This Matters

    Without preview mode, editors have to publish content to see how it looks. This breaks their workflow and risks publishing unfinished work.

    With FlatWP’s preview mode, editors can iterate on drafts, share preview links with teammates, and only publish when ready.

    It’s a small feature that makes a huge difference in adoption.

  • GraphQL vs REST API: Why We Chose GraphQL for FlatWP

    WordPress offers both REST API and GraphQL for headless implementations. We deliberately chose GraphQL for FlatWP, and here’s why.

    The Over-Fetching Problem

    WordPress REST API returns everything about a post, whether you need it or not:

    GET /wp-json/wp/v2/posts/123

    You get the author object, meta fields, embedded media, comment stats, and dozens of other fields you’ll never use. This bloats response sizes and slows down your site.

    GraphQL’s Precision

    With GraphQL, you request exactly what you need:

    query GetPost($id: ID!) {
      post(id: $id) {
        title
        content
        featuredImage {
          url
          alt
        }
      }
    }

    The response contains only those fields. Nothing more, nothing less.

    TypeScript Integration

    GraphQL’s typed schema enables automatic TypeScript generation. Our codegen process creates perfect types from your queries:

    // Auto-generated from GraphQL schema
    interface GetPostQuery {
      post: {
        title: string;
        content: string;
        featuredImage: {
          url: string;
          alt: string;
        };
      };
    }

    This is nearly impossible with REST API without manually maintaining types.

    Nested Data in One Request

    REST API requires multiple requests for nested data:

    // Get post
    GET /wp-json/wp/v2/posts/123
    // Get author
    GET /wp-json/wp/v2/users/5
    // Get categories
    GET /wp-json/wp/v2/categories?post=123

    GraphQL fetches everything in one query:

    query GetPost($id: ID!) {
      post(id: $id) {
        title
        author {
          name
          avatar
        }
        categories {
          name
          slug
        }
      }
    }

    Better Performance

    Fewer requests = faster page loads. We measured:

    • REST API: 3 requests, 45KB total, 280ms
    • GraphQL: 1 request, 12KB, 95ms

    The WPGraphQL Plugin

    WPGraphQL is mature, well-maintained, and has a huge ecosystem:

    • WPGraphQL for ACF
    • WPGraphQL for WooCommerce
    • WPGraphQL for Yoast SEO
    • WPGraphQL JWT Authentication

    Popular plugins have GraphQL extensions, making integration seamless.

    When to Use REST API

    GraphQL isn’t always the answer. Use REST API when:

    • You need file uploads (GraphQL doesn’t handle multipart well)
    • Your WordPress host doesn’t support WPGraphQL
    • You’re building a simple integration with minimal data needs

    But for full-featured headless sites, GraphQL’s benefits are undeniable.

  • Deploying FlatWP: Vercel, Netlify, or Self-Hosted?

    FlatWP works on any platform that supports Next.js, but the deployment choice significantly impacts performance and developer experience.

    Vercel (Recommended)

    Vercel created Next.js, so integration is seamless:

    Pros:

    • Zero-config deployment – just connect GitHub
    • ISR works perfectly out of the box
    • Global edge network for fast delivery
    • On-demand revalidation built-in
    • Excellent free tier (100GB bandwidth, unlimited builds)
    • Preview deployments for every PR

    Cons:

    • Can get expensive at scale ($20/user/month for teams)
    • Vendor lock-in (though you can export)

    Best for: Most projects, especially if you value DX and don’t mind the cost at scale.

    Netlify

    Netlify has excellent Next.js support via their Essential Next.js plugin:

    Pros:

    • Strong free tier (100GB bandwidth)
    • Great build performance
    • Form handling built-in
    • Split testing features
    • Slightly cheaper than Vercel at scale

    Cons:

    • ISR support is newer, less battle-tested
    • Some Next.js features lag behind Vercel
    • Build times can be slower for large sites

    Best for: Teams already on Netlify or those wanting to save costs.

    Cloudflare Pages

    Cloudflare now supports Next.js via their @cloudflare/next-on-pages adapter:

    Pros:

    • Incredibly generous free tier (unlimited requests)
    • Cloudflare’s global network
    • R2 storage for assets
    • Very cost-effective at scale

    Cons:

    • Requires adapter configuration
    • Some Next.js features not supported
    • Newer, less documentation
    • ISR implementation differs from Vercel

    Best for: High-traffic sites on a budget.

    Self-Hosted (Node.js)

    You can deploy Next.js to any Node.js server:

    Pros:

    • Full control
    • No platform fees
    • Can use your existing infrastructure

    Cons:

    • You manage scaling, CDN, caching
    • More DevOps overhead
    • ISR requires Redis or similar for cache
    • No automatic preview deployments

    Best for: Enterprise with existing infrastructure or strict data requirements.

    Our Recommendation

    Start with Vercel. The DX is unmatched and the free tier is generous enough for most projects. Once you’re at scale and costs matter, evaluate Netlify or Cloudflare.

    For the WordPress backend, use any WordPress host – FlatWP doesn’t care where WordPress lives as long as GraphQL is accessible.