Practice: Add an Editable CTA and Image
Extend the hero recipe with a saved call-to-action label, destination, image, and alternative text.
Start with Build an Editable Hero Block. Keep its heading and description, then add a call to action and an optional image. A call to action, or CTA, is a link inviting the visitor to do something, such as view rooms or contact the hotel.
Your task
Work in src/blocks/HeroBlock.tsx. Extend the existing block rather than registering a second block. Keep its name hero-block and its existing heading and description attributes so the instance you already saved stays connected.
New attribute Type and control Initial value How editors use it ctaLabelstring, textExplore our roomsEdit the link label directly in the canvas ctaUrlstring, URL#roomsSet a destination through the URL control coverobject, imagenullSelect an image from the Media Library imageAltstring, textAn empty string Supply alternative text for an informative image |
|---|
Render the image when a cover has been selected. Use a single-column layout on narrow screens and place text and image side by side on wider screens.
The initial destination #rooms points to an element on the same page with id="rooms". For a working test, set the CTA URL to an existing Page on your test site or add that anchor target.
Starter guidance
Add these imports to the recipe's existing import statement:
1import { defineBlock, WpEditable, WpImage } from "@forgewp/react"Use this attribute as the pattern for a structured editor control, then declare the remaining attributes yourself:
1ctaUrl: {
2 type: "string",
3 control: "url",
4 label: "CTA destination",
5 default: "#rooms",
6},Your implementation needs these connections:
- Bind the link's
hreftoctaUrlin both views. - Use
WpEditablewithtagName="span"for the label inside the editor's link. - Save label edits through
setAttributes. - Give
coveran image control and useWpImageto display the selected value. - Connect the image's
alttoimageAlt. - Keep editor and visitor layouts aligned.
Acceptance criteria
- The existing hero retains its saved heading and description after you update the theme.
- The CTA label can be edited in the canvas and survives saving and reloading.
- The CTA destination can be edited with the generated URL control.
- Clicking the CTA in Gutenberg keeps the editor open; test actual navigation on the visitor page.
- Selecting or replacing an image updates the block, and the selection survives reloading.
- An unselected cover leaves a readable text-only hero.
- The visitor's image uses the alternative text you supplied.
- At a narrow viewport, content stacks without horizontal overflow; at a wider viewport, text and image appear side by side.
- Two instances can use different labels, destinations, and images.
For an informative image, write alternative text that communicates what matters in the picture. An empty alternative is appropriate when the image is purely decorative.
Hints, if you need them
Hint 1: Save the label
The heading already demonstrates the pattern you need: an attribute supplies value, and onChange writes the new value with setAttributes. Use that same connection for ctaLabel.
Hint 2: Select an image
Use type: "object", control: "image", and default: null for cover. The generated Media Library control supplies the selected image value. Pass it to WpImage as src.
Hint 3: Render optional content
A conditional expression such as attributes.cover && (...) lets the image appear after a selection. Keep the surrounding layout readable before the image is selected.
Hint 4: Check both views
The editor uses edit; the visitor renderer comes from save. Add the image, CTA, and matching classes to both. The editor's label needs onChange; the visitor's label only needs its saved value.
Verify your work
Run the starter's typecheck and export commands:
pnpm typecheck
pnpm forgewp export --validate --strictUpdate the theme on your WordPress test site. Start with the hero instance saved during the recipe, then exercise every acceptance criterion. Inspect blocks/hero-block/block.json for the additional attributes and render.php for their visitor bindings.
Compare with the worked solution
When you are ready, open Solution: Hero CTA and Image. Compare the data bindings and verification results, not just the appearance. Different spacing and colors are welcome.
Extend it further
Add an editable eyebrow line above the heading using the same attribute-to-control pattern. Decide whether editors should change it directly in the canvas or through a sidebar field, then verify that two block instances keep independent values.