Skip to content

Commit

Permalink
Image block: Ensure the wp-image-123 class and data-id attributes…
Browse files Browse the repository at this point in the history
… work with block bindings / pattern overrides (WordPress#63013)

* Update the image block id classname via dynamic render when it mismatches the attribute value

* Also update data-id so that it uses the id attribute

* Adjust comment

* Fix PHP lint

* Only add `data-id` attribute to the image block when used in a gallery

* Use multiple array keys to check for gallery parent

* Change variable names

* Add e2e test

* Try alternative approach

* Revert "Try alternative approach"

This reverts commit ad46c2d.

* Add extra test for standalone image

* Only apply binding values for data-id attribute and wp-image classname when a binding is applied

* Make it more succinct

* Fix linting issues

---------

Co-authored-by: Mario Santos <[email protected]>
Co-authored-by: talldan <[email protected]>
Co-authored-by: SantosGuillamot <[email protected]>
Co-authored-by: cbravobernal <[email protected]>
Co-authored-by: kevin940726 <[email protected]>
Co-authored-by: ndiego <[email protected]>
Co-authored-by: jeherve <[email protected]>
Co-authored-by: perezcarreno <[email protected]>
  • Loading branch information
9 people authored and carstingaxion committed Jul 18, 2024
1 parent 20a2c32 commit d40a396
Show file tree
Hide file tree
Showing 2 changed files with 160 additions and 5 deletions.
31 changes: 26 additions & 5 deletions packages/block-library/src/image/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,33 @@ function render_block_core_image( $attributes, $content, $block ) {
return '';
}

$has_id_binding = isset( $attributes['metadata']['bindings']['id'] ) && isset( $attributes['id'] );

// Ensure the `wp-image-id` classname on the image block supports block bindings.
if ( $has_id_binding ) {
// If there's a mismatch with the 'wp-image-' class and the actual id, the id was
// probably overridden by block bindings. Update it to the correct value.
// See https://github.com/WordPress/gutenberg/issues/62886 for why this is needed.
$id = $attributes['id'];
$image_classnames = $p->get_attribute( 'class' );
$class_with_binding_value = "wp-image-$id";
if ( is_string( $image_classnames ) && ! str_contains( $image_classnames, $class_with_binding_value ) ) {
$image_classnames = preg_replace( '/wp-image-(\d+)/', $class_with_binding_value, $image_classnames );
$p->set_attribute( 'class', $image_classnames );
}
}

// For backwards compatibility, the data-id html attribute is only set for
// image blocks nested in a gallery. Detect if the image is in a gallery by
// checking the data-id attribute.
// See the `block_core_gallery_data_id_backcompatibility` function.
if ( isset( $attributes['data-id'] ) ) {
// Adds the data-id="$id" attribute to the img element to provide backwards
// compatibility for the Gallery Block, which now wraps Image Blocks within
// innerBlocks. The data-id attribute is added in a core/gallery
// `render_block_data` hook.
$p->set_attribute( 'data-id', $attributes['data-id'] );
// If there's a binding for the `id`, the `id` attribute is used for the
// value, since `data-id` does not support block bindings.
// Else the `data-id` is used for backwards compatibility, since
// third parties may be filtering its value.
$data_id = $has_id_binding ? $attributes['id'] : $attributes['data-id'];
$p->set_attribute( 'data-id', $data_id );
}

$link_destination = isset( $attributes['linkDestination'] ) ? $attributes['linkDestination'] : 'none';
Expand Down
134 changes: 134 additions & 0 deletions test/e2e/specs/editor/various/pattern-overrides.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ test.describe( 'Pattern Overrides', () => {

test.afterEach( async ( { requestUtils } ) => {
await requestUtils.deleteAllBlocks();
await requestUtils.deleteAllMedia();
} );

test.afterAll( async ( { requestUtils } ) => {
Expand Down Expand Up @@ -795,6 +796,139 @@ test.describe( 'Pattern Overrides', () => {
expect( patternInnerBlocks[ 0 ].attributes.link ).toBe( undefined );
} );

test( 'image block classname and data-id attributes contain the correct media ids when used in a gallery', async ( {
admin,
editor,
page,
requestUtils,
} ) => {
// Upload two images, one for the original pattern, one for the override.
const { id: originalImageId, source_url: originalImageSrc } =
await requestUtils.uploadMedia(
path.resolve(
process.cwd(),
'test/e2e/assets/10x10_e2e_test_image_z9T8jK.png'
)
);
const { id: overrideImageId, source_url: overrideImageSrc } =
await requestUtils.uploadMedia(
path.resolve(
process.cwd(),
'test/e2e/assets/1024x768_e2e_test_image_size.jpeg'
)
);
const overrideName = 'test';

// Might be overkill, but check that the ids are actually different.
expect( overrideImageId ).not.toBe( originalImageId );

// Create a pattern with a gallery that has a single image with pattern overrides enabled.
// It has media that is not yet uploaded.
const { id } = await requestUtils.createBlock( {
title: 'Pattern',
content: `<!-- wp:gallery {"linkTo":"none"} -->
<figure class="wp-block-gallery has-nested-images columns-default is-cropped"><!-- wp:image {"id":${ originalImageId },"sizeSlug":"large","linkDestination":"none","metadata":{"bindings":{"__default":{"source":"core/pattern-overrides"}},"name":"${ overrideName }"}} -->
<figure class="wp-block-image size-large"><img src="${ originalImageSrc }" alt="" class="wp-image-${ originalImageId }"/></figure>
<!-- /wp:image --></figure>
<!-- /wp:gallery -->`,
status: 'publish',
} );

// Insert the pattern into a new post, overriding the image via the pattern block attributes.
await admin.createNewPost();
const imageAlt = 'Overridden Image';
await editor.insertBlock( {
name: 'core/block',
attributes: {
ref: id,
content: {
[ overrideName ]: {
id: overrideImageId,
url: overrideImageSrc,
alt: imageAlt,
},
},
},
} );

// Check the image attributes on the frontend.
const postId = await editor.publishPost();
await page.goto( `/?p=${ postId }` );
const imageBlock = page.getByAltText( imageAlt );
await expect( imageBlock ).toHaveAttribute(
'data-id',
`${ overrideImageId }`
);
await expect( imageBlock ).toHaveAttribute(
'class',
`wp-image-${ overrideImageId }`
);
} );

test( 'image block classname contains the correct media id and has no data-id attribute when used as a standalone image', async ( {
admin,
editor,
page,
requestUtils,
} ) => {
// Upload two images, one for the original pattern, one for the override.
const { id: originalImageId, source_url: originalImageSrc } =
await requestUtils.uploadMedia(
path.resolve(
process.cwd(),
'test/e2e/assets/10x10_e2e_test_image_z9T8jK.png'
)
);
const { id: overrideImageId, source_url: overrideImageSrc } =
await requestUtils.uploadMedia(
path.resolve(
process.cwd(),
'test/e2e/assets/1024x768_e2e_test_image_size.jpeg'
)
);
const overrideName = 'test';

// Might be overkill, but check that the ids are actually different.
expect( overrideImageId ).not.toBe( originalImageId );

// Create a pattern with a gallery that has a single image with pattern overrides enabled.
// It has media that is not yet uploaded.
const { id } = await requestUtils.createBlock( {
title: 'Pattern',
content: `<!-- wp:image {"id":${ originalImageId },"sizeSlug":"large","linkDestination":"none","metadata":{"bindings":{"__default":{"source":"core/pattern-overrides"}},"name":"${ overrideName }"}} -->
<figure class="wp-block-image size-large"><img src="${ originalImageSrc }" alt="" class="wp-image-${ originalImageId }"/></figure>
<!-- /wp:image -->`,
status: 'publish',
} );

// Insert the pattern into a new post, overriding the image via the pattern block attributes.
await admin.createNewPost();
const imageAlt = 'Overridden Image';
await editor.insertBlock( {
name: 'core/block',
attributes: {
ref: id,
content: {
[ overrideName ]: {
id: overrideImageId,
url: overrideImageSrc,
alt: imageAlt,
},
},
},
} );

// Check the image attributes on the frontend.
const postId = await editor.publishPost();
await page.goto( `/?p=${ postId }` );
const imageBlock = page.getByAltText( imageAlt );
await expect( imageBlock ).not.toHaveAttribute( 'data-id' );
await expect( imageBlock ).toHaveAttribute(
'class',
`wp-image-${ overrideImageId }`
);
} );

test( 'blocks with the same name should be synced', async ( {
page,
admin,
Expand Down

0 comments on commit d40a396

Please sign in to comment.