Tag: typescript

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

  • Monorepo Architecture for FlatWP Projects

    FlatWP uses a monorepo to keep Next.js and WordPress plugin development in sync. Here’s why and how it works.

    Why Monorepo?

    In a headless setup, you’re maintaining:

    • Next.js frontend
    • WordPress plugin for webhooks/admin
    • Shared TypeScript types
    • Configuration files

    Keeping these in separate repos means:

    • Types get out of sync
    • Changes require coordinating multiple PRs
    • Testing becomes complicated
    • New developers need to clone multiple repos

    A monorepo solves all of this.

    Our Structure

    flatwp/
    ├── apps/
    │   ├── web/           # Next.js app
    │   └── wp-plugin/     # WordPress plugin
    ├── packages/
    │   ├── types/         # Shared TS types
    │   └── config/        # ESLint, TS configs
    ├── package.json
    └── pnpm-workspace.yaml

    Shared Types in Action

    When you generate GraphQL types, both the Next.js app and WordPress plugin admin UI access them:

    // packages/types/src/wordpress.ts
    export interface Post {
      id: string;
      title: string;
      slug: string;
    }
    
    // Used in apps/web
    import { Post } from '@flatwp/types';
    
    // Used in apps/wp-plugin admin UI
    import { Post } from '@flatwp/types';

    One source of truth, no duplication.

    pnpm Workspaces

    We use pnpm for fast, efficient dependency management:

    # pnpm-workspace.yaml
    packages:
      - 'apps/*'
      - 'packages/*'

    Run commands across all workspaces:

    pnpm dev          # Start all apps in dev mode
    pnpm build        # Build all apps
    pnpm type-check   # Type check everything

    Turborepo for Speed

    Turborepo caches builds and runs tasks in parallel:

    // turbo.json
    {
      "tasks": {
        "build": {
          "dependsOn": ["^build"],
          "outputs": [".next/**", "build/**"]
        },
        "dev": {
          "cache": false,
          "persistent": true
        }
      }
    }

    Second builds are near-instant thanks to caching.

    Benefits We’ve Seen

    • Faster onboarding: One clone, one install
    • Atomic changes: Update types + usage in one commit
    • Better CI: Test everything together
    • Shared tooling: One ESLint config, one Prettier config

    When NOT to Monorepo

    If you’re just starting and want to move fast, skip the monorepo initially. Build the Next.js app first, add the WordPress plugin later.

    But once you’re serious about shipping, the monorepo pays dividends.