Metadata & Compiler Extensions
Declare page metadata, integrate compiler plugins, and find the programmatic compiler APIs and custom PHP workflow.
Start with the normal React theme and export workflow. Use the features here when a site needs metadata, a build integration, or server behavior beyond the standard primitives.
Page and site metadata
WpHead declares document metadata. Put defaults in the root layout and template-specific declarations in the appropriate Page or single template. During export, ForgeWP records head metadata separately from the visible body and writes the generated head fragments used by WordPress.
1import { WpHead } from "@forgewp/react"
2
3export function StayMetadata() {
4 return (
5 <WpHead
6 title="Stay in the courtyard"
7 description="Explore our courtyard rooms and plan your arrival."
8 ogTitle="A courtyard stay"
9 ogDescription="Quiet rooms in the heart of the city."
10 ogImage="https://example.com/images/courtyard.jpg"
11 ogType="website"
12 twitterCard="summary_large_image"
13 canonical="https://example.com/stay/"
14 schema={{
15 "@context": "https://schema.org",
16 "@type": "WebPage",
17 name: "Courtyard stay",
18 }}
19 />
20 )
21}Mount this component in the intended template. Replace the example URLs and copy with the site's real values. keywords, twitterCreator, and extra React children are also supported. Keep structured data under your control and supply data appropriate to the Page.
SEO is a convenience wrapper around WpHead, with default description/keywords and an additional noIndex flag. A source-owned metadata value changes when you rebuild the theme; use recognized WordPress bindings or the site's chosen SEO plugin for content that editors own.
After installing an export, inspect the actual document head for title, description, canonical URL, social image, robots directives, and structured data. Check both a Page and a custom single-post template. If a WordPress SEO plugin also emits metadata, choose ownership and inspect for duplicate tags. The compiler includes presence-gated schema integrations for Yoast and Rank Math; verify the active plugin's final output on the site.
Compiler plugins
A compiler plugin runs on the development machine during loading/export. It is distinct from a WordPress plugin installed in wp-admin.
A ForgeWPPlugin has a name and can provide synchronous hooks:
Hook Arguments and result validateConfig(config, themeRoot, context); throw an error to reject the configuration.transformFunctionsPhp(php, config, themeRoot, context); return the complete transformed PHP string. |
|---|
Hooks run in configured order. ForgeWPPluginContext types the supplied Node filesystem and path helpers as context.fs and context.path. Hooks that do not need every argument can simply accept fewer parameters. Form files are merged after plugin validation, so a validation hook should not assume all discovered form contracts are already in config.forms.
For example, the monorepo's hotelchecker24/wp.config.ts uses @forgewp/plugin-seo. Its configuration includes:
1import seoPlugin from "@forgewp/plugin-seo"
2
3const plugins = [
4 seoPlugin({
5 sitemaps: {
6 postTypes: ["post", "page"],
7 taxonomies: ["category", "post_tag"],
8 },
9 }),
10]Install or link that package in the theme, then add plugins to the object passed to defineConfig. Use the post types and taxonomies that actually exist on your site. Core also supports seo.sitemaps in wp.config.ts; its generated filters add the specified post types and taxonomies to the existing WordPress core providers and defer when a supported SEO plugin is active. The optional compiler plugin supplies another integration path. Choose one configuration path and inspect the generated hooks and live sitemap instead of duplicating the same customization.
The optional SEO plugin also accepts plugins.yoast, plugins.rankMath, and favicon. Review its configuration separately from your chosen WordPress SEO plugin's settings.
Custom PHP with src/server/
Use a WordPress plugin for behavior that should survive switching themes. For small theme-specific server hooks, place PHP files directly in src/server/. The exporter appends top-level .php files in sorted filename order to the generated functions.php, removing their outer PHP tags.
1<?php
2add_filter('excerpt_length', function ($length) {
3 return 24;
4}, 999);Export again and check the generated functions.php for this hook. Run PHP syntax validation and test the affected output on WordPress. Avoid redeclaring functions or relying on nested folders being discovered. Changes to generated functions.php belong in source so the next export includes them.
Programmatic compiler API
Most theme authors should use pnpm forgewp export. Build tools and adapter integrations can import the following exports from @forgewp/compiler. These functions act on project files; use a temporary copy when experimenting with export or validation routines that repair/scaffold source.
Export Purpose defineConfig(config)Typed identity helper for theme configuration. loadConfig(themeRoot)Load/validate config and merge discovered form files. exportTheme(options)Export a theme; returns config, outDir, zipPath, and assets.validateCriticalFiles(themeRoot)Preflight checks, including supported source restoration. validateExport({ themeRoot, outDir, assets, config, strict? })Inspect exported files; returns missing and warnings.scanForHydrationIslands(themeRoot)Discover island names. scanForHydrationIslandsWithProps(themeRoot)Discover island records with source paths and trigger/gating details. findComponentPath(themeRoot, kebabName)Find an island component file, or null.getHydrationRollupInputs(themeRoot)Build Vite/Rollup entry mappings for islands. scanForEditableSchemas(themeRoot)Discover editable schemas from source. resolveFrameworkAdapter(adapterName?)Resolve the adapter module specifier. loadFrameworkAdapter(adapterName?)Load the adapter implementation. analyzeHydrationIslands(themeRoot, mapping)Measure compiled island chunk sizes from a name-to-chunk mapping. generateVisualReport(themeRoot, analysis, islandsWithProps, config)Write the diagnostics report. forgewpPageConfigPlugin()Vite integration for Page configuration. forgewpVirtualPlugin({ projectRoot? }?)Vite integration for generated data/hooks modules. |
|---|
The current runtime accepts exportTheme({ themeRoot, skipBuild?, zip?, validate?, strict?, packageManager?, onProgress? }). These options are described by ForgeWPExportOptions; the returned promise resolves to ForgeWPExportResult. Progress callbacks receive ForgeWPExportProgress with string stage and message properties. The adapter contract is ForgeWPFrameworkAdapter, with build assets and static markup described by ForgeWPBuildAssets and ForgeWPStaticMarkup.
See Compiler Architecture for the pipeline and Framework Development for package responsibilities.
Typed build-tool integration
A build script can use the same export options as the CLI:
1import { exportTheme, type ForgeWPExportResult } from "@forgewp/compiler"
2
3export async function exportProject(
4 themeRoot: string
5): Promise<ForgeWPExportResult> {
6 return exportTheme({
7 themeRoot,
8 validate: true,
9 strict: true,
10 zip: false,
11 onProgress({ stage, message }) {
12 console.log(stage, message)
13 },
14 })
15}The function above runs an export when called; use it from your build tooling after selecting the intended project directory. A progress callback receives lifecycle messages; the current exporter catches callback errors so reporting does not abort the export. The stage is a string, allowing the compiler to add reporting stages without requiring a new callback signature.
Additional result contracts are ForgeWPValidationOptions / ForgeWPValidationResult, ForgeWPHydrationIsland, ForgeWPEditableField, ForgeWPIslandDiagnostic, and ForgeWPHydrationAnalysis. Parsed editable fields retain provider-specific metadata as unknown; check or narrow that metadata before using it. The diagnostics analysis can also include optional static-lint violations.