Skip to content

Commit 01e5505

Browse files
Merge pull request #1704 from equalizedigital/claude/update-gutenberg-rules-VFZ0M
Add role="none" support alongside role="presentation" in image alt checks
2 parents a9e770d + 3ad6868 commit 01e5505

11 files changed

Lines changed: 44 additions & 26 deletions

includes/classes/Rules/Rule/ImgAltEmptyRule.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,11 @@ public static function get_rule(): array {
3737
),
3838
'why_it_matters' => esc_html__( 'Screen readers rely on alternative text to describe images to users who cannot see them. If the alt attribute is empty, it signals that the image is decorative and should be skipped. However, if a meaningful image has an empty alt attribute, users with visual impairments will miss important information. Proper use of alternative text improves accessibility and ensures all users can understand the content.', 'accessibility-checker' ),
3939
'how_to_fix' => sprintf(
40-
// translators: %1$s is <code>alt=""</code> and %2$s is <code>role="presentation"</code>.
41-
esc_html__( 'Review the image to determine if it is decorative. If it is decorative, it is correct to use an empty %1$s attribute and you can dismiss this warning by using the "Ignore" feature in Accessibility Checker or adding %2$s to the image and rescanning the page. If the image conveys information, add descriptive alt text that communicates the image\'s purpose or meaning.', 'accessibility-checker' ),
40+
// translators: %1$s is <code>alt=""</code>, %2$s is <code>role="presentation"</code>, and %3$s is <code>role="none"</code>.
41+
esc_html__( 'Review the image to determine if it is decorative. If it is decorative, it is correct to use an empty %1$s attribute and you can dismiss this warning by using the "Ignore" feature in Accessibility Checker or adding %2$s or %3$s to the image and rescanning the page. If the image conveys information, add descriptive alt text that communicates the image\'s purpose or meaning.', 'accessibility-checker' ),
4242
'<code>alt=""</code>',
4343
'<code>role="presentation"</code>',
44+
'<code>role="none"</code>',
4445
),
4546
'references' => [
4647
[

src/pageScanner/checks/img-alt-empty-check.js

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,6 @@ export default {
99
// Check if alt attribute is empty string (not missing, but explicitly empty)
1010
const hasEmptyAlt = node.hasAttribute( 'alt' ) && node.getAttribute( 'alt' ) === '';
1111

12-
// Skip if element has presentation role
13-
if (
14-
hasEmptyAlt &&
15-
(
16-
node.getAttribute( 'role' ) === 'presentation' ||
17-
node.getAttribute( 'role' ) === 'none'
18-
)
19-
) {
20-
return true;
21-
}
22-
2312
// Skip if aria-hidden is true
2413
if ( hasEmptyAlt && node.getAttribute( 'aria-hidden' ) === 'true' ) {
2514
return true;

src/pageScanner/checks/img-alt-missing-check.js

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,6 @@ export default {
1818
// Get the tag name
1919
const tagName = node.tagName.toLowerCase();
2020

21-
// Handle role="presentation"
22-
if ( node.hasAttribute( 'role' ) && node.getAttribute( 'role' ) === 'presentation' ) {
23-
// Images with role="presentation" are intentionally hidden from screen readers,
24-
// so missing alt text is acceptable in this case
25-
return false;
26-
}
27-
2821
// Handle aria-hidden="true"
2922
if ( node.hasAttribute( 'aria-hidden' ) && node.getAttribute( 'aria-hidden' ) === 'true' ) {
3023
// Images with aria-hidden="true" are not exposed to assistive technologies,

src/pageScanner/checks/linked-image-alt-not-empty.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@ export default {
2929
// Check each visible image for non-empty alt text
3030
return images.every( ( img ) => {
3131
const alt = img.getAttribute( 'alt' );
32-
const role = img.getAttribute( 'role' );
32+
const roleTokens = ( img.getAttribute( 'role' ) || '' ).toLowerCase().split( /\s+/ );
3333
const ariaHidden = img.getAttribute( 'aria-hidden' );
3434

35-
if ( role === 'presentation' || ariaHidden === 'true' ) {
35+
if ( roleTokens.includes( 'presentation' ) || roleTokens.includes( 'none' ) || ariaHidden === 'true' ) {
3636
return true;
3737
}
3838

src/pageScanner/checks/linked-image-alt-present.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@ export default {
2929
// Check each visible image for alt attribute
3030
return images.every( ( img ) => {
3131
const hasAlt = img.hasAttribute( 'alt' );
32-
const role = img.getAttribute( 'role' );
32+
const roleTokens = ( img.getAttribute( 'role' ) || '' ).toLowerCase().split( /\s+/ );
3333
const ariaHidden = img.getAttribute( 'aria-hidden' );
3434

35-
return hasAlt || role === 'presentation' || ariaHidden === 'true';
35+
return hasAlt || roleTokens.includes( 'presentation' ) || roleTokens.includes( 'none' ) || ariaHidden === 'true';
3636
} );
3737
},
3838
};

src/pageScanner/rules/img-alt-empty.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
export default {
77
id: 'img_alt_empty',
8-
selector: 'img[alt=""], input[type="image"][alt=""]',
8+
selector: 'img[alt=""]:not([role~="none"]):not([role~="presentation"]), input[type="image"][alt=""]:not([role~="none"]):not([role~="presentation"])',
99
excludeHidden: true,
1010
tags: [ 'cat.text-alternatives', 'wcag1a', 'wcag111' ],
1111
all: [],

src/pageScanner/rules/img-alt-missing.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
export default {
77
id: 'img_alt_missing',
8-
selector: 'img, input[type="image"]',
8+
selector: 'img:not([role~="none"]):not([role~="presentation"]), input[type="image"]:not([role~="none"]):not([role~="presentation"])',
99
excludeHidden: true,
1010
any: [],
1111
all: [],

tests/jest/rules/imgAltEmpty.test.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,11 @@ describe( 'Image Alt Empty Validation', () => {
6666
html: '<img src="decorative.jpg" alt="" role="none">',
6767
shouldPass: true,
6868
},
69+
{
70+
name: 'should pass for img with role="none presentation" (multi-value token)',
71+
html: '<img src="decorative.jpg" alt="" role="none presentation">',
72+
shouldPass: true,
73+
},
6974
{
7075
name: 'should pass for img without alt attribute',
7176
html: '<img src="test.jpg">',

tests/jest/rules/imgAltMissing.test.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,16 @@ describe( 'Image Alt Missing Validation', () => {
5555
html: '<img src="test.jpg" role="presentation">',
5656
shouldPass: true,
5757
},
58+
{
59+
name: 'should pass for img with role="none"',
60+
html: '<img src="test.jpg" role="none">',
61+
shouldPass: true,
62+
},
63+
{
64+
name: 'should pass for img with role="none presentation" (multi-value token)',
65+
html: '<img src="test.jpg" role="none presentation">',
66+
shouldPass: true,
67+
},
5868
{
5969
name: 'should pass for img with aria-hidden="true"',
6070
html: '<img src="test.jpg" aria-hidden="true">',

tests/jest/rules/imgLinkedAltEmpty.test.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,16 @@ describe( 'Linked Image Empty Alternative Text Rule', () => {
6161
html: '<a href="page.html"><img src="decorative.jpg" role="presentation" alt=""></a>',
6262
shouldPass: true,
6363
},
64+
{
65+
name: 'passes when image has role="none"',
66+
html: '<a href="page.html"><img src="decorative.jpg" role="none" alt=""></a>',
67+
shouldPass: true,
68+
},
69+
{
70+
name: 'passes when image has role="none presentation" (multi-value token)',
71+
html: '<a href="page.html"><img src="decorative.jpg" role="none presentation" alt=""></a>',
72+
shouldPass: true,
73+
},
6474
{
6575
name: 'passes when image has aria-hidden="true"',
6676
html: '<a href="page.html"><img src="decorative.jpg" aria-hidden="true" alt=""></a>',

0 commit comments

Comments
 (0)