Skip to content
This repository was archived by the owner on Feb 23, 2024. It is now read-only.

Commit 6dccf6f

Browse files
kmanijakKarol Manijakgithub-actions[bot]
authored
Fix: skewed placeholder of product image - issue#7553 (#7651)
* Fix typo in HTML markup of ProductImage block placeholder Typo caused rendering of incorrect HTML attributes: width and height of Product Image placeholder that were anyway ignored by the browser * Remove inline styles (width and height) from ImagePlaceholder in ProductElements > Image block Inline height took precedence over the inherited styles which made the placeholder image skewed (in loading and loaded state). Removal of those styles allows the ImagePlaceholder to adapt the height to the available space keeping the ratio or inherit the styles from the parent * Remove inline styles (width and height) from placeholder image in ProductImage.php block Inline styles applied to the placeholder image of ProductImage block were overriden by other styles with higher specificity, which made them redundant. Additionally, corresponding styles were removed from the placeholder image from Editor code as they caused UI glitches. Additional proof that it's safe to remove them is in the first commit in this branch, the purpose of which was to fix those styles as there was a typo which corrupted them and eventually inline width and height were ignored by the browser and not applied to the element * Add test to check placeholder image renders without width and height inline attributes This is to prevent adding inline width and height attributes so the sizing of the placeholder image is controlled by the inherited styles or element styles, in the same way as a regular product image * Fix TypeScript errors in the block test file of Product Image * Add generic alt text to placeholder image Alt text added in this commit is a generic text, not description of the actual image. That's because the image itself is set externally through the settings and may change over time * Revert adding placeholder image alt text and add comments to make the empty alt explicit After a Github discussion: https://github.com/woocommerce/woocommerce-blocks/pull/7651\#discussion_r1019560494 it was decided the placeholder should NOT have alt text as it serves the purpose of decorative image. According to the guidelines decorative images should not have alt text: https://www.w3.org/WAI/tutorials/images/decorative/. Comments were added also to other places where it happens * bot: update checkstyle.xml Co-authored-by: Karol Manijak <[email protected]> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent 1e4d336 commit 6dccf6f

File tree

6 files changed

+65
-32
lines changed

6 files changed

+65
-32
lines changed

assets/js/atomic/blocks/product-elements/image/block.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,9 +129,10 @@ export const Block = ( props ) => {
129129
};
130130

131131
const ImagePlaceholder = () => {
132-
return (
133-
<img src={ PLACEHOLDER_IMG_SRC } alt="" width={ 500 } height={ 500 } />
134-
);
132+
// The alt text is left empty on purpose, as it's considered a decorative image.
133+
// More can be found here: https://www.w3.org/WAI/tutorials/images/decorative/.
134+
// Github discussion for a context: https://github.com/woocommerce/woocommerce-blocks/pull/7651#discussion_r1019560494.
135+
return <img src={ PLACEHOLDER_IMG_SRC } alt="" />;
135136
};
136137

