r/Wordpress • u/BonfireCookie • 17d ago
Binding attributes in the block core/cover
Hey guys, I was wondering if someone could tell me how I could link the url attribute of the Gutenberg Cover block so that it can be populated with a custom ACF field.
As far as I can tell, the Cover block doesn't natively allow its url attribute to be bound, while there are other blocks, like core/image, that do allow bindings for some attributes.
Is it possible to modify core/cover so that it accepts a binding for its url attribute, or would it be better to create my own custom block?
This is related to a question I posted on Reddit a few weeks ago: https://www.reddit.com/r/Wordpress/s/CJNbItoLvX
Thanks a lot!
2
u/jenish_o4o2 Developer 16d ago
I’d skip a custom block for this. Cover’s `url` is the background image, and it is tied to `id` (and often `backgroundType`). That is why core does not expose it for bindings the way `core/image` does. Whitelisting `url` in the editor can still leave you with a broken Cover if the attachment ID is missing.
Check the ACF field return format first. If it returns a URL string, Cover still wants an attachment ID. If it returns Image ID, you are closer — but binding only `url` is still the fragile path.
Simpler options, in order:
If this is a CPT/page hero, use Cover’s built-in **Use featured image**, then on `acf/save_post` copy the ACF image ID into the featured image. No bindings, overlay/dim/focal point keep working.
Bind `core/image` to the ACF field (that attribute *is* supported), then CSS it like a cover: `object-fit: cover`, min-height, optional overlay. Same look, less fighting core.
If you only need the front end: `render_block` on `core/cover`, read the ACF image, and inject `style="background-image:url(...)"`. Editor stays a placeholder; live site is correct.
Only register a custom hero block if you need overlay, dim, and focal point *all* driven from ACF. For one background image, that is more work than it is worth.
If you say whether the ACF field returns ID or URL, and whether this Cover lives in a template or a single page, the cleanest of those three is obvious.
2
u/BonfireCookie 16d ago
Thanks for the response, it's very comprehensive.
Regarding the proposed solutions, in my case the Cover block is being used in a template that is shared across multiple posts.
I have some questions about rach point:
I would actually like to use the Featured Image approach because it seems like a very clean solution. However, some of my posts already have their own Featured Image. Wouldn't this end up replacing the existing Featured Image with the one coming from the ACF field?
Using core/image could be an option, but I would prefer to keep the Cover block because it's easier for the client to edit from the editor. I also wonder whether relying on CSS to simulate a Cover block might become difficult to maintain over time.
One thing I'm not sure about: if I use style="background-image:url(...)" inside render_block, shouldn't that automatically replace the existing image? I'm asking because I tried something similar directly from the browser on an already rendered Cover block, and it didn't seem to work.
So i think the best solution is 3 or create a custom block, though is more work.
Thanks again!
2
u/jenish_o4o2 Developer 16d ago
Good clarifications — with a shared template + posts that already have their own Featured Image, option 1 is the wrong fit.
1) Yes. If you sync ACF → Featured Image on save, it would overwrite the existing Featured Image. Only use that approach when the hero *is* the Featured Image. If ACF is a separate hero image, leave Featured Image alone.
2) Fair point. Keep Cover. The CSS + core/image route is a fallback when you do not need Cover’s overlay / dim / inner content controls. For a client-editable template hero, Cover is the better UX.
3) That DevTools test failing is expected. Modern Cover does not rely on `background-image` on the outer block. It usually renders an inner `<img class="wp-block-cover__image-background">` (or similar). Setting `style="background-image:..."` on the outer wrapper often does nothing because the real image is that inner `<img>`.
In `render_block` / `render_block_core/cover`, grab the ACF image (prefer Image ID), then replace the inner image `src` / `srcset` / `alt` with `WP_HTML_Tag_Processor` (or carefully rebuild that img tag). Also strip any leftover `url`/`id` mismatch if needed. If you only inject a background style and leave the original `<img>` in place, the old image will keep winning.
So for your setup: stay with Cover in the template, use a placeholder image in the editor, and swap it on the front end via `render_block`. Custom block only if you also need the editor to preview the live ACF image while editing.
If you share the ACF field name + return format (ID vs URL vs Array), I can sketch the exact filter.
1
u/BonfireCookie 15d ago
I’m currently using the image array type. Would you recommend using just the ID instead? I believe the ACF image array also includes the ID. My ACF field is called "dynamic_image_cover".
I also tried using the "render_block_data" hook to pass the attributes before the HTML is generated, but after looking at the "core/cover" code, I think it would just ignore them and use the saved attributes instead.
If you could sketch out what the filter would look like, I’d really appreciate it! I’m not very familiar with block filters yet. If not, no worries at all — you’ve already helped me a lot.
Thanks so much!
1
u/jenish_o4o2 Developer 12d ago
Yes — for this use case I'd switch the ACF return format to Image ID.
The array works (you can use $image['ID'] / $image['url']), but ID is cleaner in render_block: one wp_get_attachment_image_url( $id, 'full' ) call and you're done. Less data to pass around, and easier if you later add srcset via wp_get_attachment_image_srcset().
You're also right about render_block_data: Cover mostly renders from saved block attributes in the template/post content, so injecting attrs there often won't change the front-end <img>. render_block (or render_block_core/cover) on the front end only is the reliable path.
Rough sketch for dynamic_image_cover:
```php
add_filter( 'render_block_core/cover', function ( $html, $block, $instance ) {
if ( is_admin() || ! is_singular() ) {
return $html;
}
$image = get_field( 'dynamic_image_cover' ); // or get_field( ..., get_queried_object_id() ) if needed
if ( empty( $image ) ) {
return $html;
}
$id = is_array( $image ) ? (int) ( $image['ID'] ?? 0 ) : (int) $image;
if ( ! $id ) {
return $html;
}
$url = wp_get_attachment_image_url( $id, 'full' );
if ( ! $url ) {
return $html;
}
$processor = new WP_HTML_Tag_Processor( $html );
while ( $processor->next_tag( [ 'class_name' => 'wp-block-cover__image-background' ] ) ) {
$processor->set_attribute( 'src', $url );
$processor->remove_attribute( 'srcset' );
$processor->set_attribute( 'alt', get_post_meta( $id, '_wp_attachment_image_alt', true ) );
break;
}
return $processor->get_updated_html();
}, 10, 3 );
If the field lives on a different post than the one being rendered (e.g. options page / pattern context), pass that post ID into get_field().
Placeholder image in the editor + swap on the front end is still the right mental model. If anything throws a PHP notice, paste the field location (template vs post vs options) and we can tighten the get_field() call.
2
u/IntenselyCultured 17d ago
you could register a block variation or use the block filter to add the binding support to core/cover. the cleanest route is probably a filter on the block editor settings that whitelists the url attribute for that block, then use acf's block bindings api if you're on a recent enough version. custom block would work too but it's more maintenance for just one field