WordPress TypeScript Generator for Custom Fields | Field Forge
Download Log in

TypeScript Generation for Headless WordPress

Field Forge auto-generates TypeScript type definitions (.d.ts files) for every field group on your WordPress site. Every field type is mapped to its TypeScript equivalent. Repeater fields become Array<SubFields>. Flexible content becomes discriminated unions. The result: a fully-typed custom fields API for your Next.js, Astro, Nuxt, SvelteKit, or any JavaScript frontend.


The headless WordPress type-safety problem

Headless WordPress means WordPress serves as the CMS and a separate JavaScript frontend (Next.js, Astro, Nuxt, etc.) renders the pages. The frontend fetches content via REST API or WPGraphQL and displays it. For simple content — title, excerpt, featured image — TypeScript types are built into most SDKs.

Custom fields are the problem. Custom fields are plugin-defined, not core WordPress. TypeScript doesn’t know that your “Hero Section” field group has a title: string, subtitle: string, background_image: WPImage, and cta_button: { text: string; url: string; }. Frontend code that accesses data.hero_title has no type safety — typos, missing fields, and field-rename refactors all become runtime errors.

The solutions that existed before Field Forge:

  • Write types by hand — tedious and drifts out of sync when you edit field groups in WordPress
  • Use a generic any — defeats the purpose of TypeScript
  • Use Zod or similar runtime validation — adds boilerplate to every API call
  • Use code generation from GraphQL schema — works if you use WPGraphQL + GraphQL Code Generator, but complex to set up

Field Forge provides a simpler path: auto-generate TypeScript definitions directly from your field groups.


How it works

Step 1: Build a field group in Field Forge

You design a field group in the visual builder — let’s say “Hero Section” with fields for title, subtitle, background image, and CTA button.

Step 2: Click “Download TypeScript”

In the field group admin screen, Field Forge has a “Download TypeScript” button that generates a .d.ts file containing the type definitions for all your field groups.

Step 3: Use the types in your frontend

Commit the .d.ts file to your frontend repo (or copy-paste into an existing types file). TypeScript now knows the exact shape of every field group’s data.

import { HeroSectionFields } from './types/fieldforge.d.ts';

function Hero({ data }: { data: HeroSectionFields }) {
  return (
    <section>
      <h1>{data.title}</h1>
      <p>{data.subtitle}</p>
      <img src={data.background_image.url} alt={data.background_image.alt} />
      <a href={data.cta_button.url}>{data.cta_button.text}</a>
    </section>
  );
}

TypeScript catches typos, missing fields, and wrong types at compile time. IDE autocomplete works. Refactoring is safe.


Field type mapping

Every Field Forge field type has a corresponding TypeScript type:

Field Forge field TypeScript type
Text string
Textarea string
Number number
Range number
Email string
URL string
Password string (sensitive)
Image WPImage (built-in interface)
File WPFile
WYSIWYG string (HTML)
oEmbed string (embed HTML)
Gallery WPImage[]
Select (single) 'option_a' \| 'option_b' \| 'option_c' (literal union of choices)
Select (multi) Array<'option_a' \| 'option_b'>
Checkbox string[]
Radio 'option_a' \| 'option_b'
True/False boolean
Button Group 'option_a' \| 'option_b'
Relationship WPPost[]
Post Object WPPost
Page Link string (URL)
Taxonomy WPTerm[] or WPTerm (depending on settings)
User WPUser or WPUser[]
Date Picker string (ISO format)
Time Picker string
Color Picker string (hex or rgba)
Repeater Array<RepeaterSubFields> (nested type)
Group nested type
Flexible Content Array<LayoutA \| LayoutB \| LayoutC> (discriminated union)
Clone reference to cloned group

Built-in types

Field Forge’s generated .d.ts includes helper types you’ll use throughout your frontend:

interface WPImage {
  id: number;
  url: string;
  alt: string;
  width: number;
  height: number;
  sizes: {
    thumbnail: string;
    medium: string;
    large: string;
    full: string;
  };
}

interface WPFile {
  id: number;
  url: string;
  filename: string;
  mime_type: string;
  filesize: number;
}

interface WPPost {
  id: number;
  title: string;
  slug: string;
  content: string;
  excerpt: string;
  date: string;
  modified: string;
  featured_image: WPImage | null;
  categories: WPTerm[];
  tags: WPTerm[];
}

