Tag: wordpress

  • Building FlatWP – Our Headless WordPress Journey

    Building FlatWP – Our Headless WordPress Journey

    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.

    Developer working on code

    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.

    Modern web development workspace

    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.

  • 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

    Mastering TypeScript with Advanced Custom Fields

    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. This guide will show you every workaround the proper solution.

    Code editor with TypeScript

    “TypeScript makes you feel like a wizard. ACF without types makes you feel like a detective. FlatWP gives you both.” – A satisfied developer

    The Problem With Untyped ACF

    When you query ACF fields through GraphQL, you get untyped data that looks like this:

    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. You can read more about this on the official ACF documentation.

    Real-World Problems

    Here are the issues we encountered before implementing type safety:

    1. Typos in field names that don’t show until production
    2. Refactoring field names becomes a search-and-replace nightmare
    3. No way to know what fields exist without checking WordPress admin
    4. Team members constantly asking “what’s the field name for X?”

    TypeScript code on monitor

    Breaking It Down Further

    The issue compounds when you have:

    • Multiple developers on the team
    • Complex field groups with nested repeaters
    • Client-requested field changes mid-project
    • Different ACF field types (relationships, galleries, etc.)
    Nested List Example

    Sometimes you need nested lists to organize information:

    • Frontend Issues
      • No autocomplete in VSCode/Cursor
      • Runtime type errors
      • Manual type guards everywhere
    • Backend Issues
      • Field name mismatches
      • Data structure uncertainty
      • Version control conflicts
    Why h6 Headings Matter

    Even though h6 is rarely used, it’s still valid HTML and should be styled properly. This is the deepest heading level you’ll encounter.


    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;
        width: number;
        height: number;
      };
      ctaText: string;
      ctaUrl: string;
      backgroundColor?: 'light' | 'dark' | 'accent';
    }

    Now your components are fully typed with intelligent autocomplete:

    export function HeroBlock({ fields }: { fields: HeroBlock }) {
      return (
        <section className={`hero hero--${fields.backgroundColor || 'light'}`}>
          <h1>{fields.heading}</h1>
          <p>{fields.subheading}</p>
          <img 
            src={fields.image.url} 
            alt={fields.image.alt}
            width={fields.image.width}
            height={fields.image.height}
          />
          <a href={fields.ctaUrl}>{fields.ctaText}</a>
        </section>
      );
    }

    Development team collaboration

    Advanced Formatting Examples

    Let’s look at various ways to format content for maximum readability.

    Mixed List Types

    Here’s an ordered list with definitions:

    1. Generate Types – Run the codegen command after ACF changes
    2. Import Types – Use them in your component props
    3. Enjoy Safety – TypeScript catches errors before runtime

    And an unordered list with code examples:

    • npm run generate-types – Generates ACF types
    • npm run build – Builds the Next.js app
    • npm run dev – Runs development server

    Pro tip: Add type generation to your pre-commit hooks so types are always in sync with your ACF configuration!

    Complex Table Example

    ACF Field Type TypeScript Type GraphQL Return Notes
    Text string String Simple text field
    Number number Int/Float Numeric values
    True/False boolean Boolean Checkbox value
    Image WPImage MediaItem Complex object with URL, alt, dimensions
    Repeater Array<T> [Type] Array of typed objects

    Flexible Content Blocks

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

    const blockComponents = {
      hero: HeroBlock,
      features: FeaturesBlock,
      testimonial: TestimonialBlock,
      cta: CTABlock,
      gallery: GalleryBlock,
    } as const;
    
    type BlockLayout = keyof typeof blockComponents;
    
    interface ACFBlock<T = unknown> {
      id: string;
      layout: BlockLayout;
      fields: T;
    }
    
    export function BlockRenderer({ blocks }: { blocks: ACFBlock[] }) {
      return (
        <>
          {blocks.map((block) => {
            const Component = blockComponents[block.layout];
            if (!Component) {
              console.warn(`Unknown block type: ${block.layout}`);
              return null;
            }
            return <Component key={block.id} fields={block.fields} />;
          })}
        </>
      );
    }

    Visit our documentation site for more examples and implementation details.

    Installation Steps

    Getting started is straightforward:

    1. Install the FlatWP WordPress plugin from the repository
    2. Configure your ACF field groups as usual
    3. Run npm install @flatwp/types in your Next.js project
    4. Execute npm run generate-types to create TypeScript interfaces
    5. Import and use types in your components

    Important: Make sure to run type generation after every ACF schema change to keep your frontend in sync!

    Developer working on laptop

    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.

    Pro Feature Highlights

    • Pre-configured ACF field groups
    • Matching React/Shadcn components
    • Dark mode variants
    • Mobile-responsive layouts
    • Accessibility built-in (ARIA labels, keyboard navigation)
    • Animation variants using Framer Motion

    You’ll be able to build complex page layouts in WordPress while maintaining full TypeScript safety in your React components. Check out our GitHub repository to follow development progress.


    Conclusion: Type Safety Changed Everything

    We shipped our first FlatWP site to production 6 months ago and haven’t looked back. Zero runtime errors related to ACF field access. Confident refactoring. Happy developers. Manual type checking Automatic type checking.

    The investment in proper TypeScript integration pays dividends on every single project.

  • 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.

  • Form Handling in Headless WordPress: Three Approaches

    Forms are everywhere – contact forms, newsletter signups, lead capture. Here’s how to handle them in a headless WordPress setup.

    Approach 1: WordPress Forms (Recommended)

    Use Contact Form 7 or WPForms in WordPress, submit from Next.js:

    // Server action in Next.js
    async function handleSubmit(formData: FormData) {
      const response = await fetch(
        'https://cms.flatwp.com/wp-json/contact-form-7/v1/contact-forms/123/feedback',
        {
          method: 'POST',
          body: formData,
        }
      );
      
      return response.json();
    }

    Pros:

    • Editors manage form fields in WordPress
    • Email notifications handled by WordPress
    • Submissions stored in WordPress database
    • Works with existing WordPress plugins

    Cons:

    • Extra API call to WordPress
    • WordPress becomes a dependency for forms

    Approach 2: Next.js Server Actions

    Handle forms entirely in Next.js with server actions:

    // app/contact/actions.ts
    'use server'
    
    export async function submitContact(formData: FormData) {
      const data = {
        name: formData.get('name'),
        email: formData.get('email'),
        message: formData.get('message'),
      };
      
      // Send email via Resend, SendGrid, etc.
      await sendEmail(data);
      
      // Store in database if needed
      await db.contacts.create(data);
    }

    Pros:

    • No WordPress dependency
    • Full control over validation and processing
    • Modern server actions pattern
    • Can integrate with any email service

    Cons:

    • Editors can’t manage form fields
    • Need separate storage for submissions
    • More code to maintain

    Approach 3: Third-Party Services

    Use Formspree, Tally, or similar:

    <form action="https://formspree.io/f/your-id" method="POST">
      <input name="email" type="email" />
      <button type="submit">Submit</button>
    </form>

    Pros:

    • Zero backend code
    • Spam protection included
    • Email notifications handled
    • Nice dashboard for submissions

    Cons:

    • Monthly cost ($0-$20)
    • Less customization
    • Another service to manage

    FlatWP’s Approach

    We include adapters for all three approaches. Our default recommendation:

    • Use WordPress forms for marketing sites (editors need control)
    • Use server actions for apps (more dynamic needs)
    • Use third-party for MVPs (fastest to ship)

    The beauty of headless is you’re not locked in. Start with one, switch to another as needs change.

    Validation with Zod

    Regardless of approach, validate with Zod:

    const contactSchema = z.object({
      name: z.string().min(2),
      email: z.string().email(),
      message: z.string().min(10),
    });
    
    export async function submitContact(formData: FormData) {
      const data = contactSchema.parse({
        name: formData.get('name'),
        email: formData.get('email'),
        message: formData.get('message'),
      });
      
      // data is now typed and validated
    }

    Type-safe forms with runtime validation. Beautiful.

  • The Cost of Going Headless: Is It Worth It?

    Headless WordPress adds complexity. Let’s be honest about the costs and benefits so you can make an informed decision.

    The Real Costs

    Development Time: A headless setup takes longer initially. Traditional WordPress theme: 1-2 weeks. Headless setup: 2-4 weeks for your first project. (FlatWP aims to cut this to 1 week.)

    Hosting:

    • WordPress: $15-50/month (same as before)
    • Next.js: $0-20/month (Vercel free tier or $20/month Pro)
    • Total: Similar to traditional WordPress

    Maintenance: Two systems to update instead of one. But Next.js updates are painless compared to WordPress plugin/theme updates.

    Learning Curve: Your team needs to know React and Next.js. Not trivial for PHP-only developers.

    The Benefits

    Performance: 3-5x faster page loads translate to higher conversion rates. For e-commerce, a 100ms improvement = 1% revenue increase.

    Security: WordPress admin is hidden behind authentication. Your public site has no PHP, no wp-admin exposure, no plugin vulnerabilities.

    Developer Experience: Modern tooling, TypeScript, component libraries, hot reload. This makes development faster and more enjoyable.

    Scaling: Static/ISR pages handle traffic spikes effortlessly. No server scaling needed.

    Flexibility: Want to add a React dashboard? Native mobile app? Share your WordPress content across multiple frontends easily.

    When Traditional WordPress Makes Sense

    Don’t go headless if:

    • You need to ship in <1 week
    • Budget is extremely tight
    • Your team doesn’t know React
    • The site is simple (5 pages, basic blog)
    • You rely heavily on WordPress themes

    When Headless Makes Sense

    Go headless if:

    • Performance matters (e-commerce, high-traffic)
    • You want modern DX
    • Security is critical
    • You need flexibility for future features
    • Your team knows or wants to learn React

    The FlatWP Advantage

    FlatWP reduces the “time to value” dramatically. Instead of 2-4 weeks for your first headless site, you’re shipping in 1 week with production-ready patterns.

    That cost reduction makes headless viable for many more projects.

    ROI Calculation

    Let’s say you’re an agency building client sites:

    • Traditional WordPress: $8k project, 2 weeks = $4k/week
    • Custom Headless: $12k project, 3 weeks = $4k/week (same rate, longer timeline)
    • FlatWP Headless: $10k project, 1.5 weeks = $6.6k/week (higher margins)

    The efficiency gain pays for itself immediately.

  • WooCommerce Headless: Coming to FlatWP Pro

    E-commerce is the #1 requested feature for FlatWP. We’re building a production-ready headless WooCommerce storefront for the Pro version.

    Why Headless WooCommerce?

    Traditional WooCommerce sites are slow. Product pages take 3-5 seconds to load, cart updates require full page refreshes, and checkout flows are clunky.

    A headless storefront gives you:

    • Instant navigation: Products load in <500ms
    • Smooth cart updates: Add to cart without page reload
    • Modern checkout: One-page, optimized flows
    • Better mobile UX: App-like experience

    Speed directly impacts conversion. Amazon found 100ms slower = 1% sales drop. For a $1M/year store, that’s $10k annually.

    The Technical Approach

    We’re using WPGraphQL for WooCommerce to query products, categories, and orders:

    query GetProducts {
      products(first: 20) {
        nodes {
          id
          name
          slug
          price
          image {
            url
          }
          ... on SimpleProduct {
            stockQuantity
          }
        }
      }
    }

    For cart and checkout, we’re using WooCommerce’s REST API with JWT authentication.

    What’s Included

    FlatWP Pro’s WooCommerce integration will include:

    • Product catalog: Grid/list views with filtering and sorting
    • Single product pages: Gallery, variants, add to cart
    • Cart: Persistent cart with quantity updates
    • Checkout: One-page checkout with Stripe integration
    • Account pages: Order history, address management
    • Search: Product search with filters

    All built with Shadcn components, fully typed with TypeScript.

    Performance Targets

    We’re targeting:

    • Product list: <1s LCP
    • Product detail: <1.5s LCP
    • Add to cart: <200ms
    • Checkout page: <2s LCP

    These are 3-5x faster than typical WooCommerce sites.

    Launch Timeline

    We’re targeting Q1 2025 for the WooCommerce beta. It’ll be included with FlatWP Pro ($299 one-time or $99/year).

    If you’re interested in early access, join our waitlist.

    Why Not Free?

    E-commerce is complex. We’re investing significant engineering time to make it production-ready:

    • Proper cart state management
    • Payment gateway integration
    • Tax calculations
    • Shipping methods
    • Order processing

    This is Pro-tier functionality. The revenue funds ongoing development and support.

    For DIY developers, we’ll document how to build WooCommerce integration yourself using the free version.

  • FlatWP 2025: Product Roadmap and Vision

    We’re launching FlatWP’s open-source version in December 2024. Here’s what we’re planning for 2025.

    Q1 2025: Foundation (Free Version)

    January – Public Beta

    • Open-source release on GitHub
    • Core ISR implementation
    • Basic WordPress plugin
    • Preview mode
    • Image optimization
    • Comprehensive documentation

    February – Community Building

    • Launch on Product Hunt
    • Create video tutorials
    • Start Discord community
    • Collect feedback and iterate

    March – Stability & DX

    • Bug fixes from beta feedback
    • Improved error messages
    • Better CLI tooling
    • VSCode extension (maybe)

    Q2 2025: Pro Features

    April – Pro Launch

    • Advanced ACF component library (20+ blocks)
    • Enhanced WordPress plugin with React admin UI
    • Performance monitoring dashboard
    • Priority support for Pro users
    • Commercial license

    May – WooCommerce Beta

    • Headless storefront (beta)
    • Product catalog with filtering
    • Cart functionality
    • Basic checkout flow

    June – Multi-Language

    • WPML/Polylang integration
    • i18n routing in Next.js
    • Language switcher component
    • Translated URLs

    Q3 2025: Scale & Polish

    July – WooCommerce GA

    • Production-ready e-commerce
    • Multiple payment gateways
    • Order management
    • Customer accounts

    August – Agency Features

    • White-label options
    • Multi-site support
    • Client handoff templates
    • Agency license tier

    September – Performance Tools

    • Advanced caching strategies
    • CDN optimization guides
    • Performance budgets
    • Automated Lighthouse CI

    Q4 2025: Enterprise & Ecosystem

    October – Template Marketplace

    • Industry-specific templates
    • Premium themes
    • Pre-built pages
    • Community contributions

    November – Enterprise Features

    • Advanced security options
    • Custom deployment workflows
    • Dedicated support
    • SLA agreements

    December – Year in Review

    • Retrospective blog post
    • Community awards
    • 2026 planning

    Community-Driven Development

    This roadmap will evolve based on user feedback. We’re building FlatWP with the community, not just for it.

    Top-voted GitHub issues get priority. Feature requests in Discord get considered. If you have ideas, we’re listening.

    Pricing Reminder

    • Free: Always free, MIT license
    • Pro: $299 one-time or $99/year (launching April 2025)
    • Agency: $999/year (launching August 2025)

    Early adopters who buy Pro before June 2025 get lifetime updates for their one-time payment.

    Let’s build the future of WordPress together.