137138
const Image = ( { image, loaded, showFullSize, fallbackAlt } ) => {

assets/js/atomic/blocks/product-elements/image/test/block.test.js

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,10 @@ describe( 'Product Image Block', () => {
6262
describe( 'with product link', () => {
6363
test( 'should render an anchor with the product image', () => {
6464
const component = render(
65-
<ProductDataContextProvider product={ productWithImages }>
65+
<ProductDataContextProvider
66+
product={ productWithImages }
67+
isLoading={ false }
68+
>
6669
<Block showProductLink={ true } />
6770
</ProductDataContextProvider>
6871
);
@@ -79,14 +82,17 @@ describe( 'Product Image Block', () => {
7982
);
8083

8184
const anchor = productImage.closest( 'a' );
82-
expect( anchor.getAttribute( 'href' ) ).toBe(
85+
expect( anchor?.getAttribute( 'href' ) ).toBe(
8386
productWithImages.permalink
8487
);
8588
} );
8689

8790
test( 'should render an anchor with the placeholder image', () => {
8891
const component = render(
89-
<ProductDataContextProvider product={ productWithoutImages }>
92+
<ProductDataContextProvider
93+
product={ productWithoutImages }
94+
isLoading={ false }
95+
>
9096
<Block showProductLink={ true } />
9197
</ProductDataContextProvider>
9298
);
@@ -97,10 +103,10 @@ describe( 'Product Image Block', () => {
97103
);
98104

99105
const anchor = placeholderImage.closest( 'a' );
100-
expect( anchor.getAttribute( 'href' ) ).toBe(
106+
expect( anchor?.getAttribute( 'href' ) ).toBe(
101107
productWithoutImages.permalink
102108
);
103-
expect( anchor.getAttribute( 'aria-label' ) ).toBe(
109+
expect( anchor?.getAttribute( 'aria-label' ) ).toBe(
104110
`Link to ${ productWithoutImages.name }`
105111
);
106112
} );
@@ -109,7 +115,10 @@ describe( 'Product Image Block', () => {
109115
describe( 'without product link', () => {
110116
test( 'should render the product image without an anchor wrapper', () => {
111117
const component = render(
112-
<ProductDataContextProvider product={ productWithImages }>
118+
<ProductDataContextProvider
119+
product={ productWithImages }
120+
isLoading={ false }
121+
>
113122
<Block showProductLink={ false } />
114123
</ProductDataContextProvider>
115124
);
@@ -129,7 +138,10 @@ describe( 'Product Image Block', () => {
129138

130139
test( 'should render the placeholder image without an anchor wrapper', () => {
131140
const component = render(
132-
<ProductDataContextProvider product={ productWithoutImages }>
141+
<ProductDataContextProvider
142+
product={ productWithoutImages }
143+
isLoading={ false }
144+
>
133145
<Block showProductLink={ false } />
134146
</ProductDataContextProvider>
135147
);
@@ -143,4 +155,24 @@ describe( 'Product Image Block', () => {
143155
expect( anchor ).toBe( null );
144156
} );
145157
} );
158+
159+
describe( 'without image', () => {
160+
test( 'should render the placeholder with no inline width or height attributes', () => {
161+
const component = render(
162+
<ProductDataContextProvider
163+
product={ productWithoutImages }
164+
isLoading={ false }
165+
>
166+
<Block showProductLink={ true } />
167+
</ProductDataContextProvider>
168+
);
169+
170+
const placeholderImage = component.getByAltText( '' );
171+
expect( placeholderImage.getAttribute( 'src' ) ).toBe(
172+
'placeholder.jpg'
173+
);
174+
expect( placeholderImage.getAttribute( 'width' ) ).toBe( null );
175+
expect( placeholderImage.getAttribute( 'height' ) ).toBe( null );
176+
} );
177+
} );
146178
} );

assets/js/base/components/block-error-boundary/block-error.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ const BlockError = ( {
2323
return showErrorBlock ? (
2424
<div className="wc-block-error wc-block-components-error">
2525
{ imageUrl && (
26+
// The alt text is left empty on purpose, as it's considered a decorative image.
27+
// More can be found here: https://www.w3.org/WAI/tutorials/images/decorative/.
28+
// Github discussion for a context: https://github.com/woocommerce/woocommerce-blocks/pull/7651#discussion_r1019560494.
2629
<img
2730
className="wc-block-error__image wc-block-components-error__image"
2831
src={ imageUrl }

assets/js/base/components/reviews/review-list-item/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ function getReviewImage( review, imageType, isLoading ) {
2727
src={ review.product_image?.thumbnail || '' }
2828
/>
2929
) : (
30+
// The alt text is left empty on purpose, as it's considered a decorative image.
31+
// More can be found here: https://www.w3.org/WAI/tutorials/images/decorative/.
32+
// Github discussion for a context: https://github.com/woocommerce/woocommerce-blocks/pull/7651#discussion_r1019560494.
3033
<img
3134
aria-hidden="true"
3235
alt=""

checkstyle.xml

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,10 +1118,10 @@
11181118
<error line="75" column="36" severity="error" message="Property &apos;max_amount&apos; does not exist on type &apos;never&apos;." source="TS2339" />
11191119
</file>
11201120
<file name="assets/js/atomic/blocks/product-elements/image/block.js">
1121-
<error line="137" column="19" severity="error" message="Binding element &apos;image&apos; implicitly has an &apos;any&apos; type." source="TS7031" />
1122-
<error line="137" column="26" severity="error" message="Binding element &apos;loaded&apos; implicitly has an &apos;any&apos; type." source="TS7031" />
1123-
<error line="137" column="34" severity="error" message="Binding element &apos;showFullSize&apos; implicitly has an &apos;any&apos; type." source="TS7031" />
1124-
<error line="137" column="48" severity="error" message="Binding element &apos;fallbackAlt&apos; implicitly has an &apos;any&apos; type." source="TS7031" />
1121+
<error line="138" column="19" severity="error" message="Binding element &apos;image&apos; implicitly has an &apos;any&apos; type." source="TS7031" />
1122+
<error line="138" column="26" severity="error" message="Binding element &apos;loaded&apos; implicitly has an &apos;any&apos; type." source="TS7031" />
1123+
<error line="138" column="34" severity="error" message="Binding element &apos;showFullSize&apos; implicitly has an &apos;any&apos; type." source="TS7031" />
1124+
<error line="138" column="48" severity="error" message="Binding element &apos;fallbackAlt&apos; implicitly has an &apos;any&apos; type." source="TS7031" />
11251125
</file>
11261126
<file name="assets/js/atomic/blocks/product-elements/rating/block.tsx">
11271127
<error line="55" column="35" severity="error" message="Argument of type &apos;{ id: number; name: string; parent: number; type: string; variation: string; permalink: string; sku: string; short_description: string; description: string; on_sale: boolean; prices: { currency_code: string; ... 9 more ...; price_range: null; }; ... 14 more ...; add_to_cart: { ...; }; }&apos; is not assignable to parameter of type &apos;Omit&lt;ProductResponseItem, &quot;average_rating&quot;&gt; &amp; { average_rating: string; }&apos;.
@@ -1430,15 +1430,6 @@
14301430
<error line="252" column="56" severity="error" message="Argument of type &apos;null&apos; is not assignable to parameter of type &apos;Object&apos;." source="TS2345" />
14311431
<error line="475" column="34" severity="error" message="Argument of type &apos;null&apos; is not assignable to parameter of type &apos;Object | undefined&apos;." source="TS2345" />
14321432
</file>
1433-
<file name="assets/js/atomic/blocks/product-elements/image/test/block.test.js">
1434-
<error line="65" column="6" severity="error" message="Property &apos;isLoading&apos; is missing in type &apos;{ children: Element; product: { name: string; id: number; fallbackAlt: string; permalink: string; images: { id: number; src: string; thumbnail: string; srcset: string; sizes: string; name: string; alt: string; }[]; }; }&apos; but required in type &apos;{ product: any; children: Object; isLoading: boolean; }&apos;." source="TS2741" />
1435-
<error line="82" column="12" severity="error" message="Object is possibly &apos;null&apos;." source="TS2531" />
1436-
<error line="89" column="6" severity="error" message="Property &apos;isLoading&apos; is missing in type &apos;{ children: Element; product: { name: string; id: number; fallbackAlt: string; permalink: string; images: never[]; }; }&apos; but required in type &apos;{ product: any; children: Object; isLoading: boolean; }&apos;." source="TS2741" />
1437-
<error line="100" column="12" severity="error" message="Object is possibly &apos;null&apos;." source="TS2531" />
1438-
<error line="103" column="12" severity="error" message="Object is possibly &apos;null&apos;." source="TS2531" />
1439-
<error line="112" column="6" severity="error" message="Property &apos;isLoading&apos; is missing in type &apos;{ children: Element; product: { name: string; id: number; fallbackAlt: string; permalink: string; images: { id: number; src: string; thumbnail: string; srcset: string; sizes: string; name: string; alt: string; }[]; }; }&apos; but required in type &apos;{ product: any; children: Object; isLoading: boolean; }&apos;." source="TS2741" />
1440-
<error line="132" column="6" severity="error" message="Property &apos;isLoading&apos; is missing in type &apos;{ children: Element; product: { name: string; id: number; fallbackAlt: string; permalink: string; images: never[]; }; }&apos; but required in type &apos;{ product: any; children: Object; isLoading: boolean; }&apos;." source="TS2741" />
1441-
</file>
14421433
<file name="assets/js/atomic/blocks/product-elements/title/test/block.test.js">
14431434
<error line="22" column="6" severity="error" message="Property &apos;isLoading&apos; is missing in type &apos;{ children: Element; product: { id: number; name: string; permalink: string; }; }&apos; but required in type &apos;{ product: any; children: Object; isLoading: boolean; }&apos;." source="TS2741" />
14441435
<error line="23" column="7" severity="error" message="Type &apos;{ showProductLink: false; }&apos; is missing the following properties from type &apos;Attributes&apos;: headingLevel, align" source="TS2739" />
@@ -1726,14 +1717,14 @@
17261717
<error line="14" column="26" severity="error" message="Parameter &apos;review&apos; implicitly has an &apos;any&apos; type." source="TS7006" />
17271718
<error line="14" column="34" severity="error" message="Parameter &apos;imageType&apos; implicitly has an &apos;any&apos; type." source="TS7006" />
17281719
<error line="14" column="45" severity="error" message="Parameter &apos;isLoading&apos; implicitly has an &apos;any&apos; type." source="TS7006" />
1729-
<error line="51" column="28" severity="error" message="Parameter &apos;review&apos; implicitly has an &apos;any&apos; type." source="TS7006" />
1730-
<error line="77" column="32" severity="error" message="Parameter &apos;review&apos; implicitly has an &apos;any&apos; type." source="TS7006" />
1731-
<error line="93" column="27" severity="error" message="Parameter &apos;review&apos; implicitly has an &apos;any&apos; type." source="TS7006" />
1732-
<error line="102" column="25" severity="error" message="Parameter &apos;review&apos; implicitly has an &apos;any&apos; type." source="TS7006" />
1733-
<error line="117" column="27" severity="error" message="Parameter &apos;review&apos; implicitly has an &apos;any&apos; type." source="TS7006" />
1734-
<error line="150" column="28" severity="error" message="Binding element &apos;attributes&apos; implicitly has an &apos;any&apos; type." source="TS7031" />
1735-
<error line="160" column="10" severity="error" message="Property &apos;rating&apos; does not exist on type &apos;{}&apos;." source="TS2339" />
1736-
<error line="161" column="20" severity="error" message="Operator &apos;&gt;&apos; cannot be applied to types &apos;boolean&apos; and &apos;number&apos;." source="TS2365" />
1720+
<error line="54" column="28" severity="error" message="Parameter &apos;review&apos; implicitly has an &apos;any&apos; type." source="TS7006" />
1721+
<error line="80" column="32" severity="error" message="Parameter &apos;review&apos; implicitly has an &apos;any&apos; type." source="TS7006" />
1722+
<error line="96" column="27" severity="error" message="Parameter &apos;review&apos; implicitly has an &apos;any&apos; type." source="TS7006" />
1723+
<error line="105" column="25" severity="error" message="Parameter &apos;review&apos; implicitly has an &apos;any&apos; type." source="TS7006" />
1724+
<error line="120" column="27" severity="error" message="Parameter &apos;review&apos; implicitly has an &apos;any&apos; type." source="TS7006" />
1725+
<error line="153" column="28" severity="error" message="Binding element &apos;attributes&apos; implicitly has an &apos;any&apos; type." source="TS7031" />
1726+
<error line="163" column="10" severity="error" message="Property &apos;rating&apos; does not exist on type &apos;{}&apos;." source="TS2339" />
1727+
<error line="164" column="20" severity="error" message="Operator &apos;&gt;&apos; cannot be applied to types &apos;boolean&apos; and &apos;number&apos;." source="TS2365" />
17371728
</file>
17381729
<file name="assets/js/base/components/reviews/review-list/index.js">
17391730
<error line="13" column="24" severity="error" message="Binding element &apos;attributes&apos; implicitly has an &apos;any&apos; type." source="TS7031" />

src/BlockTypes/ProductImage.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,10 @@ private function render_image( $product ) {
147147
$image_info = wp_get_attachment_image_src( get_post_thumbnail_id( $product->get_id() ), 'woocommerce_thumbnail' );
148148

149149
if ( ! isset( $image_info[0] ) ) {
150-
return sprintf( '<img src="%s" alt="" width="500 height="500" />', wc_placeholder_img_src( 'woocommerce_thumbnail' ) );
150+
// The alt text is left empty on purpose, as it's considered a decorative image.
151+
// More can be found here: https://www.w3.org/WAI/tutorials/images/decorative/.
152+
// Github discussion for a context: https://github.com/woocommerce/woocommerce-blocks/pull/7651#discussion_r1019560494.
153+
return sprintf( '<img src="%s" alt="" />', wc_placeholder_img_src( 'woocommerce_thumbnail' ) );
151154
}
152155

153156
return sprintf(

0 commit comments

Comments
 (0)