interface WPUser {
  id: number;
  name: string;
  email: string;
  avatar: string;
}

interface WPTerm {
  id: number;
  name: string;
  slug: string;
  description: string;
}

Example: Hero field group

A field group called “Hero Section” with title, subtitle, background image, and CTA button generates:

export interface HeroSectionFields {
  title: string;
  subtitle: string;
  background_image: WPImage;
  cta_button: {
    text: string;
    url: string;
    open_in_new_tab: boolean;
  };
}

Usage in a Next.js component:

import type { HeroSectionFields } from '@/types/fieldforge';

interface Props {
  hero: HeroSectionFields;
}

export function Hero({ hero }: Props) {
  return (
    <section className="hero">
      <img
        src={hero.background_image.sizes.large}
        alt={hero.background_image.alt}
        width={hero.background_image.width}
        height={hero.background_image.height}
      />
      <h1>{hero.title}</h1>
      <p>{hero.subtitle}</p>
      <a
        href={hero.cta_button.url}
        target={hero.cta_button.open_in_new_tab ? '_blank' : undefined}
      >
        {hero.cta_button.text}
      </a>
    </section>
  );
}

Every property is typed. TypeScript catches hero.titel (typo), hero.background_image.URL (wrong case), and hero.cta_button.open_new_tab (wrong field name) at compile time.


Repeater types

Repeater fields become Array<SubFields>. Nested repeaters work recursively:

export interface TeamPageFields {
  team_members: Array<{
    name: string;
    photo: WPImage;
    bio: string;
    skills: Array<{
      skill_name: string;
      proficiency: number;
    }>;
  }>;
}

TypeScript understands the nesting. Iterating over team_members and then skills is fully typed.


Flexible content as discriminated unions

Flexible content fields generate discriminated unions — TypeScript’s native feature for handling multi-type arrays:

type HeroLayout = {
  acf_fc_layout: 'hero';
  title: string;
  subtitle: string;
  background_image: WPImage;
};

type FeaturesLayout = {
  acf_fc_layout: 'features';
  section_title: string;
  features: Array<{
    icon: string;
    title: string;
    description: string;
  }>;
};

type CTALayout = {
  acf_fc_layout: 'cta';
  headline: string;
  button: { text: string; url: string };
};

export interface LandingPageFields {
  page_sections: Array<HeroLayout | FeaturesLayout | CTALayout>;
}

In your frontend component, use a type guard to render the right layout:

function PageSections({ sections }: { sections: LandingPageFields['page_sections'] }) {
  return (
    <>
      {sections.map((section, i) => {
        if (section.acf_fc_layout === 'hero') {
          return <Hero key={i} data={section} />;
        }
        if (section.acf_fc_layout === 'features') {
          return <Features key={i} data={section} />;
        }
        if (section.acf_fc_layout === 'cta') {
          return <CTA key={i} data={section} />;
        }
      })}
    </>
  );
}

Inside each if block, TypeScript narrows section to the correct type. No casting needed.


Regeneration workflow

When you edit field groups in Field Forge’s admin, the types change. To keep your frontend in sync:

  1. Edit the field group in WordPress
  2. Click “Download TypeScript” in the Field Forge admin
  3. Replace the .d.ts file in your frontend repo
  4. Commit the change

Or automate it via Field Forge’s REST API:

# Fetch the latest TypeScript definitions via curl
curl https://wp.example.com/wp-json/fieldforge/v1/typescript > types/fieldforge.d.ts

Add this to your frontend build pipeline and types are always up to date.


Works with any frontend framework

TypeScript types are framework-agnostic. Field Forge’s generated types work with:

  • Next.js — React-based, excellent TypeScript integration
  • Astro — islands architecture, great for content sites
  • Nuxt — Vue-based, Nuxt Content integration
  • SvelteKit — Svelte-based, built-in TypeScript support
  • Remix — React-based, server-first
  • Vanilla TypeScript — any frontend that uses TypeScript

Ready for type-safe headless WordPress?

Get Field Forge — from $35/year →

TypeScript generation is included in every paid plan. No other WordPress custom fields plugin has this feature.

Forge AI Assistant Online

Hi! I'm the Field Forge AI assistant. Ask me anything about the plugin — setup, features, troubleshooting, or development.

Just now
Powered by Forge AI · Browse docs