Working with ACF
Wonderpress treats Advanced Custom Fields as an optional hydration source for partials. Field definitions live in partial manifests; wonderpress-core registers the ACF groups at runtime; your page templates read the values through wonder_partial_props(). If ACF is absent, core no-ops.
Installing ACF
wonderpress init does not install ACF. When you need it:
ACF_PRO_LICENSE=... wonderpress acf installThat downloads and activates ACF directly from its official distribution. PRO is the default because Wonderpress repeater fields require it. The license key is read only from the environment: it is never accepted as a CLI flag, written to the project, or passed to WP-CLI.
Use --free to install the latest free edition from advancedcustomfields.com (that edition has no Repeater). Add --force to reinstall an edition that is already present.
Installing activates the plugin without persisting the PRO license for updates. Put define( 'ACF_PRO_LICENSE', '…' ); in wp-config.php, or activate under ACF → Updates.
Marking a partial ACF-compatible
wonderpress partial create --name Testimonials --acf \ --prop items:repeater --sub items:quote:string:required
--acf records acf_compatible: true on the manifest. Core reads manifests on acf/init and registers a field group from the declared properties. Property types string, boolean, email, select, post_object, image, link, and repeater become ACF fields. Optional label, when (conditionals keyed by sibling property name), and whitelisted acf overrides (ui, return_format, wrapper, and similar) are supported.
Repeaters are one level deep, via --sub or nested properties in a --json spec. Flexible content is not generated.
Location: groups appear only where you put them
Partial manifests declare fields only, never ACF location rules. A group with no location is skipped. Without that rule, a Hero metabox and a Hero block would appear on the same screen.
Locate a partial’s group in either of two ways:
- Template composition (preferred). List the partial in a page-template manifest’s
composition. Core derives the page-template location from that file and registers one combined field group for the template. - The
wonderpress_template_fieldsfilter, an explicit PHP map for when you are not using composition:
add_filter( 'wonderpress_template_fields', function () { return array( 'template-landing.php' => array( 'hero', 'testimonials' ), );} );
Avoid the default key unless you want those partials on every page that uses WordPress’s default template.
Hydrating in the template
( new \Wonderpress\Partials\Hero( wonder_partial_props( 'hero' ) ) )->render();wonder_partial_props( 'hero' ) returns array( 'acf' => get_field( 'hero' ) ); the partial’s construction copies the field values onto flat properties, so the view reads $title and $photo the same as it would from block attributes. With template composition, pass the instance id as the second argument: wonder_partial_props( 'landing-hero', 'hero-main' ).
That landing page typically locks 'all'. On a blog post you insert the Hero block instead, and the field group stays off that screen.
Dual partials
--acf and --block combine: the block authors through Gutenberg attributes, the PHP caller hydrates from ACF, and both paths must deliver the same value shapes to the view. The CLI enforces that every property type on a dual partial is dual-authorable, including transitively through partial embeds. The type tiers and wire formats are in Property types.
The placement rule from above applies with extra force: do not locate the ACF group on a page that also inserts the block.
Embedding the rich Link primitive
A property of type: "link" maps to a simple four-field group (content, url, open_in_new_tab, title). To embed the rich Link primitive (type switch, internal, file, email, and telephone targets) inside another partial, reference it as a partial embed:
{ "name": "cta", "type": "partial", "partial": "link", "label": "Call to action"}
The fields come from core’s manifest/partials/link.json, which core loads automatically for ACF registration when the partial is located. Render with wonder_render_partial_ref( 'link', $this->cta ) or new \Wonderpress_Core\Partials\Link( [ 'acf' => $this->cta ] ). The standalone manifest is also installable with wonderpress partial install-manifest link.
After editing manifests
Field definitions live in .wonderpress/manifest/partials/*.json. After editing one, run wonderpress partial sync <Name> so the class $_properties and block.json stay aligned, then reload the editor and re-save any page whose groups changed shape.