Skip to content
CoverKit CoverKit v0.1.13

Native block bindings (experiment)

CoverKit can bind coverkit/layer attributes to post fields via WordPress native block bindings (metadata.bindings on the block). This path runs alongside the existing per–use-case mapping UI stored in _coverkit_use_cases. The experiment proves end-to-end binding without replacing the mapping sidebar.

Requirements: WordPress 7.0+ (register_block_bindings_source(), editor bindings UI). Gated by the coverkit_block_bindings_enabled filter (default true).

Use-case mappingsNative block bindings
Where configuredTemplate sidebar → use case → field → layerLayer block inspector → Layer {id} SmartPanel, or use-cases sidebar → Field bindings
Storage_coverkit_use_cases.mappings (per use case, per layer)metadata.bindings on each coverkit/layer block
ScopeOne mapping list per enabled use case; multiple layers can map the same fieldPer block, per attribute (text, image, imageId)
Editor UIsrc/editor/use-cases/MappingFields.jssrc/editor/use-cases/FieldBindingSelect.js, src/shared/inspector/bindings.js (core Attributes panel is intentionally hidden)
Apply at renderMapping_ApplicatorBlock_Bindings_Applicator

Legacy per-layer mapping.field in the layer inspector is unchanged; bindings are an additional opt-in path.

Why CoverKit reimplements binding resolution

Section titled “Why CoverKit reimplements binding resolution”

CoverKit does not render templates through WP_Block::render(). Generation parses block JSON into canvas elements in Template::parse(). WordPress resolves bindings inside private WP_Block::process_block_bindings().

Block_Bindings_Applicator mirrors that step: read element['metadata']['bindings'], call get_block_bindings_source( 'coverkit/field' )->get_value(), then write onto parsed elements via Mapping_Applicator::set_element_attribute() (including image hide-on-empty).

flowchart LR
subgraph editor [Template editor]
LayerBlock["coverkit/layer"]
BindUI["Layer bindings SmartPanel"]
OldMap["Use-case mappings sidebar"]
LayerBlock --> BindUI
LayerBlock --> OldMap
end
subgraph storage [Saved on template CPT]
MetaBindings["attrs.metadata.bindings"]
MetaUseCases["_coverkit_use_cases.mappings"]
end
subgraph render [Image generation]
Template["Template::apply_data()"]
BindApp["Block_Bindings_Applicator"]
MapApp["Mapping_Applicator"]
Generator["Generator"]
end
BindUI --> MetaBindings
OldMap --> MetaUseCases
MetaBindings --> BindApp
MetaUseCases --> MapApp
Template --> BindApp --> MapApp --> Generator

In Template::apply_data():

  1. Placeholder tokens in layer text ({post_title}, …)
  2. apply_block_bindings() — native bindings
  3. apply_use_case_mappings() — sidebar mappings
  4. process_elements() — typography, fit text, etc.

Precedence: When both a binding and a use-case mapping target the same layer and same attribute, the use-case mapping wins. Bindings apply first; mappings overwrite on conflict. Existing templates without bindings behave as before.

ClassFileRole
Block_Bindingsincludes/class-coverkit-block-bindings.phpRegisters source coverkit/field; declares bindable attributes text, image, imageId; get_field_value() reuses Field_Resolver + active use case formatting
Block_Bindings_Contextincludes/class-coverkit-block-bindings-context.phpStatic render scope (post_id, use case class, generation key) for one generation request
Block_Bindings_Applicatorincludes/class-coverkit-block-bindings-applicator.phpApplies bindings to parsed elements

Boot: Block_Bindings::get_instance() from coverkit.php init().

Binding source registration:

register_block_bindings_source( 'coverkit/field', [
'label' => __( 'CoverKit Field', 'coverkit' ),
'uses_context' => [ 'postId', 'postType' ],
'get_value_callback' => [ Block_Bindings::class, 'get_field_value' ],
] );

Field catalog for the editor: GET /wp-json/coverkit/v1/binding-fields?use_case=sandbox (see rest-api.md).

  • src/editor/block-bindings/index.jsregisterBlockBindingsSource( 'coverkit/field', … )
  • src/editor/block-bindings/bindingFieldsStore.js — loads field list from REST
  • src/editor/block-bindings/resolveFieldValue.js — preview values (same preview post as Sandbox / useUseCasePreview)
  • src/editor/use-cases/FieldBindingSelect.jsFieldBindingsPanel / FieldBindingsContent (SmartPanel in inspector, plain content in use-cases sidebar)
  • src/shared/inspector/bindings.js — layer inspector panel wired into InspectorControls

WordPress core’s native Attributes panel is hidden for coverkit/layer by returning an empty supported-attributes list from Block_Bindings::filter_supported_attributes(); server-side binding resolution is unchanged (Block_Bindings_Applicator falls back to SUPPORTED_ATTRIBUTES).

Imported from src/editor/index.js.

add_filter( 'coverkit_block_bindings_enabled', '__return_false' );

When disabled, the binding source is not registered, supported attributes are not declared, and Template::apply_block_bindings() returns early.

  • tests/php/BlockBindingsApplicatorTest.php — bound text on a parsed element resolves post_title for Sandbox
  • tests/php/UseCaseRestTest.phpGET /binding-fields catalog

Use the fixture markup below on a WordPress 7.0+ dev site with the Sandbox use case enabled.

Copy block markup from tests/fixtures/block-bindings-sandbox-qa.html into a new coverkit template (Code editor), or paste via Tools → Import if you maintain a reusable pattern.

  1. Open the template in the block editor.
  2. Select the Bound title layer → confirm there is no core Attributes panel in the block inspector.
  3. Open the Layer {id} SmartPanel in the block inspector (or Field bindings in the use-cases sidebar) → bind Text to Post Title (fixture markup may already include a binding).
  4. Enable Sandbox, pick a preview post with a known title and featured image.
  5. Confirm the canvas preview and generated Sandbox image show the post title on the headline layer and the featured image on the image layer.
  6. Add a Sandbox use-case mapping for the same layer’s text to a different field → confirm the mapping overrides the binding.
  7. Optional: bind image / imageId on an image layer via the CoverKit bindings panel and repeat with another post.

Stored on the layer block as metadata.bindings:

{
"text": {
"source": "coverkit/field",
"args": { "field": "post_title" }
}
}

Supported attributes: text (strings), image (URL), imageId (attachment ID).

  • Replacing the use-case mapping sidebar with bindings-only workflow
  • Pattern overrides / synced patterns
  • core/post-meta binding source for arbitrary meta keys

Copy when opening the feature PR:

feat: experiment with native block bindings on coverkit/layer
Adds a CoverKit field binding source and render applicator so layer attributes can be bound via WordPress 7.0 native metadata.bindings, alongside the existing per-use-case mapping system.
Registers server and client binding sources, applies bindings during Template::apply_data() before use-case mappings (mappings override on conflict), and documents the experiment for Sandbox QA.

← Codebase index · Blocks and editor · Hooks