Build Editable Room Details
Define named room fields once and render each Page's saved values through useWpMeta in a custom template.
Create a room-details Page whose title, description, capacity, and size can be updated in WordPress. The layout stays in React, while each Page stores its own room values.
This builds on Page templates and editable content. Instead of composing the main details from blocks, editors fill named fields with clear labels.
What you will build
Value Source Example Room name Native WordPress Page title Garden Suite Description room_description metadataA light-filled room overlooking the courtyard. Capacity room_capacity metadata2 guests Size room_size metadata36 square metres Layout and labels React source Description, capacity, and size arrangement |
|---|
A schema defines the field names, types, labels, and defaults. useWpMeta() reads a saved value for the current Page and uses the supplied default when the value is unset or empty.
Before you start
Use a React-adapter theme and a WordPress test site. Activate Advanced Custom Fields (ACF) on the test site for this walkthrough's generated field-group interface. The recipe uses text fields; the practice adds a URL field. ForgeWP supplies their definitions during export, so you can work from the schema rather than manually recreating the group in ACF.
The field definitions and their editing interface are separate concerns. This walkthrough uses ACF's interface; see ACF and Exported Fields for the underlying WordPress metadata integration.
1. Create the template and schema
Run these commands from the theme root:
pnpm forgewp make:page RoomDetails
pnpm forgewp make:editable RoomDetails --fields=room_description:text,room_capacity:text,room_size:textThey create src/app/pages/RoomDetails.tsx and cms/editables/room-details.ts. Their shared room-details slug connects the schema's field group to the generated page-room-details.php template.
2. Define the fields
Replace the schema file with:
1import { defineEditable, getEditableDefaults, text } from "@forgewp/react"
2
3export const editable = defineEditable({
4 room_description: text({
5 label: "Room description",
6 default: "A light-filled room overlooking the courtyard.",
7 }),
8 room_capacity: text({
9 label: "Room capacity",
10 default: "2 guests",
11 }),
12 room_size: text({
13 label: "Room size",
14 default: "36 square metres",
15 }),
16})
17
18export const defaults = getEditableDefaults(editable)The keys, such as room_size, are the saved-data identifiers. Labels are what editors see. Keep keys stable across layout updates; you can improve labels without renaming the stored values.
Capacity and size are text in this example so editors can enter complete phrases. Choose numeric fields in a design that needs numeric validation or calculations.
3. Read the current Page's values
Replace the Page component with:
1import { useWpMeta, useWpTitle } from "@forgewp/react"
2import { defaults } from "../../../cms/editables/room-details"
3
4export function RoomDetails() {
5 const title = useWpTitle()
6 const description = useWpMeta("room_description", defaults.room_description)
7 const capacity = useWpMeta("room_capacity", defaults.room_capacity)
8 const size = useWpMeta("room_size", defaults.room_size)
9
10 return (
11 <main className="mx-auto max-w-4xl px-6 py-16">
12 <p className="text-sm font-semibold uppercase tracking-wide text-slate-500">
13 Make yourself at home
14 </p>
15 <h1 className="mt-3 text-4xl font-bold text-slate-950">{title}</h1>
16 <p className="mt-6 text-lg leading-relaxed text-slate-600">{description}</p>
17 <dl className="mt-10 grid gap-6 border-t border-slate-200 pt-8 sm:grid-cols-2">
18 <div>
19 <dt className="text-sm font-semibold text-slate-500">Capacity</dt>
20 <dd className="mt-2 text-xl text-slate-950">{capacity}</dd>
21 </div>
22 <div>
23 <dt className="text-sm font-semibold text-slate-500">Room size</dt>
24 <dd className="mt-2 text-xl text-slate-950">{size}</dd>
25 </div>
26 </dl>
27 </main>
28 )
29}The import goes up three levels from src/app/pages/ to the project root, then enters cms/editables/. Reusing defaults keeps the schema and template aligned.
The dl, dt, and dd elements describe a list of labels and values. The template uses the Page title for its h1; the named fields supply its remaining content.
4. Export and enter room data
pnpm typecheck
pnpm forgewp export --validate --strictUse the project's equivalent typecheck if its scripts differ from the starter. For a local preview route, follow Create a Custom Page Template and add RoomDetails to the existing route switch.
- Update the theme on the WordPress test site and confirm ACF is active.
- Open an existing test Page or create one named Garden Suite.
- Select the generated Room Details template, associated with
page-room-details.php, and save. Reload the editor if needed for the template-specific field group to appear. - Find the generated Room Details Content group. Depending on the editor layout, it can appear below the main canvas.
- Enter a description, capacity, and size. Save the Page and view its frontend.
Keep this custom template selected. It renders the named fields directly; this version's Page body is unused because the component contains no BlockArea.
5. Verify independent Page values
- The Page title appears as the room name.
- Each saved field appears under the expected label and survives an editor reload.
- A second Page using the same template can have different room details.
- An unset or empty field uses its schema-derived default.
- Changing a layout class and updating the test theme keeps saved values connected to the same keys.
- Narrow screens stack the details, and wider screens display the two facts beside one another.
Defaults provide an initial/fallback display. When testing them, distinguish a field that has never been saved from one that has a saved value. Update existing saved content through WordPress; changing the source default is a separate action.
Inspect the export
File or area What to check page-room-details.phpGenerated custom Page wrapper Room fragment under forgewp-static/forgewp_get_meta_value calls using the expected keysGenerated field setup in functions.phpField labels and a Page-template location matching page-room-details.php |
|---|
Common checks
What you see What to check The field group is missing Check ACF activation, the assigned Page template, matching schema slug, and installed export A default keeps appearing Save a value under the exact field key and refresh applicable caches A field edit changes a different value Check the schema key and the first argument to its useWpMeta() callBody blocks do not appear This template displays named fields; add a BlockArea when the design also needs a body slot |
|---|
Continue to Practice: Add a Room Enquiry Link.